diff options
author | Jim Quinlan <jim2101024@gmail.com> | 2022-01-06 11:03:30 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2022-01-12 13:45:50 -0600 |
commit | 11ed8b8624b8085f706864b4addcd304b1e4fc38 (patch) | |
tree | f9f6334b5210af3896d5dd3c19e1763ed33d5d5f /drivers/pci | |
parent | 93e41f3fca3d4a0f927b784012338c37f80a8a80 (diff) |
PCI: brcmstb: Do not turn off WOL regulators on suspend
If any downstream device can be a wakeup device, do not turn off the
regulators as the device will need them on.
Link: https://lore.kernel.org/r/20220106160332.2143-8-jim2101024@gmail.com
Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/controller/pcie-brcmstb.c | 53 |
1 files changed, 44 insertions, 9 deletions
diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 5a7ee482ab9a..1cba6e668150 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -310,6 +310,7 @@ struct brcm_pcie { void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val); bool refusal_mode; struct subdev_regulators *sr; + bool ep_wakeup_capable; }; /* @@ -1278,9 +1279,21 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie) pcie->bridge_sw_init_set(pcie, 1); } +static int pci_dev_may_wakeup(struct pci_dev *dev, void *data) +{ + bool *ret = data; + + if (device_may_wakeup(&dev->dev)) { + *ret = true; + dev_info(&dev->dev, "disable cancelled for wake-up device\n"); + } + return (int) *ret; +} + static int brcm_pcie_suspend(struct device *dev) { struct brcm_pcie *pcie = dev_get_drvdata(dev); + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); int ret; brcm_pcie_turn_off(pcie); @@ -1299,11 +1312,22 @@ static int brcm_pcie_suspend(struct device *dev) } if (pcie->sr) { - ret = regulator_bulk_disable(pcie->sr->num_supplies, pcie->sr->supplies); - if (ret) { - dev_err(dev, "Could not turn off regulators\n"); - reset_control_reset(pcie->rescal); - return ret; + /* + * Now turn off the regulators, but if at least one + * downstream device is enabled as a wake-up source, do not + * turn off regulators. + */ + pcie->ep_wakeup_capable = false; + pci_walk_bus(bridge->bus, pci_dev_may_wakeup, + &pcie->ep_wakeup_capable); + if (!pcie->ep_wakeup_capable) { + ret = regulator_bulk_disable(pcie->sr->num_supplies, + pcie->sr->supplies); + if (ret) { + dev_err(dev, "Could not turn off regulators\n"); + reset_control_reset(pcie->rescal); + return ret; + } } } clk_disable_unprepare(pcie->clk); @@ -1324,10 +1348,21 @@ static int brcm_pcie_resume(struct device *dev) return ret; if (pcie->sr) { - ret = regulator_bulk_enable(pcie->sr->num_supplies, pcie->sr->supplies); - if (ret) { - dev_err(dev, "Could not turn on regulators\n"); - goto err_disable_clk; + if (pcie->ep_wakeup_capable) { + /* + * We are resuming from a suspend. In the suspend we + * did not disable the power supplies, so there is + * no need to enable them (and falsely increase their + * usage count). + */ + pcie->ep_wakeup_capable = false; + } else { + ret = regulator_bulk_enable(pcie->sr->num_supplies, + pcie->sr->supplies); + if (ret) { + dev_err(dev, "Could not turn on regulators\n"); + goto err_disable_clk; + } } } |