diff options
author | David S. Miller <davem@davemloft.net> | 2015-11-23 11:53:11 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-11-23 11:53:11 -0500 |
commit | 3d40e44361eab3dd6c969241d12dac7466eb7174 (patch) | |
tree | b315bb7d08318d8cf53b1a22ad5505d1840706f4 | |
parent | 3f8c0f7efb4fcac11f31afa97584d06118c614bb (diff) | |
parent | c8c1b39a86940edd35439f1e5c9ff39888daf0f0 (diff) | |
download | op-kernel-dev-3d40e44361eab3dd6c969241d12dac7466eb7174.zip op-kernel-dev-3d40e44361eab3dd6c969241d12dac7466eb7174.tar.gz |
Merge branch 'dsa-gpio-reset'
Andrew Lunn says:
====================
DSA: GPIO to reset switches
These two patches add support for using a GPIO to hard reset a switch
during reset.
v2:
Thanks to a clue from Neil Armstrong, i figured out how to convert the
gpio into a gpiod, while keeping the ACTIVE_LOW flag, so simplifiying
the set/reset code.
I have not included the Tested-by: from Phil Reid, since i made a lot
of changes.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/devicetree/bindings/net/dsa/dsa.txt | 3 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.c | 10 | ||||
-rw-r--r-- | include/net/dsa.h | 8 | ||||
-rw-r--r-- | net/dsa/dsa.c | 17 |
4 files changed, 38 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.txt b/Documentation/devicetree/bindings/net/dsa/dsa.txt index 04e6bef..5fdbbcd 100644 --- a/Documentation/devicetree/bindings/net/dsa/dsa.txt +++ b/Documentation/devicetree/bindings/net/dsa/dsa.txt @@ -31,6 +31,8 @@ A switch child node has the following optional property: switch. Must be set if the switch can not detect the presence and/or size of a connected EEPROM, otherwise optional. +- reset-gpios : phandle and specifier to a gpio line connected to + reset pin of the switch chip. A switch may have multiple "port" children nodes @@ -114,6 +116,7 @@ Example: #size-cells = <0>; reg = <17 1>; /* MDIO address 17, switch 1 in tree */ mii-bus = <&mii_bus1>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; switch1port0: port@0 { reg = <0>; diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index b06dba0..75e245c 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -19,6 +19,7 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/netdevice.h> +#include <linux/gpio/consumer.h> #include <linux/phy.h> #include <net/dsa.h> #include <net/switchdev.h> @@ -2323,6 +2324,7 @@ int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); u16 is_reset = (ppu_active ? 0x8800 : 0xc800); + struct gpio_desc *gpiod = ds->pd->reset; unsigned long timeout; int ret; int i; @@ -2336,6 +2338,14 @@ int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active) /* Wait for transmit queues to drain. */ usleep_range(2000, 4000); + /* If there is a gpio connected to the reset pin, toggle it */ + if (gpiod) { + gpiod_set_value_cansleep(gpiod, 1); + usleep_range(10000, 20000); + gpiod_set_value_cansleep(gpiod, 0); + usleep_range(10000, 20000); + } + /* Reset the switch. Keep the PPU active if requested. The PPU * needs to be active to support indirect phy register access * through global registers 0x18 and 0x19. diff --git a/include/net/dsa.h b/include/net/dsa.h index 82a4c60..3f23dd9 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -16,6 +16,7 @@ #include <linux/timer.h> #include <linux/workqueue.h> #include <linux/of.h> +#include <linux/of_gpio.h> #include <linux/phy.h> #include <linux/phy_fixed.h> #include <linux/ethtool.h> @@ -64,6 +65,13 @@ struct dsa_chip_data { * NULL if there is only one switch chip. */ s8 *rtable; + + /* + * A switch may have a GPIO line tied to its reset pin. Parse + * this from the device tree, and use it before performing + * switch soft reset. + */ + struct gpio_desc *reset; }; struct dsa_platform_data { diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 1eba07f..0b5565f 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -21,6 +21,7 @@ #include <linux/of_mdio.h> #include <linux/of_platform.h> #include <linux/of_net.h> +#include <linux/of_gpio.h> #include <linux/sysfs.h> #include <linux/phy_fixed.h> #include "dsa_priv.h" @@ -688,6 +689,9 @@ static int dsa_of_probe(struct device *dev) const char *port_name; int chip_index, port_index; const unsigned int *sw_addr, *port_reg; + int gpio; + enum of_gpio_flags of_flags; + unsigned long flags; u32 eeprom_len; int ret; @@ -766,6 +770,19 @@ static int dsa_of_probe(struct device *dev) put_device(cd->host_dev); cd->host_dev = &mdio_bus_switch->dev; } + gpio = of_get_named_gpio_flags(child, "reset-gpios", 0, + &of_flags); + if (gpio_is_valid(gpio)) { + flags = (of_flags == OF_GPIO_ACTIVE_LOW ? + GPIOF_ACTIVE_LOW : 0); + ret = devm_gpio_request_one(dev, gpio, flags, + "switch_reset"); + if (ret) + goto out_free_chip; + + cd->reset = gpio_to_desc(gpio); + gpiod_direction_output(cd->reset, 0); + } for_each_available_child_of_node(child, port) { port_reg = of_get_property(port, "reg", NULL); |