Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

gpio: brcmstb: allow parent_irq to wake

The classic parent_wake_irq can only occur after the system has
been placed into a hardware managed power management state. This
prevents its use for waking from software managed suspend states
like s2idle.

By allowing the parent_irq to be enabled for wake enabled GPIO
during suspend, these GPIO can now be used to wake from these
states. The 'suspended' boolean is introduced to support wake
event accounting.

Signed-off-by: Doug Berger <opendmb@gmail.com>
[florian: port changes after generic gpio chip conversion]
Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Link: https://patch.msgid.link/20260204164333.1146039-4-florian.fainelli@broadcom.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

authored by

Doug Berger and committed by
Bartosz Golaszewski
2c46f19c 66ff5094

+57 -28
+57 -28
drivers/gpio/gpio-brcmstb.c
··· 54 54 int parent_irq; 55 55 int num_gpios; 56 56 int parent_wake_irq; 57 + bool suspended; 57 58 }; 58 59 59 60 #define MAX_GPIO_PER_BANK 32 ··· 241 240 { 242 241 int ret = 0; 243 242 243 + if (priv->parent_wake_irq == priv->parent_irq) 244 + return ret; 245 + 244 246 if (enable) 245 247 ret = enable_irq_wake(priv->parent_wake_irq); 246 248 else ··· 293 289 294 290 while ((status = brcmstb_gpio_get_active_irqs(bank))) { 295 291 unsigned int offset; 292 + 293 + if (priv->suspended && bank->wake_active & status) { 294 + priv->suspended = false; 295 + pm_wakeup_event(&priv->pdev->dev, 0); 296 + } 296 297 297 298 for_each_set_bit(offset, &status, 32) { 298 299 if (offset >= bank->width) ··· 472 463 } 473 464 474 465 if (of_property_read_bool(np, "wakeup-source")) { 466 + /* 467 + * Set wakeup capability so we can process boot-time 468 + * "wakeups" (e.g., from S5 cold boot). 469 + */ 470 + device_set_wakeup_capable(dev, true); 471 + device_wakeup_enable(dev); 475 472 priv->parent_wake_irq = platform_get_irq(pdev, 1); 476 473 if (priv->parent_wake_irq < 0) { 477 - priv->parent_wake_irq = 0; 474 + priv->parent_wake_irq = priv->parent_irq; 478 475 dev_warn(dev, 479 476 "Couldn't get wake IRQ - GPIOs will not be able to wake from sleep"); 480 477 } else { 481 - /* 482 - * Set wakeup capability so we can process boot-time 483 - * "wakeups" (e.g., from S5 cold boot) 484 - */ 485 - device_set_wakeup_capable(dev, true); 486 - device_wakeup_enable(dev); 487 478 err = devm_request_irq(dev, priv->parent_wake_irq, 488 479 brcmstb_gpio_wake_irq_handler, 489 480 IRQF_SHARED, ··· 494 485 goto out_free_domain; 495 486 } 496 487 } 488 + priv->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake; 497 489 } 498 490 499 491 priv->irq_chip.name = dev_name(dev); ··· 504 494 priv->irq_chip.irq_unmask = brcmstb_gpio_irq_unmask; 505 495 priv->irq_chip.irq_ack = brcmstb_gpio_irq_ack; 506 496 priv->irq_chip.irq_set_type = brcmstb_gpio_irq_set_type; 507 - 508 - if (priv->parent_wake_irq) 509 - priv->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake; 510 497 511 498 irq_set_chained_handler_and_data(priv->parent_irq, 512 499 brcmstb_gpio_irq_handler, priv); ··· 527 520 priv->reg_base + GIO_BANK_OFF(bank->id, i)); 528 521 } 529 522 530 - static void brcmstb_gpio_quiesce(struct device *dev, bool save) 523 + static void brcmstb_gpio_quiesce(struct brcmstb_gpio_priv *priv, bool save) 531 524 { 532 - struct brcmstb_gpio_priv *priv = dev_get_drvdata(dev); 533 525 struct brcmstb_gpio_bank *bank; 534 526 u32 imask; 535 - 536 - /* disable non-wake interrupt */ 537 - if (priv->parent_irq >= 0) 538 - disable_irq(priv->parent_irq); 539 527 540 528 list_for_each_entry(bank, &priv->bank_list, node) { 541 529 if (save) ··· 549 547 550 548 static void brcmstb_gpio_shutdown(struct platform_device *pdev) 551 549 { 550 + struct brcmstb_gpio_priv *priv = dev_get_drvdata(&pdev->dev); 551 + 552 + if (priv->parent_irq > 0) 553 + disable_irq(priv->parent_irq); 554 + 552 555 /* Enable GPIO for S5 cold boot */ 553 - brcmstb_gpio_quiesce(&pdev->dev, false); 556 + brcmstb_gpio_quiesce(priv, false); 554 557 } 555 558 556 559 static void brcmstb_gpio_bank_restore(struct brcmstb_gpio_priv *priv, ··· 571 564 572 565 static int brcmstb_gpio_suspend(struct device *dev) 573 566 { 574 - brcmstb_gpio_quiesce(dev, true); 567 + struct brcmstb_gpio_priv *priv = dev_get_drvdata(dev); 568 + 569 + if (priv->parent_irq > 0) 570 + priv->suspended = true; 571 + 572 + return 0; 573 + } 574 + 575 + static int brcmstb_gpio_suspend_noirq(struct device *dev) 576 + { 577 + struct brcmstb_gpio_priv *priv = dev_get_drvdata(dev); 578 + 579 + /* Catch any wakeup sources occurring between suspend and noirq */ 580 + if (!priv->suspended) 581 + return -EBUSY; 582 + 583 + if (priv->parent_irq > 0) 584 + disable_irq(priv->parent_irq); 585 + 586 + brcmstb_gpio_quiesce(priv, true); 587 + 588 + if (priv->parent_wake_irq) 589 + enable_irq(priv->parent_irq); 590 + 575 591 return 0; 576 592 } 577 593 ··· 602 572 { 603 573 struct brcmstb_gpio_priv *priv = dev_get_drvdata(dev); 604 574 struct brcmstb_gpio_bank *bank; 605 - bool need_wakeup_event = false; 606 575 607 - list_for_each_entry(bank, &priv->bank_list, node) { 608 - need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); 576 + if (priv->parent_wake_irq) 577 + disable_irq(priv->parent_irq); 578 + 579 + priv->suspended = false; 580 + 581 + list_for_each_entry(bank, &priv->bank_list, node) 609 582 brcmstb_gpio_bank_restore(priv, bank); 610 - } 611 583 612 - if (priv->parent_wake_irq && need_wakeup_event) 613 - pm_wakeup_event(dev, 0); 614 - 615 - /* enable non-wake interrupt */ 616 - if (priv->parent_irq >= 0) 584 + if (priv->parent_irq > 0) 617 585 enable_irq(priv->parent_irq); 618 586 619 587 return 0; 620 588 } 621 589 622 590 static const struct dev_pm_ops brcmstb_gpio_pm_ops = { 623 - .suspend_noirq = pm_sleep_ptr(brcmstb_gpio_suspend), 591 + .suspend = pm_sleep_ptr(brcmstb_gpio_suspend), 592 + .suspend_noirq = pm_sleep_ptr(brcmstb_gpio_suspend_noirq), 624 593 .resume_noirq = pm_sleep_ptr(brcmstb_gpio_resume), 625 594 }; 626 595