spmi: pmic-arb: add support to dispatch interrupt based on IRQ status
authorAshay Jaiswal <ashayj@codeaurora.org>
Fri, 30 Sep 2022 00:50:15 +0000 (17:50 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 30 Sep 2022 12:33:23 +0000 (14:33 +0200)
Current implementation of SPMI arbiter dispatches interrupt based on the
Arbiter's accumulator status, in some cases the accumulator status may
remain zero and the interrupt remains un-handled. Add logic to dispatch
interrupts based Arbiter's IRQ status if the accumulator status is zero.

Signed-off-by: Ashay Jaiswal <ashayj@codeaurora.org>
Signed-off-by: David Collins <collinsd@codeaurora.org>
Signed-off-by: Fenglin Wu <quic_fenglinw@quicinc.com>
Link: https://lore.kernel.org/r/1655004286-11493-6-git-send-email-quic_fenglinw@quicinc.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Link: https://lore.kernel.org/r/20220930005019.2663064-7-sboyd@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/spmi/spmi-pmic-arb.c

index e19eaec..56f2294 100644 (file)
@@ -630,12 +630,18 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
        u8 ee = pmic_arb->ee;
        u32 status, enable, handled = 0;
        int i, id, apid;
+       /* status based dispatch */
+       bool acc_valid = false;
+       u32 irq_status = 0;
 
        chained_irq_enter(chip, desc);
 
        for (i = first >> 5; i <= last >> 5; ++i) {
                status = readl_relaxed(
                                ver_ops->owner_acc_status(pmic_arb, ee, i));
+               if (status)
+                       acc_valid = true;
+
                while (status) {
                        id = ffs(status) - 1;
                        status &= ~BIT(id);
@@ -653,6 +659,29 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
                }
        }
 
+       /* ACC_STATUS is empty but IRQ fired check IRQ_STATUS */
+       if (!acc_valid) {
+               for (i = first; i <= last; i++) {
+                       /* skip if APPS is not irq owner */
+                       if (pmic_arb->apid_data[i].irq_ee != pmic_arb->ee)
+                               continue;
+
+                       irq_status = readl_relaxed(
+                                            ver_ops->irq_status(pmic_arb, i));
+                       if (irq_status) {
+                               enable = readl_relaxed(
+                                            ver_ops->acc_enable(pmic_arb, i));
+                               if (enable & SPMI_PIC_ACC_ENABLE_BIT) {
+                                       dev_dbg(&pmic_arb->spmic->dev,
+                                               "Dispatching IRQ for apid=%d status=%x\n",
+                                               i, irq_status);
+                                       if (periph_interrupt(pmic_arb, i) != 0)
+                                               handled++;
+                               }
+                       }
+               }
+       }
+
        if (handled == 0)
                handle_bad_irq(desc);