spmi: pmic-arb: support show_resume_irq

show_resume_irq is used to debug interrupts that cause wakeup.
Support it for spmi arbiter's interrupt controller.

Change-Id: I52d51c09d7ff316248542c84a1cd65a28e2283da
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index a7bf2a1..b0dfa1b 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 @@
 	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 @@
 				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 @@
 			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 @@
 			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 @@
 	.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;
@@ -1154,6 +1184,8 @@
 	if (err)
 		goto err_domain_remove;
 
+	the_pa = pa;
+	register_syscore_ops(&spmi_pmic_arb_syscore_ops);
 	return 0;
 
 err_domain_remove:
@@ -1168,8 +1200,11 @@
 {
 	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;