|
7 | 7 | #define pr_fmt(fmt) "PCI: OF: " fmt |
8 | 8 |
|
9 | 9 | #include <linux/cleanup.h> |
| 10 | +#include <linux/gpio/consumer.h> |
10 | 11 | #include <linux/irqdomain.h> |
11 | 12 | #include <linux/kernel.h> |
12 | 13 | #include <linux/pci.h> |
|
15 | 16 | #include <linux/of_address.h> |
16 | 17 | #include <linux/of_pci.h> |
17 | 18 | #include <linux/platform_device.h> |
| 19 | +#include <linux/pm_wakeirq.h> |
18 | 20 | #include "pci.h" |
19 | 21 |
|
20 | 22 | #ifdef CONFIG_PCI |
@@ -586,6 +588,79 @@ int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) |
586 | 588 | return irq_create_of_mapping(&oirq); |
587 | 589 | } |
588 | 590 | EXPORT_SYMBOL_GPL(of_irq_parse_and_map_pci); |
| 591 | +static void pci_configure_wake_irq(struct pci_dev *pdev, struct gpio_desc *wake) |
| 592 | +{ |
| 593 | + int ret, wake_irq; |
| 594 | + |
| 595 | + wake_irq = gpiod_to_irq(wake); |
| 596 | + if (wake_irq < 0) { |
| 597 | + pci_err(pdev, "Failed to get wake irq: %d\n", wake_irq); |
| 598 | + return; |
| 599 | + } |
| 600 | + |
| 601 | + /* |
| 602 | + * dev_pm_set_dedicated_wake_irq() associates a wakeup IRQ with the |
| 603 | + * device and requests it, but the PM core keeps it disabled by default. |
| 604 | + * The IRQ is enabled only when the device is allowed to wake the system |
| 605 | + * (during system suspend and after runtime suspend), and only if device |
| 606 | + * wakeup is enabled. |
| 607 | + * |
| 608 | + * When the wake IRQ fires, the wakeirq handler invokes pm_runtime_resume() |
| 609 | + * to bring the device back to an active power state (e.g. from D3cold to D0). |
| 610 | + * Once the device is active and the link is usable, the endpoint may signal |
| 611 | + * a PME, which is then handled by the PCI core (either via PME polling or the |
| 612 | + * PCIe PME service driver) to wakeup particular endpoint. |
| 613 | + */ |
| 614 | + ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, wake_irq); |
| 615 | + if (ret < 0) { |
| 616 | + pci_err(pdev, "Failed to set WAKE# IRQ: %d\n", ret); |
| 617 | + return; |
| 618 | + } |
| 619 | + |
| 620 | + ret = irq_set_irq_type(wake_irq, IRQ_TYPE_LEVEL_LOW); |
| 621 | + if (ret < 0) { |
| 622 | + dev_pm_clear_wake_irq(&pdev->dev); |
| 623 | + pci_err(pdev, "Failed to set irq_type: %d\n", ret); |
| 624 | + return; |
| 625 | + } |
| 626 | + |
| 627 | + device_init_wakeup(&pdev->dev, true); |
| 628 | +} |
| 629 | + |
| 630 | +void pci_configure_of_wake_gpio(struct pci_dev *dev) |
| 631 | +{ |
| 632 | + struct device_node *dn = pci_device_to_OF_node(dev); |
| 633 | + struct gpio_desc *gpio; |
| 634 | + |
| 635 | + if (!dn) |
| 636 | + return; |
| 637 | + /* |
| 638 | + * fwnode_gpiod_get() may fail with -EBUSY (e.g. shared WAKE#), but the |
| 639 | + * actual WAKE# trigger from the device would still work and the host |
| 640 | + * controller driver will enable power to the topology. |
| 641 | + * |
| 642 | + * -EPROBE_DEFER cannot be propagated here since pci_device_add() has no |
| 643 | + * retry mechanism. |
| 644 | + */ |
| 645 | + gpio = fwnode_gpiod_get(of_fwnode_handle(dn), "wake", GPIOD_IN, NULL); |
| 646 | + if (!IS_ERR(gpio)) { |
| 647 | + dev->wake = gpio; |
| 648 | + pci_configure_wake_irq(dev, gpio); |
| 649 | + } |
| 650 | +} |
| 651 | + |
| 652 | +void pci_remove_of_wake_gpio(struct pci_dev *dev) |
| 653 | +{ |
| 654 | + struct device_node *dn = pci_device_to_OF_node(dev); |
| 655 | + |
| 656 | + if (!dn) |
| 657 | + return; |
| 658 | + |
| 659 | + device_init_wakeup(&dev->dev, false); |
| 660 | + dev_pm_clear_wake_irq(&dev->dev); |
| 661 | + gpiod_put(dev->wake); |
| 662 | + dev->wake = NULL; |
| 663 | +} |
589 | 664 | #endif /* CONFIG_OF_IRQ */ |
590 | 665 |
|
591 | 666 | static int pci_parse_request_of_pci_ranges(struct device *dev, |
|
0 commit comments