diff options
Diffstat (limited to 'drivers/spmi/spmi-pmic-arb.c')
| -rw-r--r-- | drivers/spmi/spmi-pmic-arb.c | 57 |
1 files changed, 49 insertions, 8 deletions
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index b02e48185355..0ae654a921f8 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -24,6 +24,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spmi.h> +#include <linux/syscore_ops.h> /* 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; @@ -1005,6 +1035,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) pa->spmic = ctrl; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); + if (!res) { + dev_err(&pdev->dev, "core resource not specified\n"); + err = -EINVAL; + goto err_put_ctrl; + } + pa->core_size = resource_size(res); if (pa->core_size <= 0x800) { dev_err(&pdev->dev, "core_size is smaller than 0x800. Failing Probe\n"); @@ -1147,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: @@ -1161,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; |
