OSDN Git Service

pinctrl: amd: Fix wakeups when IRQ is shared with SCI
[uclinux-h8/linux.git] / drivers / pinctrl / pinctrl-amd.c
index bae9d42..ecab906 100644 (file)
@@ -598,14 +598,14 @@ static struct irq_chip amd_gpio_irqchip = {
 
 #define PIN_IRQ_PENDING        (BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF))
 
-static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
+static bool do_amd_gpio_irq_handler(int irq, void *dev_id)
 {
        struct amd_gpio *gpio_dev = dev_id;
        struct gpio_chip *gc = &gpio_dev->gc;
-       irqreturn_t ret = IRQ_NONE;
        unsigned int i, irqnr;
        unsigned long flags;
        u32 __iomem *regs;
+       bool ret = false;
        u32  regval;
        u64 status, mask;
 
@@ -627,6 +627,14 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
                /* Each status bit covers four pins */
                for (i = 0; i < 4; i++) {
                        regval = readl(regs + i);
+                       /* caused wake on resume context for shared IRQ */
+                       if (irq < 0 && (regval & BIT(WAKE_STS_OFF))) {
+                               dev_dbg(&gpio_dev->pdev->dev,
+                                       "Waking due to GPIO %d: 0x%x",
+                                       irqnr + i, regval);
+                               return true;
+                       }
+
                        if (!(regval & PIN_IRQ_PENDING) ||
                            !(regval & BIT(INTERRUPT_MASK_OFF)))
                                continue;
@@ -650,9 +658,12 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
                        }
                        writel(regval, regs + i);
                        raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
-                       ret = IRQ_HANDLED;
+                       ret = true;
                }
        }
+       /* did not cause wake on resume context for shared IRQ */
+       if (irq < 0)
+               return false;
 
        /* Signal EOI to the GPIO unit */
        raw_spin_lock_irqsave(&gpio_dev->lock, flags);
@@ -664,6 +675,16 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
        return ret;
 }
 
+static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
+{
+       return IRQ_RETVAL(do_amd_gpio_irq_handler(irq, dev_id));
+}
+
+static bool __maybe_unused amd_gpio_check_wake(void *dev_id)
+{
+       return do_amd_gpio_irq_handler(-1, dev_id);
+}
+
 static int amd_get_groups_count(struct pinctrl_dev *pctldev)
 {
        struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev);
@@ -1033,6 +1054,7 @@ static int amd_gpio_probe(struct platform_device *pdev)
                goto out2;
 
        platform_set_drvdata(pdev, gpio_dev);
+       acpi_register_wakeup_handler(gpio_dev->irq, amd_gpio_check_wake, gpio_dev);
 
        dev_dbg(&pdev->dev, "amd gpio driver loaded\n");
        return ret;
@@ -1050,6 +1072,7 @@ static int amd_gpio_remove(struct platform_device *pdev)
        gpio_dev = platform_get_drvdata(pdev);
 
        gpiochip_remove(&gpio_dev->gc);
+       acpi_unregister_wakeup_handler(amd_gpio_check_wake, gpio_dev);
 
        return 0;
 }