diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index c0b936d802ef..0ae654a921f8 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -24,6 +24,7 @@ #include #include #include +#include /* PMIC Arbiter configuration registers */ #define PMIC_ARB_VERSION 0x0000 @@ -159,6 +160,7 @@ struct spmi_pmic_arb { u16 last_apid; struct apid_data apid_data[PMIC_ARB_MAX_PERIPHS]; }; +static struct spmi_pmic_arb *the_pa; /** * pmic_arb_ver: version dependent functionality. @@ -525,7 +527,7 @@ static void cleanup_irq(struct spmi_pmic_arb *pa, u16 apid, int id) irq_mask, ppid); } -static void periph_interrupt(struct spmi_pmic_arb *pa, u16 apid) +static void periph_interrupt(struct spmi_pmic_arb *pa, u16 apid, bool show) { unsigned int irq; u32 status; @@ -542,22 +544,32 @@ static void periph_interrupt(struct spmi_pmic_arb *pa, u16 apid) cleanup_irq(pa, apid, id); continue; } - generic_handle_irq(irq); + if (show) { + struct irq_desc *desc; + const char *name = "null"; + + desc = irq_to_desc(irq); + if (desc == NULL) + name = "stray irq"; + else if (desc->action && desc->action->name) + name = desc->action->name; + + pr_warn("spmi_show_resume_irq: %d triggered [0x%01x, 0x%02x, 0x%01x] %s\n", + irq, sid, per, id, name); + } else { + generic_handle_irq(irq); + } } } -static void pmic_arb_chained_irq(struct irq_desc *desc) +static void __pmic_arb_chained_irq(struct spmi_pmic_arb *pa, bool show) { - struct spmi_pmic_arb *pa = irq_desc_get_handler_data(desc); - struct irq_chip *chip = irq_desc_get_chip(desc); void __iomem *intr = pa->intr; int first = pa->min_apid >> 5; int last = pa->max_apid >> 5; u32 status, enable; int i, id, apid; - chained_irq_enter(chip, desc); - for (i = first; i <= last; ++i) { status = readl_relaxed(intr + pa->ver_ops->owner_acc_status(pa->ee, i)); @@ -568,10 +580,18 @@ static void pmic_arb_chained_irq(struct irq_desc *desc) enable = readl_relaxed(intr + pa->ver_ops->acc_enable(apid)); if (enable & SPMI_PIC_ACC_ENABLE_BIT) - periph_interrupt(pa, apid); + periph_interrupt(pa, apid, show); } } +} +static void pmic_arb_chained_irq(struct irq_desc *desc) +{ + struct spmi_pmic_arb *pa = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); + __pmic_arb_chained_irq(pa, false); chained_irq_exit(chip, desc); } @@ -988,6 +1008,16 @@ static const struct irq_domain_ops pmic_arb_irq_domain_ops = { .xlate = qpnpint_irq_domain_dt_translate, }; +static void spmi_pmic_arb_resume(void) +{ + if (spmi_show_resume_irq()) + __pmic_arb_chained_irq(the_pa, true); +} + +static struct syscore_ops spmi_pmic_arb_syscore_ops = { + .resume = spmi_pmic_arb_resume, +}; + static int spmi_pmic_arb_probe(struct platform_device *pdev) { struct spmi_pmic_arb *pa; @@ -1153,6 +1183,8 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) if (err) goto err_domain_remove; + the_pa = pa; + register_syscore_ops(&spmi_pmic_arb_syscore_ops); return 0; err_domain_remove: @@ -1167,8 +1199,11 @@ static int spmi_pmic_arb_remove(struct platform_device *pdev) { struct spmi_controller *ctrl = platform_get_drvdata(pdev); struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl); + spmi_controller_remove(ctrl); irq_set_chained_handler_and_data(pa->irq, NULL, NULL); + unregister_syscore_ops(&spmi_pmic_arb_syscore_ops); + the_pa = NULL; irq_domain_remove(pa->domain); spmi_controller_put(ctrl); return 0; diff --git a/include/linux/spmi.h b/include/linux/spmi.h index 1396a255d2a2..319c52a298ef 100644 --- a/include/linux/spmi.h +++ b/include/linux/spmi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -171,6 +171,19 @@ static inline void spmi_driver_unregister(struct spmi_driver *sdrv) module_driver(__spmi_driver, spmi_driver_register, \ spmi_driver_unregister) +#ifdef CONFIG_QCOM_SHOW_RESUME_IRQ +extern int msm_show_resume_irq_mask; +static inline bool spmi_show_resume_irq(void) +{ + return msm_show_resume_irq_mask; +} +#else +static inline bool spmi_show_resume_irq(void) +{ + return false; +} +#endif + int spmi_register_read(struct spmi_device *sdev, u8 addr, u8 *buf); int spmi_ext_register_read(struct spmi_device *sdev, u8 addr, u8 *buf, size_t len);