From e1127aca07e48ec385b0346b1102d68e53c467e8 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Thu, 1 Aug 2013 19:05:34 +0000
Subject: kernel: b53: add support for GPIO reset

This is needed for some switches used on bcm47xx SoCs like the one on the Asus RT-N66U.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>

SVN-Revision: 37645
---
 .../generic/files/drivers/net/phy/b53/b53_common.c | 29 ++++++++++++++++++++++
 .../generic/files/drivers/net/phy/b53/b53_priv.h   | 14 +++++++++++
 2 files changed, 43 insertions(+)

(limited to 'target/linux/generic/files/drivers/net')

diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
index 86e3a787fb..97968dbf0b 100644
--- a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
@@ -20,6 +20,7 @@
 
 #include <linux/delay.h>
 #include <linux/export.h>
+#include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/switch.h>
@@ -451,10 +452,30 @@ static int b53_apply(struct b53_device *dev)
 	return 0;
 }
 
+void b53_switch_reset_gpio(struct b53_device *dev)
+{
+	int gpio = dev->reset_gpio;
+
+	if (gpio < 0)
+		return;
+
+	gpio_set_value(gpio, 0);
+	gpio_direction_output(gpio, 1);
+	gpio_set_value(gpio, 0);
+	mdelay(50);
+
+	gpio_set_value(gpio, 1);
+	mdelay(20);
+
+	dev->current_page = 0xff;
+}
+
 static int b53_switch_reset(struct b53_device *dev)
 {
 	u8 mgmt;
 
+	b53_switch_reset_gpio(dev);
+
 	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
 
 	if (!(mgmt & SM_SW_FWD_EN)) {
@@ -1114,6 +1135,7 @@ int b53_switch_init(struct b53_device *dev)
 {
 	struct switch_dev *sw_dev = &dev->sw_dev;
 	unsigned i;
+	int ret;
 
 	for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) {
 		const struct b53_chip_data *chip = &b53_switch_chips[i];
@@ -1192,6 +1214,13 @@ int b53_switch_init(struct b53_device *dev)
 	if (!dev->buf)
 		return -ENOMEM;
 
+	dev->reset_gpio = b53_switch_get_reset_gpio(dev);
+	if (dev->reset_gpio >= 0) {
+		ret = devm_gpio_request(dev->dev, dev->reset_gpio, "robo_reset");
+		if (ret)
+			return ret;
+	}
+
 	return b53_switch_reset(dev);
 }
 
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h b/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
index fca74ae4b9..53da406407 100644
--- a/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
@@ -75,6 +75,7 @@ struct b53_device {
 	u8 duplex_reg;
 	u8 jumbo_pm_reg;
 	u8 jumbo_size_reg;
+	int reset_gpio;
 
 	/* used ports mask */
 	u16 enabled_ports;
@@ -275,4 +276,17 @@ static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg,
 	return ret;
 }
 
+#ifdef CONFIG_BCM47XX
+
+#include <bcm47xx_nvram.h>
+static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
+{
+       return bcm47xx_nvram_gpio_pin("robo_reset");
+}
+#else
+static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
+{
+       return -ENOENT;
+}
+#endif
 #endif
-- 
cgit v1.2.3