gpio: pca953x: add regulator control
Daniel Fu [Fri, 3 Jul 2015 14:59:38 +0000 (07:59 -0700)]
Bug 1654140

Change-Id: Icf5f670a61a10fcff70ac87d616e0ca9f2fe2cdc
Signed-off-by: Daniel Fu <danifu@nvidia.com>
Reviewed-on: http://git-master/r/766321
(cherry picked from commit 6ef9ea80f06d364016d14ca38e533d1ae63c4503)
Reviewed-on: http://git-master/r/831667
GVS: Gerrit_Virtual_Submit
Reviewed-by: Kerwin Wan <kerwinw@nvidia.com>
Tested-by: Kerwin Wan <kerwinw@nvidia.com>

drivers/gpio/gpio-pca953x.c

index 310a91e..a16fc32 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c/pca953x.h>
 #include <linux/slab.h>
+#include <linux/regulator/consumer.h>
 #ifdef CONFIG_OF_GPIO
 #include <linux/of_platform.h>
 #endif
@@ -93,7 +94,7 @@ struct pca953x_chip {
        u8 irq_trig_fall[MAX_BANK];
        struct irq_domain *domain;
 #endif
-
+       struct regulator *vcc_reg;
        struct i2c_client *client;
        struct gpio_chip gpio_chip;
        const char *const *names;
@@ -756,27 +757,45 @@ static int pca953x_probe(struct i2c_client *client,
 
        chip->chip_type = id->driver_data & (PCA953X_TYPE | PCA957X_TYPE);
 
+       chip->vcc_reg = devm_regulator_get(&client->dev, "vcc");
+       if (PTR_ERR(chip->vcc_reg) == -ENODEV) {
+               dev_info(&client->dev, "no regulator found for vcc."
+                       " Assuming vcc is always powered");
+               chip->vcc_reg = NULL;
+       } else if (IS_ERR(chip->vcc_reg)) {
+               ret = PTR_ERR(chip->vcc_reg);
+               dev_err(&client->dev, "vcc regualtor get failed, err %ld\n", ret);
+               return ret;
+       }
+
+       if (chip->vcc_reg) {
+               ret = regulator_enable(chip->vcc_reg);
+               if (ret < 0) {
+                       dev_err(&client->dev, "failed to enable vcc\n");
+                       return ret;
+               }
+       }
+
        mutex_init(&chip->i2c_lock);
 
        /* initialize cached registers from their original values.
         * we can't share this chip with another i2c master.
         */
        pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK);
-
        if (chip->chip_type == PCA953X_TYPE)
                ret = device_pca953x_init(chip, invert);
        else
                ret = device_pca957x_init(chip, invert);
        if (ret)
-               return ret;
+               goto fail;
 
        ret = pca953x_irq_setup(chip, id, irq_base);
        if (ret)
-               return ret;
+               goto fail;
 
        ret = gpiochip_add(&chip->gpio_chip);
        if (ret)
-               return ret;
+               goto fail;
 
        if (pdata && pdata->setup) {
                ret = pdata->setup(client, chip->gpio_chip.base,
@@ -787,6 +806,12 @@ static int pca953x_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, chip);
        return 0;
+
+fail:
+       if (chip->vcc_reg)
+               regulator_disable(chip->vcc_reg);
+
+       return ret;
 }
 
 static int pca953x_remove(struct i2c_client *client)
@@ -805,6 +830,9 @@ static int pca953x_remove(struct i2c_client *client)
                }
        }
 
+       if (chip->vcc_reg)
+               regulator_disable(chip->vcc_reg);
+
        ret = gpiochip_remove(&chip->gpio_chip);
        if (ret) {
                dev_err(&client->dev, "%s failed, %d\n",
@@ -855,13 +883,26 @@ MODULE_DEVICE_TABLE(of, pca953x_dt_ids);
 #ifdef CONFIG_PM
 static int pca953x_suspend(struct device *dev)
 {
-       /* we do know our state already, so nothing to save */
+       struct pca953x_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
+
+       if (chip->vcc_reg)
+               regulator_disable(chip->vcc_reg);
        return 0;
 }
 
 static int pca953x_resume(struct device *dev)
 {
-       struct pca953x_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pca953x_chip *chip = i2c_get_clientdata(client);
+       int ret = 0;
+
+       if (chip->vcc_reg) {
+               ret = regulator_enable(chip->vcc_reg);
+               if (ret < 0) {
+                       dev_err(&client->dev, "failed to enable vcc\n");
+                       return ret;
+               }
+       }
 
        switch (chip->chip_type) {
        case PCA953X_TYPE: