diff options
author | Phil Reid <preid@electromag.com.au> | 2016-07-29 11:39:55 +0800 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2016-08-11 10:13:57 +0200 |
commit | e23efa311110648d58268c9b83b21de9d990a78c (patch) | |
tree | 52a88638b8f32c6a88e4e5f3eaba6cc52949a498 /drivers/gpio | |
parent | 65053e1a7743e282c3dd08d3d435ac8b746f5359 (diff) | |
download | linux-e23efa311110648d58268c9b83b21de9d990a78c.tar.bz2 |
gpio: pca954x: Add vcc regulator and enable it
Some i2c gpio devices are connected to a switchable power supply
which needs to be enabled prior to probing the device. This patch
allows the drive to enable the devices vcc regulator prior to probing.
Signed-off-by: Phil Reid <preid@electromag.com.au>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpio-pca953x.c | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 02f2a5621bb0..cbe2824461eb 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -21,6 +21,7 @@ #include <asm/unaligned.h> #include <linux/of_platform.h> #include <linux/acpi.h> +#include <linux/regulator/consumer.h> #define PCA953X_INPUT 0 #define PCA953X_OUTPUT 1 @@ -113,6 +114,7 @@ struct pca953x_chip { const char *const *names; int chip_type; unsigned long driver_data; + struct regulator *regulator; }; static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val, @@ -746,6 +748,7 @@ static int pca953x_probe(struct i2c_client *client, int irq_base = 0; int ret; u32 invert = 0; + struct regulator *reg; chip = devm_kzalloc(&client->dev, sizeof(struct pca953x_chip), GFP_KERNEL); @@ -765,6 +768,20 @@ static int pca953x_probe(struct i2c_client *client, chip->client = client; + reg = devm_regulator_get(&client->dev, "vcc"); + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + if (ret != -EPROBE_DEFER) + dev_err(&client->dev, "reg get err: %d\n", ret); + return ret; + } + ret = regulator_enable(reg); + if (ret) { + dev_err(&client->dev, "reg en err: %d\n", ret); + return ret; + } + chip->regulator = reg; + if (id) { chip->driver_data = id->driver_data; } else { @@ -776,8 +793,10 @@ static int pca953x_probe(struct i2c_client *client, chip->driver_data = (int)(uintptr_t)match->data; } else { id = acpi_match_device(pca953x_acpi_ids, &client->dev); - if (!id) - return -ENODEV; + if (!id) { + ret = -ENODEV; + goto err_exit; + } chip->driver_data = id->driver_data; } @@ -797,15 +816,15 @@ static int pca953x_probe(struct i2c_client *client, else ret = device_pca957x_init(chip, invert); if (ret) - return ret; + goto err_exit; ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip); if (ret) - return ret; + goto err_exit; ret = pca953x_irq_setup(chip, irq_base); if (ret) - return ret; + goto err_exit; if (pdata && pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, @@ -816,6 +835,10 @@ static int pca953x_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); return 0; + +err_exit: + regulator_disable(chip->regulator); + return ret; } static int pca953x_remove(struct i2c_client *client) @@ -827,14 +850,14 @@ static int pca953x_remove(struct i2c_client *client) if (pdata && pdata->teardown) { ret = pdata->teardown(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); - if (ret < 0) { + if (ret < 0) dev_err(&client->dev, "%s failed, %d\n", "teardown", ret); - return ret; - } } - return 0; + regulator_disable(chip->regulator); + + return ret; } /* convenience to stop overlong match-table lines */ |