Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / drivers / i2c / i2c-core-base.c
index 26f03a1..5ec082e 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/of_device.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_wakeirq.h>
@@ -181,6 +182,8 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)
 
        if (bri->prepare_recovery)
                bri->prepare_recovery(adap);
+       if (bri->pinctrl)
+               pinctrl_select_state(bri->pinctrl, bri->pins_gpio);
 
        /*
         * If we can set SDA, we will always create a STOP to ensure additional
@@ -236,6 +239,8 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)
 
        if (bri->unprepare_recovery)
                bri->unprepare_recovery(adap);
+       if (bri->pinctrl)
+               pinctrl_select_state(bri->pinctrl, bri->pins_default);
 
        return ret;
 }
@@ -251,13 +256,135 @@ int i2c_recover_bus(struct i2c_adapter *adap)
 }
 EXPORT_SYMBOL_GPL(i2c_recover_bus);
 
-static void i2c_init_recovery(struct i2c_adapter *adap)
+static void i2c_gpio_init_pinctrl_recovery(struct i2c_adapter *adap)
+{
+       struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
+       struct device *dev = &adap->dev;
+       struct pinctrl *p = bri->pinctrl;
+
+       /*
+        * we can't change states without pinctrl, so remove the states if
+        * populated
+        */
+       if (!p) {
+               bri->pins_default = NULL;
+               bri->pins_gpio = NULL;
+               return;
+       }
+
+       if (!bri->pins_default) {
+               bri->pins_default = pinctrl_lookup_state(p,
+                                                        PINCTRL_STATE_DEFAULT);
+               if (IS_ERR(bri->pins_default)) {
+                       dev_dbg(dev, PINCTRL_STATE_DEFAULT " state not found for GPIO recovery\n");
+                       bri->pins_default = NULL;
+               }
+       }
+       if (!bri->pins_gpio) {
+               bri->pins_gpio = pinctrl_lookup_state(p, "gpio");
+               if (IS_ERR(bri->pins_gpio))
+                       bri->pins_gpio = pinctrl_lookup_state(p, "recovery");
+
+               if (IS_ERR(bri->pins_gpio)) {
+                       dev_dbg(dev, "no gpio or recovery state found for GPIO recovery\n");
+                       bri->pins_gpio = NULL;
+               }
+       }
+
+       /* for pinctrl state changes, we need all the information */
+       if (bri->pins_default && bri->pins_gpio) {
+               dev_info(dev, "using pinctrl states for GPIO recovery");
+       } else {
+               bri->pinctrl = NULL;
+               bri->pins_default = NULL;
+               bri->pins_gpio = NULL;
+       }
+}
+
+static int i2c_gpio_init_generic_recovery(struct i2c_adapter *adap)
+{
+       struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
+       struct device *dev = &adap->dev;
+       struct gpio_desc *gpiod;
+       int ret = 0;
+
+       /*
+        * don't touch the recovery information if the driver is not using
+        * generic SCL recovery
+        */
+       if (bri->recover_bus && bri->recover_bus != i2c_generic_scl_recovery)
+               return 0;
+
+       /*
+        * pins might be taken as GPIO, so we should inform pinctrl about
+        * this and move the state to GPIO
+        */
+       if (bri->pinctrl)
+               pinctrl_select_state(bri->pinctrl, bri->pins_gpio);
+
+       /*
+        * if there is incomplete or no recovery information, see if generic
+        * GPIO recovery is available
+        */
+       if (!bri->scl_gpiod) {
+               gpiod = devm_gpiod_get(dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
+               if (PTR_ERR(gpiod) == -EPROBE_DEFER) {
+                       ret  = -EPROBE_DEFER;
+                       goto cleanup_pinctrl_state;
+               }
+               if (!IS_ERR(gpiod)) {
+                       bri->scl_gpiod = gpiod;
+                       bri->recover_bus = i2c_generic_scl_recovery;
+                       dev_info(dev, "using generic GPIOs for recovery\n");
+               }
+       }
+
+       /* SDA GPIOD line is optional, so we care about DEFER only */
+       if (!bri->sda_gpiod) {
+               /*
+                * We have SCL. Pull SCL low and wait a bit so that SDA glitches
+                * have no effect.
+                */
+               gpiod_direction_output(bri->scl_gpiod, 0);
+               udelay(10);
+               gpiod = devm_gpiod_get(dev, "sda", GPIOD_IN);
+
+               /* Wait a bit in case of a SDA glitch, and then release SCL. */
+               udelay(10);
+               gpiod_direction_output(bri->scl_gpiod, 1);
+
+               if (PTR_ERR(gpiod) == -EPROBE_DEFER) {
+                       ret = -EPROBE_DEFER;
+                       goto cleanup_pinctrl_state;
+               }
+               if (!IS_ERR(gpiod))
+                       bri->sda_gpiod = gpiod;
+       }
+
+cleanup_pinctrl_state:
+       /* change the state of the pins back to their default state */
+       if (bri->pinctrl)
+               pinctrl_select_state(bri->pinctrl, bri->pins_default);
+
+       return ret;
+}
+
+static int i2c_gpio_init_recovery(struct i2c_adapter *adap)
+{
+       i2c_gpio_init_pinctrl_recovery(adap);
+       return i2c_gpio_init_generic_recovery(adap);
+}
+
+static int i2c_init_recovery(struct i2c_adapter *adap)
 {
        struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
        char *err_str;
 
        if (!bri)
-               return;
+               return 0;
+
+       if (i2c_gpio_init_recovery(adap) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
 
        if (!bri->recover_bus) {
                err_str = "no recover_bus() found";
@@ -273,10 +400,7 @@ static void i2c_init_recovery(struct i2c_adapter *adap)
                        if (gpiod_get_direction(bri->sda_gpiod) == 0)
                                bri->set_sda = set_sda_gpio_value;
                }
-               return;
-       }
-
-       if (bri->recover_bus == i2c_generic_scl_recovery) {
+       } else if (bri->recover_bus == i2c_generic_scl_recovery) {
                /* Generic SCL recovery */
                if (!bri->set_scl || !bri->get_scl) {
                        err_str = "no {get|set}_scl() found";
@@ -288,10 +412,12 @@ static void i2c_init_recovery(struct i2c_adapter *adap)
                }
        }
 
-       return;
+       return 0;
  err:
        dev_err(&adap->dev, "Not using recovery: %s\n", err_str);
        adap->bus_recovery_info = NULL;
+
+       return -EINVAL;
 }
 
 static int i2c_smbus_host_notify_to_irq(const struct i2c_client *client)
@@ -319,11 +445,9 @@ static int i2c_device_probe(struct device *dev)
        if (!client)
                return 0;
 
-       driver = to_i2c_driver(dev->driver);
-
        client->irq = client->init_irq;
 
-       if (!client->irq && !driver->disable_i2c_core_irq_mapping) {
+       if (!client->irq) {
                int irq = -ENOENT;
 
                if (client->flags & I2C_CLIENT_HOST_NOTIFY) {
@@ -349,12 +473,14 @@ static int i2c_device_probe(struct device *dev)
                client->irq = irq;
        }
 
+       driver = to_i2c_driver(dev->driver);
+
        /*
         * An I2C ID table is not mandatory, if and only if, a suitable OF
         * or ACPI ID table is supplied for the probing device.
         */
        if (!driver->id_table &&
-           !i2c_acpi_match_device(dev->driver->acpi_match_table, client) &&
+           !acpi_driver_match_device(dev, dev->driver) &&
            !i2c_of_match_device(dev->driver->of_match_table, client)) {
                status = -ENODEV;
                goto put_sync_adapter;
@@ -1227,7 +1353,7 @@ static int i2c_setup_host_notify_irq_domain(struct i2c_adapter *adap)
        if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_HOST_NOTIFY))
                return 0;
 
-       domain = irq_domain_create_linear(adap->dev.fwnode,
+       domain = irq_domain_create_linear(adap->dev.parent->fwnode,
                                          I2C_ADDR_7BITS_COUNT,
                                          &i2c_host_notify_irq_ops, adap);
        if (!domain)
@@ -1318,12 +1444,16 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
        if (res)
                goto out_reg;
 
-       dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
-
        pm_runtime_no_callbacks(&adap->dev);
        pm_suspend_ignore_children(&adap->dev, true);
        pm_runtime_enable(&adap->dev);
 
+       res = i2c_init_recovery(adap);
+       if (res == -EPROBE_DEFER)
+               goto out_reg;
+
+       dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
+
 #ifdef CONFIG_I2C_COMPAT
        res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
                                       adap->dev.parent);
@@ -1332,8 +1462,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
                         "Failed to create compatibility class link\n");
 #endif
 
-       i2c_init_recovery(adap);
-
        /* create pre-declared device nodes */
        of_i2c_register_devices(adap);
        i2c_acpi_register_devices(adap);