ARM-based Broadcom STB SoCs have GPIO-based voltage regulator for PCIe turning off/on power supplies. Signed-off-by: Jaedon Shin <jaedon.shin@xxxxxxxxx> --- .../bindings/pci/brcm,stb-pcie.yaml | 3 ++ drivers/pci/controller/pcie-brcmstb.c | 36 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml index 77d3e81a437b..efa5c885724b 100644 --- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml @@ -56,6 +56,9 @@ properties: description: Indicates usage of spread-spectrum clocking. type: boolean + supply-names: + description: List of regulator supplies to use for PCIe + required: - reg - dma-ranges diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index d20aabc26273..8968ef7fa55d 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -23,6 +23,7 @@ #include <linux/of_platform.h> #include <linux/pci.h> #include <linux/printk.h> +#include <linux/regulator/consumer.h> #include <linux/sizes.h> #include <linux/slab.h> #include <linux/string.h> @@ -173,6 +174,8 @@ struct brcm_pcie { int gen; u64 msi_target_addr; struct brcm_msi *msi; + struct regulator_bulk_data *vreg_bulk; + int num_vregs; }; /* @@ -898,6 +901,7 @@ static void __brcm_pcie_remove(struct brcm_pcie *pcie) { brcm_msi_remove(pcie); brcm_pcie_turn_off(pcie); + regulator_bulk_disable(pcie->num_vregs, pcie->vreg_bulk); clk_disable_unprepare(pcie->clk); clk_put(pcie->clk); } @@ -920,6 +924,8 @@ static int brcm_pcie_probe(struct platform_device *pdev) struct brcm_pcie *pcie; struct pci_bus *child; struct resource *res; + struct regulator_bulk_data *bulk; + int i; int ret; bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie)); @@ -955,6 +961,36 @@ static int brcm_pcie_probe(struct platform_device *pdev) return ret; } + ret = of_property_count_strings(np, "supply-names"); + pcie->num_vregs = (ret < 0) ? 0 : ret; + + if (pcie->num_vregs) { + bulk = devm_kcalloc(pcie->dev, pcie->num_vregs, sizeof(*bulk), + GFP_KERNEL); + if (!bulk) { + clk_disable_unprepare(pcie->clk); + return -ENOMEM; + } + + for (i = 0; i < pcie->num_vregs; i++) + of_property_read_string_index(np, "supply-names", i, + &bulk[i].supply); + + ret = devm_regulator_bulk_get(pcie->dev, pcie->num_vregs, bulk); + if (ret < 0) { + clk_disable_unprepare(pcie->clk); + return ret; + } + + pcie->vreg_bulk = bulk; + } + + ret = regulator_bulk_enable(pcie->num_vregs, pcie->vreg_bulk); + if (ret) { + clk_disable_unprepare(pcie->clk); + return ret; + } + ret = brcm_pcie_setup(pcie); if (ret) goto fail; -- 2.21.0