diff options
author | Brian Masney <masneyb@onstation.org> | 2018-08-03 03:18:56 +0300 |
---|---|---|
committer | Jonathan Cameron <Jonathan.Cameron@huawei.com> | 2018-08-19 14:06:58 +0300 |
commit | 7c14947e4d3d8585cc047b132cd1a4ac3167928c (patch) | |
tree | 7dd5b13d88db6fb79d3d497bebeb691f3448e232 /drivers/iio/light | |
parent | 75de3b570b1c80f185df5289cb781e453fd64502 (diff) | |
download | linux-7c14947e4d3d8585cc047b132cd1a4ac3167928c.tar.xz |
iio: tsl2772: add support for regulator framework
This patch adds support for the regulator framework to the tsl2772
driver. Driver was tested using a LG Nexus 5 (hammerhead) phone with
the two regulators and on a Raspberry Pi 2 without any regulators
controlling the power to the sensor.
Signed-off-by: Brian Masney <masneyb@onstation.org>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Diffstat (limited to 'drivers/iio/light')
-rw-r--r-- | drivers/iio/light/tsl2772.c | 95 |
1 files changed, 94 insertions, 1 deletions
diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index 66dc3254cd9a..83cece921843 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -20,6 +20,7 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/platform_data/tsl2772.h> +#include <linux/regulator/consumer.h> /* Cal defs */ #define PROX_STAT_CAL 0 @@ -109,6 +110,9 @@ #define TSL2772_MAX_PROX_LEDS 2 +#define TSL2772_BOOT_MIN_SLEEP_TIME 10000 +#define TSL2772_BOOT_MAX_SLEEP_TIME 28000 + /* Device family members */ enum { tsl2571, @@ -157,6 +161,8 @@ struct tsl2772_chip { struct mutex prox_mutex; struct mutex als_mutex; struct i2c_client *client; + struct regulator *vdd_supply; + struct regulator *vddio_supply; u16 prox_data; struct tsl2772_als_info als_cur_info; struct tsl2772_settings settings; @@ -687,6 +693,52 @@ static int tsl2772_als_calibrate(struct iio_dev *indio_dev) return ret; } +static void tsl2772_disable_regulators_action(void *_data) +{ + struct tsl2772_chip *chip = _data; + + regulator_disable(chip->vdd_supply); + regulator_disable(chip->vddio_supply); +} + +static int tsl2772_enable_regulator(struct tsl2772_chip *chip, + struct regulator *regulator) +{ + int ret; + + ret = regulator_enable(regulator); + if (ret < 0) { + dev_err(&chip->client->dev, "Failed to enable regulator: %d\n", + ret); + return ret; + } + + return 0; +} + +static struct regulator *tsl2772_get_regulator(struct tsl2772_chip *chip, + char *name) +{ + struct regulator *regulator; + int ret; + + regulator = devm_regulator_get(&chip->client->dev, name); + if (IS_ERR(regulator)) { + if (PTR_ERR(regulator) != -EPROBE_DEFER) + dev_err(&chip->client->dev, + "Failed to get %s regulator %d\n", + name, (int)PTR_ERR(regulator)); + + return regulator; + } + + ret = tsl2772_enable_regulator(chip, regulator); + if (ret < 0) + return ERR_PTR(ret); + + return regulator; +} + static int tsl2772_chip_on(struct iio_dev *indio_dev) { struct tsl2772_chip *chip = iio_priv(indio_dev); @@ -1745,6 +1797,27 @@ static int tsl2772_probe(struct i2c_client *clientp, chip->client = clientp; i2c_set_clientdata(clientp, indio_dev); + chip->vddio_supply = tsl2772_get_regulator(chip, "vddio"); + if (IS_ERR(chip->vddio_supply)) + return PTR_ERR(chip->vddio_supply); + + chip->vdd_supply = tsl2772_get_regulator(chip, "vdd"); + if (IS_ERR(chip->vdd_supply)) { + regulator_disable(chip->vddio_supply); + return PTR_ERR(chip->vdd_supply); + } + + ret = devm_add_action(&clientp->dev, tsl2772_disable_regulators_action, + chip); + if (ret < 0) { + tsl2772_disable_regulators_action(chip); + dev_err(&clientp->dev, "Failed to setup regulator cleanup action %d\n", + ret); + return ret; + } + + usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME); + ret = i2c_smbus_read_byte_data(chip->client, TSL2772_CMD_REG | TSL2772_CHIPID); if (ret < 0) @@ -1818,13 +1891,33 @@ static int tsl2772_probe(struct i2c_client *clientp, static int tsl2772_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2772_chip *chip = iio_priv(indio_dev); + int ret; - return tsl2772_chip_off(indio_dev); + ret = tsl2772_chip_off(indio_dev); + regulator_disable(chip->vdd_supply); + regulator_disable(chip->vddio_supply); + + return ret; } static int tsl2772_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2772_chip *chip = iio_priv(indio_dev); + int ret; + + ret = tsl2772_enable_regulator(chip, chip->vddio_supply); + if (ret < 0) + return ret; + + ret = tsl2772_enable_regulator(chip, chip->vdd_supply); + if (ret < 0) { + regulator_disable(chip->vddio_supply); + return ret; + } + + usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME); return tsl2772_chip_on(indio_dev); } |