summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2014-10-30 19:59:27 +0300
committerDavid S. Miller <davem@davemloft.net>2014-10-31 22:54:18 +0300
commit7d2911c4381555b31ef0bcae42a0dbf9ade7426e (patch)
tree2baef674f3a88ad52943fade77b0129f188ab1c8 /drivers/net
parentde05c400f7dfa566f598140f8604a5de8067cd5f (diff)
downloadlinux-7d2911c4381555b31ef0bcae42a0dbf9ade7426e.tar.xz
net: smc91x: Fix gpios for device tree based booting
With legacy booting, the platform init code was taking care of the configuring of GPIOs. With device tree based booting, things may or may not work depending what bootloader has configured or if the legacy platform code gets called. Let's add support for the pwrdn and reset GPIOs to the smc91x driver to fix the issues of smc91x not working properly when booted in device tree mode. And let's change n900 to use these settings as some versions of the bootloader do not configure things properly causing errors. Reported-by: Kevin Hilman <khilman@linaro.org> Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c58
-rw-r--r--drivers/net/ethernet/smsc/smc91x.h3
2 files changed, 61 insertions, 0 deletions
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 5e94d00b96b3..2c62208077fe 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -81,6 +81,7 @@ static const char version[] =
#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -2188,6 +2189,41 @@ static const struct of_device_id smc91x_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, smc91x_match);
+
+/**
+ * of_try_set_control_gpio - configure a gpio if it exists
+ */
+static int try_toggle_control_gpio(struct device *dev,
+ struct gpio_desc **desc,
+ const char *name, int index,
+ int value, unsigned int nsdelay)
+{
+ struct gpio_desc *gpio = *desc;
+ int res;
+
+ gpio = devm_gpiod_get_index(dev, name, index);
+ if (IS_ERR(gpio)) {
+ if (PTR_ERR(gpio) == -ENOENT) {
+ *desc = NULL;
+ return 0;
+ }
+
+ return PTR_ERR(gpio);
+ }
+ res = gpiod_direction_output(gpio, !value);
+ if (res) {
+ dev_err(dev, "unable to toggle gpio %s: %i\n", name, res);
+ devm_gpiod_put(dev, gpio);
+ gpio = NULL;
+ return res;
+ }
+ if (nsdelay)
+ usleep_range(nsdelay, 2 * nsdelay);
+ gpiod_set_value_cansleep(gpio, value);
+ *desc = gpio;
+
+ return 0;
+}
#endif
/*
@@ -2237,6 +2273,28 @@ static int smc_drv_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
u32 val;
+ /* Optional pwrdwn GPIO configured? */
+ ret = try_toggle_control_gpio(&pdev->dev, &lp->power_gpio,
+ "power", 0, 0, 100);
+ if (ret)
+ return ret;
+
+ /*
+ * Optional reset GPIO configured? Minimum 100 ns reset needed
+ * according to LAN91C96 datasheet page 14.
+ */
+ ret = try_toggle_control_gpio(&pdev->dev, &lp->reset_gpio,
+ "reset", 0, 0, 100);
+ if (ret)
+ return ret;
+
+ /*
+ * Need to wait for optional EEPROM to load, max 750 us according
+ * to LAN91C96 datasheet page 55.
+ */
+ if (lp->reset_gpio)
+ usleep_range(750, 1000);
+
/* Combination of IO widths supported, default to 16-bit */
if (!of_property_read_u32(np, "reg-io-width", &val)) {
if (val & 1)
diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h
index 47dce918eb0f..2a38dacbbd27 100644
--- a/drivers/net/ethernet/smsc/smc91x.h
+++ b/drivers/net/ethernet/smsc/smc91x.h
@@ -298,6 +298,9 @@ struct smc_local {
struct sk_buff *pending_tx_skb;
struct tasklet_struct tx_task;
+ struct gpio_desc *power_gpio;
+ struct gpio_desc *reset_gpio;
+
/* version/revision of the SMC91x chip */
int version;