diff options
author | Quentin Schulz <quentin.schulz@free-electrons.com> | 2017-06-08 04:07:42 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-07-02 19:43:39 -0400 |
commit | c26ebe98a103479dae9284fe0a86a95af4a5cd46 (patch) | |
tree | 5af5b1c5aa475d9d3c7f35e86c210c4940bc5f18 | |
parent | 769b461fc0c0451bacf75826d5830fc07c5a57e4 (diff) |
PCI: imx6: Add regulator support
Some boards might require to control a regulator to power the PCIe port.
Add support for an optional regulator defined in Device Tree linked in the
PCIe controller under `vpcie-supply`. If present, the regulator will be
disabled and then enabled as part of the PCIe host initialization process
and will be disabled when shutting down.
Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
[bhelgaas: use dev_err() instead of pr_err() in
imx6_pcie_assert_core_reset()]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Richard Zhu <hongxing.zhu@nxp.com>
-rw-r--r-- | Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt | 4 | ||||
-rw-r--r-- | drivers/pci/dwc/pci-imx6.c | 37 |
2 files changed, 40 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt index e3d5680875b1..cf92d3ba5a26 100644 --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt | |||
@@ -33,6 +33,10 @@ Optional properties: | |||
33 | - reset-gpio-active-high: If present then the reset sequence using the GPIO | 33 | - reset-gpio-active-high: If present then the reset sequence using the GPIO |
34 | specified in the "reset-gpio" property is reversed (H=reset state, | 34 | specified in the "reset-gpio" property is reversed (H=reset state, |
35 | L=operation state). | 35 | L=operation state). |
36 | - vpcie-supply: Should specify the regulator in charge of PCIe port power. | ||
37 | The regulator will be enabled when initializing the PCIe host and | ||
38 | disabled either as part of the init process or when shutting down the | ||
39 | host. | ||
36 | 40 | ||
37 | Additional required properties for imx6sx-pcie: | 41 | Additional required properties for imx6sx-pcie: |
38 | - clock names: Must include the following additional entries: | 42 | - clock names: Must include the following additional entries: |
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c index a98cba55c7f0..9717ef71e71b 100644 --- a/drivers/pci/dwc/pci-imx6.c +++ b/drivers/pci/dwc/pci-imx6.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
25 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
26 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
27 | #include <linux/regulator/consumer.h> | ||
27 | #include <linux/resource.h> | 28 | #include <linux/resource.h> |
28 | #include <linux/signal.h> | 29 | #include <linux/signal.h> |
29 | #include <linux/types.h> | 30 | #include <linux/types.h> |
@@ -59,6 +60,7 @@ struct imx6_pcie { | |||
59 | u32 tx_swing_full; | 60 | u32 tx_swing_full; |
60 | u32 tx_swing_low; | 61 | u32 tx_swing_low; |
61 | int link_gen; | 62 | int link_gen; |
63 | struct regulator *vpcie; | ||
62 | }; | 64 | }; |
63 | 65 | ||
64 | /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ | 66 | /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ |
@@ -257,6 +259,8 @@ static int imx6q_pcie_abort_handler(unsigned long addr, | |||
257 | 259 | ||
258 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) | 260 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) |
259 | { | 261 | { |
262 | struct device *dev = imx6_pcie->pci->dev; | ||
263 | |||
260 | switch (imx6_pcie->variant) { | 264 | switch (imx6_pcie->variant) { |
261 | case IMX7D: | 265 | case IMX7D: |
262 | reset_control_assert(imx6_pcie->pciephy_reset); | 266 | reset_control_assert(imx6_pcie->pciephy_reset); |
@@ -283,6 +287,14 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) | |||
283 | IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16); | 287 | IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16); |
284 | break; | 288 | break; |
285 | } | 289 | } |
290 | |||
291 | if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) { | ||
292 | int ret = regulator_disable(imx6_pcie->vpcie); | ||
293 | |||
294 | if (ret) | ||
295 | dev_err(dev, "failed to disable vpcie regulator: %d\n", | ||
296 | ret); | ||
297 | } | ||
286 | } | 298 | } |
287 | 299 | ||
288 | static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) | 300 | static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) |
@@ -349,10 +361,19 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) | |||
349 | struct device *dev = pci->dev; | 361 | struct device *dev = pci->dev; |
350 | int ret; | 362 | int ret; |
351 | 363 | ||
364 | if (imx6_pcie->vpcie && !regulator_is_enabled(imx6_pcie->vpcie)) { | ||
365 | ret = regulator_enable(imx6_pcie->vpcie); | ||
366 | if (ret) { | ||
367 | dev_err(dev, "failed to enable vpcie regulator: %d\n", | ||
368 | ret); | ||
369 | return; | ||
370 | } | ||
371 | } | ||
372 | |||
352 | ret = clk_prepare_enable(imx6_pcie->pcie_phy); | 373 | ret = clk_prepare_enable(imx6_pcie->pcie_phy); |
353 | if (ret) { | 374 | if (ret) { |
354 | dev_err(dev, "unable to enable pcie_phy clock\n"); | 375 | dev_err(dev, "unable to enable pcie_phy clock\n"); |
355 | return; | 376 | goto err_pcie_phy; |
356 | } | 377 | } |
357 | 378 | ||
358 | ret = clk_prepare_enable(imx6_pcie->pcie_bus); | 379 | ret = clk_prepare_enable(imx6_pcie->pcie_bus); |
@@ -412,6 +433,13 @@ err_pcie: | |||
412 | clk_disable_unprepare(imx6_pcie->pcie_bus); | 433 | clk_disable_unprepare(imx6_pcie->pcie_bus); |
413 | err_pcie_bus: | 434 | err_pcie_bus: |
414 | clk_disable_unprepare(imx6_pcie->pcie_phy); | 435 | clk_disable_unprepare(imx6_pcie->pcie_phy); |
436 | err_pcie_phy: | ||
437 | if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) { | ||
438 | ret = regulator_disable(imx6_pcie->vpcie); | ||
439 | if (ret) | ||
440 | dev_err(dev, "failed to disable vpcie regulator: %d\n", | ||
441 | ret); | ||
442 | } | ||
415 | } | 443 | } |
416 | 444 | ||
417 | static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) | 445 | static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) |
@@ -775,6 +803,13 @@ static int imx6_pcie_probe(struct platform_device *pdev) | |||
775 | if (ret) | 803 | if (ret) |
776 | imx6_pcie->link_gen = 1; | 804 | imx6_pcie->link_gen = 1; |
777 | 805 | ||
806 | imx6_pcie->vpcie = devm_regulator_get_optional(&pdev->dev, "vpcie"); | ||
807 | if (IS_ERR(imx6_pcie->vpcie)) { | ||
808 | if (PTR_ERR(imx6_pcie->vpcie) == -EPROBE_DEFER) | ||
809 | return -EPROBE_DEFER; | ||
810 | imx6_pcie->vpcie = NULL; | ||
811 | } | ||
812 | |||
778 | platform_set_drvdata(pdev, imx6_pcie); | 813 | platform_set_drvdata(pdev, imx6_pcie); |
779 | 814 | ||
780 | ret = imx6_add_pcie_port(imx6_pcie, pdev); | 815 | ret = imx6_add_pcie_port(imx6_pcie, pdev); |