Merge branch 'platform/remove_owner' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / drivers / net / ethernet / smsc / smc91x.c
index a2649c81a39371070c70aedeac7e6dcb57823ac4..5d77e6f50dd80bf61425530a427dd2544ddfe37e 100644 (file)
@@ -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)