ks8851: Add GPIO and regulator support
Allow the ks8851 driver to configure regulators and GPIOs
specified as platform data or in device tree.
Change-Id: I806f7c22ba4b75eb26720704968cdec9cd7796c8
Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org>
(cherry picked from commit c990b2faa3ce0b4f2361630a687abdedee4241a9)
Signed-off-by: Sudhir Sharma <sudsha@codeaurora.org>
diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c
index 5e313e9..a807354 100644
--- a/drivers/net/ethernet/micrel/ks8851.c
+++ b/drivers/net/ethernet/micrel/ks8851.c
@@ -23,8 +23,13 @@
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/eeprom_93cx6.h>
+#include <linux/ks8851.h>
#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include "ks8851.h"
@@ -131,6 +136,10 @@
struct spi_transfer spi_xfer1;
struct spi_transfer spi_xfer2[2];
+ struct regulator *vdd_io;
+ struct regulator *vdd_phy;
+ int rst_gpio;
+
struct eeprom_93cx6 eeprom;
};
@@ -1415,6 +1424,66 @@
#define ks8851_resume NULL
#endif
+static int __devinit ks8851_init_hw(struct spi_device *spi,
+ struct ks8851_net *ks)
+{
+ struct ks8851_pdata *pdata = spi->dev.platform_data;
+ struct device_node *dnode = spi->dev.of_node;
+ enum of_gpio_flags flags;
+ int ret;
+
+ ks->rst_gpio = -ENODEV;
+
+ if (dnode)
+ ks->rst_gpio = of_get_named_gpio_flags(dnode, "rst-gpio",
+ 0, &flags);
+ else if (pdata)
+ ks->rst_gpio = pdata->rst_gpio;
+
+ if (gpio_is_valid(ks->rst_gpio)) {
+ ret = gpio_request(ks->rst_gpio, "ks8851_rst");
+ if (ret) {
+ pr_err("ks8851 gpio_request failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Make sure the chip is in reset state */
+ gpio_direction_output(ks->rst_gpio, 0);
+ }
+
+ ks->vdd_io = regulator_get(&spi->dev, "vdd-io");
+
+ if (IS_ERR(ks->vdd_io)) {
+ ret = PTR_ERR(ks->vdd_io);
+ goto fail_gpio;
+ }
+
+ ks->vdd_phy = regulator_get(&spi->dev, "vdd-phy");
+
+ if (IS_ERR(ks->vdd_phy)) {
+ regulator_put(ks->vdd_io);
+ ret = PTR_ERR(ks->vdd_phy);
+ goto fail_gpio;
+ }
+
+ regulator_enable(ks->vdd_io);
+ regulator_enable(ks->vdd_phy);
+
+ /* Wait for atleast 10ms after turning on regulator */
+ usleep_range(10000, 11000);
+
+ if (gpio_is_valid(ks->rst_gpio))
+ gpio_direction_output(ks->rst_gpio, 1);
+
+ return 0;
+
+fail_gpio:
+ if (gpio_is_valid(ks->rst_gpio))
+ gpio_free(ks->rst_gpio);
+
+ return ret;
+}
+
static int __devinit ks8851_probe(struct spi_device *spi)
{
struct net_device *ndev;
@@ -1430,6 +1499,10 @@
ks = netdev_priv(ndev);
+ ret = ks8851_init_hw(spi, ks);
+ if (ret)
+ goto err_init;
+
ks->netdev = ndev;
ks->spidev = spi;
ks->tx_space = 6144;
@@ -1530,6 +1603,20 @@
err_id:
err_irq:
+ if (gpio_is_valid(ks->rst_gpio))
+ gpio_free(ks->rst_gpio);
+
+ if (!IS_ERR(ks->vdd_io)) {
+ regulator_disable(ks->vdd_io);
+ regulator_put(ks->vdd_io);
+ }
+
+ if (!IS_ERR(ks->vdd_phy)) {
+ regulator_disable(ks->vdd_phy);
+ regulator_put(ks->vdd_phy);
+ }
+
+err_init:
free_netdev(ndev);
return ret;
}
@@ -1541,6 +1628,19 @@
if (netif_msg_drv(priv))
dev_info(&spi->dev, "remove\n");
+ if (gpio_is_valid(priv->rst_gpio))
+ gpio_free(priv->rst_gpio);
+
+ if (!IS_ERR(priv->vdd_io)) {
+ regulator_disable(priv->vdd_io);
+ regulator_put(priv->vdd_io);
+ }
+
+ if (!IS_ERR(priv->vdd_phy)) {
+ regulator_disable(priv->vdd_phy);
+ regulator_put(priv->vdd_phy);
+ }
+
unregister_netdev(priv->netdev);
free_irq(spi->irq, priv);
free_netdev(priv->netdev);
@@ -1548,9 +1648,17 @@
return 0;
}
+static struct of_device_id ks8851_match_table[] = {
+ {
+ .compatible = "micrel,ks8851",
+ },
+ {}
+};
+
static struct spi_driver ks8851_driver = {
.driver = {
.name = "ks8851",
+ .of_match_table = ks8851_match_table,
.owner = THIS_MODULE,
},
.probe = ks8851_probe,