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>
This commit is contained in:
Sebastian Hesselbarth 2013-08-13 14:25:23 +02:00 committed by Jason Cooper
parent e5615c30c1
commit 52ba992e20
2 changed files with 38 additions and 1 deletions

View file

@ -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 {
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";
}; };

View file

@ -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 {
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)
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)
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",