diff options
author | Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | 2013-08-13 08:25:23 -0400 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2013-09-30 10:58:43 -0400 |
commit | 52ba992e201f47b878019f268391aa0e27592906 (patch) | |
tree | 597d5361fc22a4680c6ca1bff45becbe4b95a423 | |
parent | e5615c30c1c921dda957638ddf9c9437fcb7bb36 (diff) |
PCI: mvebu: add support for reset on GPIO
This patch adds a check for DT passed reset-gpios property and deasserts/
asserts reset pin on probe/remove with configurable delay. Corresponding
binding documentation is also updated.
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
-rw-r--r-- | Documentation/devicetree/bindings/pci/mvebu-pci.txt | 6 | ||||
-rw-r--r-- | drivers/pci/host/pci-mvebu.c | 33 |
2 files changed, 38 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/pci/mvebu-pci.txt b/Documentation/devicetree/bindings/pci/mvebu-pci.txt index 638673aec306..8bb3245e1946 100644 --- a/Documentation/devicetree/bindings/pci/mvebu-pci.txt +++ b/Documentation/devicetree/bindings/pci/mvebu-pci.txt | |||
@@ -76,6 +76,8 @@ and the following optional properties: | |||
76 | - marvell,pcie-lane: the physical PCIe lane number, for ports having | 76 | - marvell,pcie-lane: the physical PCIe lane number, for ports having |
77 | multiple lanes. If this property is not found, we assume that the | 77 | multiple lanes. If this property is not found, we assume that the |
78 | value is 0. | 78 | value is 0. |
79 | - reset-gpios: optional gpio to PERST# | ||
80 | - reset-delay-us: delay in us to wait after reset de-assertion | ||
79 | 81 | ||
80 | Example: | 82 | Example: |
81 | 83 | ||
@@ -138,6 +140,10 @@ pcie-controller { | |||
138 | interrupt-map = <0 0 0 0 &mpic 58>; | 140 | interrupt-map = <0 0 0 0 &mpic 58>; |
139 | marvell,pcie-port = <0>; | 141 | marvell,pcie-port = <0>; |
140 | marvell,pcie-lane = <0>; | 142 | marvell,pcie-lane = <0>; |
143 | /* low-active PERST# reset on GPIO 25 */ | ||
144 | reset-gpios = <&gpio0 25 1>; | ||
145 | /* wait 20ms for device settle after reset deassertion */ | ||
146 | reset-delay-us = <20000>; | ||
141 | clocks = <&gateclk 5>; | 147 | clocks = <&gateclk 5>; |
142 | status = "disabled"; | 148 | status = "disabled"; |
143 | }; | 149 | }; |
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index af23038a52ac..2d5f414bc45a 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c | |||
@@ -9,14 +9,17 @@ | |||
9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
10 | #include <linux/pci.h> | 10 | #include <linux/pci.h> |
11 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
12 | #include <linux/delay.h> | ||
13 | #include <linux/gpio.h> | ||
12 | #include <linux/module.h> | 14 | #include <linux/module.h> |
13 | #include <linux/mbus.h> | 15 | #include <linux/mbus.h> |
14 | #include <linux/msi.h> | 16 | #include <linux/msi.h> |
15 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
16 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
17 | #include <linux/of_address.h> | 19 | #include <linux/of_address.h> |
18 | #include <linux/of_pci.h> | ||
19 | #include <linux/of_irq.h> | 20 | #include <linux/of_irq.h> |
21 | #include <linux/of_gpio.h> | ||
22 | #include <linux/of_pci.h> | ||
20 | #include <linux/of_platform.h> | 23 | #include <linux/of_platform.h> |
21 | 24 | ||
22 | /* | 25 | /* |
@@ -126,6 +129,9 @@ struct mvebu_pcie_port { | |||
126 | unsigned int io_target; | 129 | unsigned int io_target; |
127 | unsigned int io_attr; | 130 | unsigned int io_attr; |
128 | struct clk *clk; | 131 | struct clk *clk; |
132 | int reset_gpio; | ||
133 | int reset_active_low; | ||
134 | char *reset_name; | ||
129 | struct mvebu_sw_pci_bridge bridge; | 135 | struct mvebu_sw_pci_bridge bridge; |
130 | struct device_node *dn; | 136 | struct device_node *dn; |
131 | struct mvebu_pcie *pcie; | 137 | struct mvebu_pcie *pcie; |
@@ -857,6 +863,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev) | |||
857 | i = 0; | 863 | i = 0; |
858 | for_each_child_of_node(pdev->dev.of_node, child) { | 864 | for_each_child_of_node(pdev->dev.of_node, child) { |
859 | struct mvebu_pcie_port *port = &pcie->ports[i]; | 865 | struct mvebu_pcie_port *port = &pcie->ports[i]; |
866 | enum of_gpio_flags flags; | ||
860 | 867 | ||
861 | if (!of_device_is_available(child)) | 868 | if (!of_device_is_available(child)) |
862 | continue; | 869 | continue; |
@@ -897,6 +904,30 @@ static int mvebu_pcie_probe(struct platform_device *pdev) | |||
897 | continue; | 904 | continue; |
898 | } | 905 | } |
899 | 906 | ||
907 | port->reset_gpio = of_get_named_gpio_flags(child, | ||
908 | "reset-gpios", 0, &flags); | ||
909 | if (gpio_is_valid(port->reset_gpio)) { | ||
910 | u32 reset_udelay = 20000; | ||
911 | |||
912 | port->reset_active_low = flags & OF_GPIO_ACTIVE_LOW; | ||
913 | port->reset_name = kasprintf(GFP_KERNEL, | ||
914 | "pcie%d.%d-reset", port->port, port->lane); | ||
915 | of_property_read_u32(child, "reset-delay-us", | ||
916 | &reset_udelay); | ||
917 | |||
918 | ret = devm_gpio_request_one(&pdev->dev, | ||
919 | port->reset_gpio, GPIOF_DIR_OUT, port->reset_name); | ||
920 | if (ret) { | ||
921 | if (ret == -EPROBE_DEFER) | ||
922 | return ret; | ||
923 | continue; | ||
924 | } | ||
925 | |||
926 | gpio_set_value(port->reset_gpio, | ||
927 | (port->reset_active_low) ? 1 : 0); | ||
928 | msleep(reset_udelay/1000); | ||
929 | } | ||
930 | |||
900 | port->clk = of_clk_get_by_name(child, NULL); | 931 | port->clk = of_clk_get_by_name(child, NULL); |
901 | if (IS_ERR(port->clk)) { | 932 | if (IS_ERR(port->clk)) { |
902 | dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n", | 933 | dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n", |