PCI: brcmstb: Disable/enable regulators in suspend/resume
If we found power regulators for a device below the Root Port, disable them during suspend and re-enable them during resume. If any downstream device can be a wakeup device, do not turn off the regulators as the device will need them on. [bhelgaas: drop unused regulator_oops, skip wrapping of .add_bus()/ .remove_bus(), move brcm_pcie_start_link() to .add_bus() in previous patch, squash WOL checking into this patch] Link: https://lore.kernel.org/r/20220725151258.42574-6-jim2101024@gmail.com Link: https://lore.kernel.org/r/20220725151258.42574-7-jim2101024@gmail.com Signed-off-by: Jim Quinlan <jim2101024@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Tested-by: Florian Fainelli <f.fainelli@gmail.com>
This commit is contained in:
parent
9e6be018b2
commit
7a32e9b3ff
|
@ -262,6 +262,7 @@ struct brcm_pcie {
|
||||||
void (*perst_set)(struct brcm_pcie *pcie, u32 val);
|
void (*perst_set)(struct brcm_pcie *pcie, u32 val);
|
||||||
void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
|
void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
|
||||||
struct subdev_regulators *sr;
|
struct subdev_regulators *sr;
|
||||||
|
bool ep_wakeup_capable;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool is_bmips(const struct brcm_pcie *pcie)
|
static inline bool is_bmips(const struct brcm_pcie *pcie)
|
||||||
|
@ -1244,9 +1245,21 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie)
|
||||||
pcie->bridge_sw_init_set(pcie, 1);
|
pcie->bridge_sw_init_set(pcie, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brcm_pcie_suspend(struct device *dev)
|
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, "Possible wake-up device; regulators will not be disabled\n");
|
||||||
|
}
|
||||||
|
return (int) *ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int brcm_pcie_suspend_noirq(struct device *dev)
|
||||||
{
|
{
|
||||||
struct brcm_pcie *pcie = dev_get_drvdata(dev);
|
struct brcm_pcie *pcie = dev_get_drvdata(dev);
|
||||||
|
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
brcm_pcie_turn_off(pcie);
|
brcm_pcie_turn_off(pcie);
|
||||||
|
@ -1264,12 +1277,31 @@ static int brcm_pcie_suspend(struct device *dev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pcie->sr) {
|
||||||
|
/*
|
||||||
|
* 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);
|
clk_disable_unprepare(pcie->clk);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brcm_pcie_resume(struct device *dev)
|
static int brcm_pcie_resume_noirq(struct device *dev)
|
||||||
{
|
{
|
||||||
struct brcm_pcie *pcie = dev_get_drvdata(dev);
|
struct brcm_pcie *pcie = dev_get_drvdata(dev);
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
@ -1304,15 +1336,37 @@ static int brcm_pcie_resume(struct device *dev)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_reset;
|
goto err_reset;
|
||||||
|
|
||||||
|
if (pcie->sr) {
|
||||||
|
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_reset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = brcm_pcie_start_link(pcie);
|
ret = brcm_pcie_start_link(pcie);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_reset;
|
goto err_regulator;
|
||||||
|
|
||||||
if (pcie->msi)
|
if (pcie->msi)
|
||||||
brcm_msi_set_regs(pcie->msi);
|
brcm_msi_set_regs(pcie->msi);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_regulator:
|
||||||
|
if (pcie->sr)
|
||||||
|
regulator_bulk_disable(pcie->sr->num_supplies, pcie->sr->supplies);
|
||||||
err_reset:
|
err_reset:
|
||||||
reset_control_rearm(pcie->rescal);
|
reset_control_rearm(pcie->rescal);
|
||||||
err_disable_clk:
|
err_disable_clk:
|
||||||
|
@ -1541,8 +1595,8 @@ fail:
|
||||||
MODULE_DEVICE_TABLE(of, brcm_pcie_match);
|
MODULE_DEVICE_TABLE(of, brcm_pcie_match);
|
||||||
|
|
||||||
static const struct dev_pm_ops brcm_pcie_pm_ops = {
|
static const struct dev_pm_ops brcm_pcie_pm_ops = {
|
||||||
.suspend = brcm_pcie_suspend,
|
.suspend_noirq = brcm_pcie_suspend_noirq,
|
||||||
.resume = brcm_pcie_resume,
|
.resume_noirq = brcm_pcie_resume_noirq,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_driver brcm_pcie_driver = {
|
static struct platform_driver brcm_pcie_driver = {
|
||||||
|
|
Loading…
Reference in New Issue