Skip to content

Commit 2d54067

Browse files
superm1linusw
authored andcommitted
pinctrl: amd: Fix wakeups when IRQ is shared with SCI
On some Lenovo AMD Gen2 platforms the IRQ for the SCI and pinctrl drivers are shared. Due to how the s2idle loop handling works, this case needs an extra explicit check whether the interrupt was caused by SCI or by the GPIO controller. To fix this rework the existing IRQ handler function to function as a checker and an IRQ handler depending on the calling arguments. BugLink: https://gitlab.freedesktop.org/drm/amd/-/issues/1738 Reported-by: Joerie de Gram <j.de.gram@gmail.com> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> Acked-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com> Link: https://lore.kernel.org/r/20211101014853.6177-2-mario.limonciello@amd.com Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
1 parent e9380df commit 2d54067

File tree

1 file changed

+26
-3
lines changed

1 file changed

+26
-3
lines changed

drivers/pinctrl/pinctrl-amd.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -598,14 +598,14 @@ static struct irq_chip amd_gpio_irqchip = {
598598

599599
#define PIN_IRQ_PENDING (BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF))
600600

601-
static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
601+
static bool do_amd_gpio_irq_handler(int irq, void *dev_id)
602602
{
603603
struct amd_gpio *gpio_dev = dev_id;
604604
struct gpio_chip *gc = &gpio_dev->gc;
605-
irqreturn_t ret = IRQ_NONE;
606605
unsigned int i, irqnr;
607606
unsigned long flags;
608607
u32 __iomem *regs;
608+
bool ret = false;
609609
u32 regval;
610610
u64 status, mask;
611611

@@ -627,6 +627,14 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
627627
/* Each status bit covers four pins */
628628
for (i = 0; i < 4; i++) {
629629
regval = readl(regs + i);
630+
/* caused wake on resume context for shared IRQ */
631+
if (irq < 0 && (regval & BIT(WAKE_STS_OFF))) {
632+
dev_dbg(&gpio_dev->pdev->dev,
633+
"Waking due to GPIO %d: 0x%x",
634+
irqnr + i, regval);
635+
return true;
636+
}
637+
630638
if (!(regval & PIN_IRQ_PENDING) ||
631639
!(regval & BIT(INTERRUPT_MASK_OFF)))
632640
continue;
@@ -650,9 +658,12 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
650658
}
651659
writel(regval, regs + i);
652660
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
653-
ret = IRQ_HANDLED;
661+
ret = true;
654662
}
655663
}
664+
/* did not cause wake on resume context for shared IRQ */
665+
if (irq < 0)
666+
return false;
656667

657668
/* Signal EOI to the GPIO unit */
658669
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
@@ -664,6 +675,16 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
664675
return ret;
665676
}
666677

678+
static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
679+
{
680+
return IRQ_RETVAL(do_amd_gpio_irq_handler(irq, dev_id));
681+
}
682+
683+
static bool __maybe_unused amd_gpio_check_wake(void *dev_id)
684+
{
685+
return do_amd_gpio_irq_handler(-1, dev_id);
686+
}
687+
667688
static int amd_get_groups_count(struct pinctrl_dev *pctldev)
668689
{
669690
struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev);
@@ -1033,6 +1054,7 @@ static int amd_gpio_probe(struct platform_device *pdev)
10331054
goto out2;
10341055

10351056
platform_set_drvdata(pdev, gpio_dev);
1057+
acpi_register_wakeup_handler(gpio_dev->irq, amd_gpio_check_wake, gpio_dev);
10361058

10371059
dev_dbg(&pdev->dev, "amd gpio driver loaded\n");
10381060
return ret;
@@ -1050,6 +1072,7 @@ static int amd_gpio_remove(struct platform_device *pdev)
10501072
gpio_dev = platform_get_drvdata(pdev);
10511073

10521074
gpiochip_remove(&gpio_dev->gc);
1075+
acpi_unregister_wakeup_handler(amd_gpio_check_wake, gpio_dev);
10531076

10541077
return 0;
10551078
}

0 commit comments

Comments
 (0)