diff options
Diffstat (limited to 'drivers/iio/temperature/mlx90632.c')
-rw-r--r-- | drivers/iio/temperature/mlx90632.c | 65 |
1 files changed, 57 insertions, 8 deletions
diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index 7ee7ff8047a4..f6dec0e5f097 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -18,6 +18,7 @@ #include <linux/math64.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -128,6 +129,7 @@ * calculations * @object_ambient_temperature: Ambient temperature at object (might differ of * the ambient temperature of sensor. + * @regulator: Regulator of the device */ struct mlx90632_data { struct i2c_client *client; @@ -136,6 +138,7 @@ struct mlx90632_data { u16 emissivity; u8 mtyp; u32 object_ambient_temperature; + struct regulator *regulator; }; static const struct regmap_range mlx90632_volatile_reg_range[] = { @@ -208,6 +211,15 @@ static s32 mlx90632_pwr_continuous(struct regmap *regmap) } /** + * mlx90632_reset_delay() - Give the mlx90632 some time to reset properly + * If this is not done, the following I2C command(s) will not be accepted. + */ +static void mlx90632_reset_delay(void) +{ + usleep_range(150, 200); +} + +/** * mlx90632_perform_measurement() - Trigger and retrieve current measurement cycle * @data: pointer to mlx90632_data object containing regmap information * @@ -248,11 +260,7 @@ static int mlx90632_set_meas_type(struct regmap *regmap, u8 type) if (ret < 0) return ret; - /* - * Give the mlx90632 some time to reset properly before sending a new I2C command - * if this is not done, the following I2C command(s) will not be accepted. - */ - usleep_range(150, 200); + mlx90632_reset_delay(); ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL, (MLX90632_CFG_MTYP_MASK | MLX90632_CFG_PWR_MASK), @@ -841,6 +849,32 @@ static int mlx90632_wakeup(struct mlx90632_data *data) return mlx90632_pwr_continuous(data->regmap); } +static void mlx90632_disable_regulator(void *_data) +{ + struct mlx90632_data *data = _data; + int ret; + + ret = regulator_disable(data->regulator); + if (ret < 0) + dev_err(regmap_get_device(data->regmap), + "Failed to disable power regulator: %d\n", ret); +} + +static int mlx90632_enable_regulator(struct mlx90632_data *data) +{ + int ret; + + ret = regulator_enable(data->regulator); + if (ret < 0) { + dev_err(regmap_get_device(data->regmap), "Failed to enable power regulator!\n"); + return ret; + } + + mlx90632_reset_delay(); + + return ret; +} + static int mlx90632_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -876,6 +910,23 @@ static int mlx90632_probe(struct i2c_client *client, indio_dev->channels = mlx90632_channels; indio_dev->num_channels = ARRAY_SIZE(mlx90632_channels); + mlx90632->regulator = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(mlx90632->regulator)) + return dev_err_probe(&client->dev, PTR_ERR(mlx90632->regulator), + "failed to get vdd regulator"); + + ret = mlx90632_enable_regulator(mlx90632); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(&client->dev, mlx90632_disable_regulator, + mlx90632); + if (ret < 0) { + dev_err(&client->dev, "Failed to setup regulator cleanup action %d\n", + ret); + return ret; + } + ret = mlx90632_wakeup(mlx90632); if (ret < 0) { dev_err(&client->dev, "Wakeup failed: %d\n", ret); @@ -924,7 +975,7 @@ static int mlx90632_probe(struct i2c_client *client, return iio_device_register(indio_dev); } -static int mlx90632_remove(struct i2c_client *client) +static void mlx90632_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct mlx90632_data *data = iio_priv(indio_dev); @@ -936,8 +987,6 @@ static int mlx90632_remove(struct i2c_client *client) pm_runtime_put_noidle(&client->dev); mlx90632_sleep(data); - - return 0; } static const struct i2c_device_id mlx90632_id[] = { |