Commit 52ba992e authored by Sebastian Hesselbarth's avatar Sebastian Hesselbarth Committed by Jason Cooper

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: default avatarSebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: default avatarJason Cooper <jason@lakedaemon.net>
parent e5615c30
...@@ -76,6 +76,8 @@ and the following optional properties: ...@@ -76,6 +76,8 @@ and the following optional properties:
- marvell,pcie-lane: the physical PCIe lane number, for ports having - marvell,pcie-lane: the physical PCIe lane number, for ports having
multiple lanes. If this property is not found, we assume that the multiple lanes. If this property is not found, we assume that the
value is 0. value is 0.
- reset-gpios: optional gpio to PERST#
- reset-delay-us: delay in us to wait after reset de-assertion
Example: Example:
...@@ -138,6 +140,10 @@ pcie-controller { ...@@ -138,6 +140,10 @@ pcie-controller {
interrupt-map = <0 0 0 0 &mpic 58>; interrupt-map = <0 0 0 0 &mpic 58>;
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
/* low-active PERST# reset on GPIO 25 */
reset-gpios = <&gpio0 25 1>;
/* wait 20ms for device settle after reset deassertion */
reset-delay-us = <20000>;
clocks = <&gateclk 5>; clocks = <&gateclk 5>;
status = "disabled"; status = "disabled";
}; };
......
...@@ -9,14 +9,17 @@ ...@@ -9,14 +9,17 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mbus.h> #include <linux/mbus.h>
#include <linux/msi.h> #include <linux/msi.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_pci.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
/* /*
...@@ -126,6 +129,9 @@ struct mvebu_pcie_port { ...@@ -126,6 +129,9 @@ struct mvebu_pcie_port {
unsigned int io_target; unsigned int io_target;
unsigned int io_attr; unsigned int io_attr;
struct clk *clk; struct clk *clk;
int reset_gpio;
int reset_active_low;
char *reset_name;
struct mvebu_sw_pci_bridge bridge; struct mvebu_sw_pci_bridge bridge;
struct device_node *dn; struct device_node *dn;
struct mvebu_pcie *pcie; struct mvebu_pcie *pcie;
...@@ -857,6 +863,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev) ...@@ -857,6 +863,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
i = 0; i = 0;
for_each_child_of_node(pdev->dev.of_node, child) { for_each_child_of_node(pdev->dev.of_node, child) {
struct mvebu_pcie_port *port = &pcie->ports[i]; struct mvebu_pcie_port *port = &pcie->ports[i];
enum of_gpio_flags flags;
if (!of_device_is_available(child)) if (!of_device_is_available(child))
continue; continue;
...@@ -897,6 +904,30 @@ static int mvebu_pcie_probe(struct platform_device *pdev) ...@@ -897,6 +904,30 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
continue; continue;
} }
port->reset_gpio = of_get_named_gpio_flags(child,
"reset-gpios", 0, &flags);
if (gpio_is_valid(port->reset_gpio)) {
u32 reset_udelay = 20000;
port->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
port->reset_name = kasprintf(GFP_KERNEL,
"pcie%d.%d-reset", port->port, port->lane);
of_property_read_u32(child, "reset-delay-us",
&reset_udelay);
ret = devm_gpio_request_one(&pdev->dev,
port->reset_gpio, GPIOF_DIR_OUT, port->reset_name);
if (ret) {
if (ret == -EPROBE_DEFER)
return ret;
continue;
}
gpio_set_value(port->reset_gpio,
(port->reset_active_low) ? 1 : 0);
msleep(reset_udelay/1000);
}
port->clk = of_clk_get_by_name(child, NULL); port->clk = of_clk_get_by_name(child, NULL);
if (IS_ERR(port->clk)) { if (IS_ERR(port->clk)) {
dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n", dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment