Commit e23efa31 authored by Phil Reid's avatar Phil Reid Committed by Linus Walleij

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: default avatarPhil Reid <preid@electromag.com.au>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 65053e1a
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/regulator/consumer.h>
#define PCA953X_INPUT 0 #define PCA953X_INPUT 0
#define PCA953X_OUTPUT 1 #define PCA953X_OUTPUT 1
...@@ -113,6 +114,7 @@ struct pca953x_chip { ...@@ -113,6 +114,7 @@ struct pca953x_chip {
const char *const *names; const char *const *names;
int chip_type; int chip_type;
unsigned long driver_data; unsigned long driver_data;
struct regulator *regulator;
}; };
static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val, 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, ...@@ -746,6 +748,7 @@ static int pca953x_probe(struct i2c_client *client,
int irq_base = 0; int irq_base = 0;
int ret; int ret;
u32 invert = 0; u32 invert = 0;
struct regulator *reg;
chip = devm_kzalloc(&client->dev, chip = devm_kzalloc(&client->dev,
sizeof(struct pca953x_chip), GFP_KERNEL); sizeof(struct pca953x_chip), GFP_KERNEL);
...@@ -765,6 +768,20 @@ static int pca953x_probe(struct i2c_client *client, ...@@ -765,6 +768,20 @@ static int pca953x_probe(struct i2c_client *client,
chip->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) { if (id) {
chip->driver_data = id->driver_data; chip->driver_data = id->driver_data;
} else { } else {
...@@ -776,8 +793,10 @@ static int pca953x_probe(struct i2c_client *client, ...@@ -776,8 +793,10 @@ static int pca953x_probe(struct i2c_client *client,
chip->driver_data = (int)(uintptr_t)match->data; chip->driver_data = (int)(uintptr_t)match->data;
} else { } else {
id = acpi_match_device(pca953x_acpi_ids, &client->dev); id = acpi_match_device(pca953x_acpi_ids, &client->dev);
if (!id) if (!id) {
return -ENODEV; ret = -ENODEV;
goto err_exit;
}
chip->driver_data = id->driver_data; chip->driver_data = id->driver_data;
} }
...@@ -797,15 +816,15 @@ static int pca953x_probe(struct i2c_client *client, ...@@ -797,15 +816,15 @@ static int pca953x_probe(struct i2c_client *client,
else else
ret = device_pca957x_init(chip, invert); ret = device_pca957x_init(chip, invert);
if (ret) if (ret)
return ret; goto err_exit;
ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip); ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
if (ret) if (ret)
return ret; goto err_exit;
ret = pca953x_irq_setup(chip, irq_base); ret = pca953x_irq_setup(chip, irq_base);
if (ret) if (ret)
return ret; goto err_exit;
if (pdata && pdata->setup) { if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base, ret = pdata->setup(client, chip->gpio_chip.base,
...@@ -816,6 +835,10 @@ static int pca953x_probe(struct i2c_client *client, ...@@ -816,6 +835,10 @@ static int pca953x_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip); i2c_set_clientdata(client, chip);
return 0; return 0;
err_exit:
regulator_disable(chip->regulator);
return ret;
} }
static int pca953x_remove(struct i2c_client *client) static int pca953x_remove(struct i2c_client *client)
...@@ -827,14 +850,14 @@ static int pca953x_remove(struct i2c_client *client) ...@@ -827,14 +850,14 @@ static int pca953x_remove(struct i2c_client *client)
if (pdata && pdata->teardown) { if (pdata && pdata->teardown) {
ret = pdata->teardown(client, chip->gpio_chip.base, ret = pdata->teardown(client, chip->gpio_chip.base,
chip->gpio_chip.ngpio, pdata->context); chip->gpio_chip.ngpio, pdata->context);
if (ret < 0) { if (ret < 0)
dev_err(&client->dev, "%s failed, %d\n", dev_err(&client->dev, "%s failed, %d\n",
"teardown", ret); "teardown", ret);
return ret;
}
} }
return 0; regulator_disable(chip->regulator);
return ret;
} }
/* convenience to stop overlong match-table lines */ /* convenience to stop overlong match-table lines */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment