diff options
Diffstat (limited to 'drivers/iio/light')
30 files changed, 592 insertions, 81 deletions
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 8537e88f02e3..7cf6e8490123 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -331,6 +331,17 @@ config LTR501 This driver can also be built as a module. If so, the module will be called ltr501. +config LTRF216A + tristate "Liteon LTRF216A Light Sensor" + depends on I2C + select REGMAP_I2C + help + If you say Y or M here, you get support for Liteon LTRF216A + Ambient Light Sensor. + + If built as a dynamically linked module, it will be called + ltrf216a. + config LV0104CS tristate "LV0104CS Ambient Light Sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index d10912faf964..6f23817fae6f 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_ISL29125) += isl29125.o obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_LTR501) += ltr501.o +obj-$(CONFIG_LTRF216A) += ltrf216a.o obj-$(CONFIG_LV0104CS) += lv0104cs.o obj-$(CONFIG_MAX44000) += max44000.o obj-$(CONFIG_MAX44009) += max44009.o diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 0f9d77598997..b70f2681bcb3 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -452,7 +452,7 @@ err: return ret; } -static int apds9300_remove(struct i2c_client *client) +static void apds9300_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct apds9300_data *data = iio_priv(indio_dev); @@ -462,8 +462,6 @@ static int apds9300_remove(struct i2c_client *client) /* Ensure that power off and interrupts are disabled */ apds9300_set_intr_state(data, 0); apds9300_set_power_state(data, 0); - - return 0; } static int apds9300_suspend(struct device *dev) diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 09b831f9f40b..b62c139baf41 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -1067,7 +1067,7 @@ error_power_down: return ret; } -static int apds9960_remove(struct i2c_client *client) +static void apds9960_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct apds9960_data *data = iio_priv(indio_dev); @@ -1076,8 +1076,6 @@ static int apds9960_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); apds9960_set_powermode(data, 0); - - return 0; } #ifdef CONFIG_PM diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c index 471985c220bb..3e92820bc820 100644 --- a/drivers/iio/light/bh1750.c +++ b/drivers/iio/light/bh1750.c @@ -263,7 +263,7 @@ static int bh1750_probe(struct i2c_client *client, return iio_device_register(indio_dev); } -static int bh1750_remove(struct i2c_client *client) +static void bh1750_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct bh1750_data *data = iio_priv(indio_dev); @@ -273,8 +273,6 @@ static int bh1750_remove(struct i2c_client *client) mutex_lock(&data->lock); i2c_smbus_write_byte(client, BH1750_POWER_DOWN); mutex_unlock(&data->lock); - - return 0; } static int bh1750_suspend(struct device *dev) diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index fc7141390117..90bca392b262 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -202,7 +202,7 @@ out_disable_pm: return ret; } -static int bh1780_remove(struct i2c_client *client) +static void bh1780_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct bh1780_data *bh1780 = iio_priv(indio_dev); @@ -216,8 +216,6 @@ static int bh1780_remove(struct i2c_client *client) if (ret < 0) dev_err(&client->dev, "failed to power off (%pe)\n", ERR_PTR(ret)); - - return 0; } static int bh1780_runtime_suspend(struct device *dev) diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 2c80a0535d2c..5214cd014cf8 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -357,7 +357,7 @@ static int cm3232_probe(struct i2c_client *client, return iio_device_register(indio_dev); } -static int cm3232_remove(struct i2c_client *client) +static void cm3232_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); @@ -365,8 +365,6 @@ static int cm3232_remove(struct i2c_client *client) CM3232_CMD_ALS_DISABLE); iio_device_unregister(indio_dev); - - return 0; } static const struct i2c_device_id cm3232_id[] = { diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 89f5e48a6642..6615c98b601c 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -700,7 +700,7 @@ error_disable_reg: return ret; } -static int cm36651_remove(struct i2c_client *client) +static void cm36651_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct cm36651_data *cm36651 = iio_priv(indio_dev); @@ -710,8 +710,6 @@ static int cm36651_remove(struct i2c_client *client) free_irq(client->irq, indio_dev); i2c_unregister_device(cm36651->ps_client); i2c_unregister_device(cm36651->ara_client); - - return 0; } static const struct i2c_device_id cm36651_id[] = { diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c index e2707416f9a8..8000fa347344 100644 --- a/drivers/iio/light/gp2ap002.c +++ b/drivers/iio/light/gp2ap002.c @@ -619,7 +619,7 @@ out_disable_vdd: return ret; } -static int gp2ap002_remove(struct i2c_client *client) +static void gp2ap002_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct gp2ap002 *gp2ap002 = iio_priv(indio_dev); @@ -631,8 +631,6 @@ static int gp2ap002_remove(struct i2c_client *client) iio_device_unregister(indio_dev); regulator_disable(gp2ap002->vio); regulator_disable(gp2ap002->vdd); - - return 0; } static int gp2ap002_runtime_suspend(struct device *dev) diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index b820041159f7..826439299e8b 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1573,7 +1573,7 @@ error_regulator_disable: return err; } -static int gp2ap020a00f_remove(struct i2c_client *client) +static void gp2ap020a00f_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct gp2ap020a00f_data *data = iio_priv(indio_dev); @@ -1589,8 +1589,6 @@ static int gp2ap020a00f_remove(struct i2c_client *client) free_irq(client->irq, indio_dev); iio_triggered_buffer_cleanup(indio_dev); regulator_disable(data->vled_reg); - - return 0; } static const struct i2c_device_id gp2ap020a00f_id[] = { diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c index ff5996d77818..32d58e18f26d 100644 --- a/drivers/iio/light/isl29028.c +++ b/drivers/iio/light/isl29028.c @@ -636,7 +636,7 @@ static int isl29028_probe(struct i2c_client *client, return 0; } -static int isl29028_remove(struct i2c_client *client) +static void isl29028_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct isl29028_chip *chip = iio_priv(indio_dev); @@ -647,8 +647,6 @@ static int isl29028_remove(struct i2c_client *client) pm_runtime_set_suspended(&client->dev); isl29028_clear_configure_reg(chip); - - return 0; } static int isl29028_suspend(struct device *dev) diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index eb68a52aab82..c199e63cce82 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -300,15 +300,13 @@ static int isl29125_powerdown(struct isl29125_data *data) (data->conf1 & ~ISL29125_MODE_MASK) | ISL29125_MODE_PD); } -static int isl29125_remove(struct i2c_client *client) +static void isl29125_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); isl29125_powerdown(iio_priv(indio_dev)); - - return 0; } static int isl29125_suspend(struct device *dev) diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index 5387c12231cf..57ce6d75966c 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -373,7 +373,7 @@ static int jsa1212_power_off(struct jsa1212_data *data) return ret; } -static int jsa1212_remove(struct i2c_client *client) +static void jsa1212_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct jsa1212_data *data = iio_priv(indio_dev); @@ -381,8 +381,6 @@ static int jsa1212_remove(struct i2c_client *client) iio_device_unregister(indio_dev); jsa1212_power_off(data); - - return 0; } static int jsa1212_suspend(struct device *dev) diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 679a1e1086ae..74a1ccda8b9c 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -1600,15 +1600,13 @@ powerdown_on_error: return ret; } -static int ltr501_remove(struct i2c_client *client) +static void ltr501_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); ltr501_powerdown(iio_priv(indio_dev)); - - return 0; } static int ltr501_suspend(struct device *dev) diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c new file mode 100644 index 000000000000..4b8ef36b6912 --- /dev/null +++ b/drivers/iio/light/ltrf216a.c @@ -0,0 +1,550 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * LTRF216A Ambient Light Sensor + * + * Copyright (C) 2022 Collabora, Ltd. + * Author: Shreeya Patel <shreeya.patel@collabora.com> + * + * Copyright (C) 2021 Lite-On Technology Corp (Singapore) + * Author: Shi Zhigang <Zhigang.Shi@liteon.com> + * + * IIO driver for LTRF216A (7-bit I2C slave address 0x53). + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/iopoll.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> + +#include <linux/iio/iio.h> + +#include <asm/unaligned.h> + +#define LTRF216A_ALS_RESET_MASK BIT(4) +#define LTRF216A_ALS_DATA_STATUS BIT(3) +#define LTRF216A_ALS_ENABLE_MASK BIT(1) +#define LTRF216A_MAIN_CTRL 0x00 +#define LTRF216A_ALS_MEAS_RES 0x04 +#define LTRF216A_ALS_GAIN 0x05 +#define LTRF216A_PART_ID 0x06 +#define LTRF216A_MAIN_STATUS 0x07 +#define LTRF216A_ALS_CLEAR_DATA_0 0x0a +#define LTRF216A_ALS_CLEAR_DATA_1 0x0b +#define LTRF216A_ALS_CLEAR_DATA_2 0x0c +#define LTRF216A_ALS_DATA_0 0x0d +#define LTRF216A_ALS_DATA_1 0x0e +#define LTRF216A_ALS_DATA_2 0x0f +#define LTRF216A_INT_CFG 0x19 +#define LTRF216A_INT_PST 0x1a +#define LTRF216A_ALS_THRES_UP_0 0x21 +#define LTRF216A_ALS_THRES_UP_1 0x22 +#define LTRF216A_ALS_THRES_UP_2 0x23 +#define LTRF216A_ALS_THRES_LOW_0 0x24 +#define LTRF216A_ALS_THRES_LOW_1 0x25 +#define LTRF216A_ALS_THRES_LOW_2 0x26 +#define LTRF216A_ALS_READ_DATA_DELAY_US 20000 + +static const int ltrf216a_int_time_available[][2] = { + { 0, 400000 }, + { 0, 200000 }, + { 0, 100000 }, + { 0, 50000 }, + { 0, 25000 }, +}; + +static const int ltrf216a_int_time_reg[][2] = { + { 400, 0x03 }, + { 200, 0x13 }, + { 100, 0x22 }, + { 50, 0x31 }, + { 25, 0x40 }, +}; + +/* + * Window Factor is needed when the device is under Window glass + * with coated tinted ink. This is to compensate for the light loss + * due to the lower transmission rate of the window glass and helps + * in calculating lux. + */ +#define LTRF216A_WIN_FAC 1 + +struct ltrf216a_data { + struct regmap *regmap; + struct i2c_client *client; + u32 int_time; + u16 int_time_fac; + u8 als_gain_fac; + /* + * Protects regmap accesses and makes sure integration time + * remains constant during the measurement of lux. + */ + struct mutex lock; +}; + +static const struct iio_chan_spec ltrf216a_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_INT_TIME), + }, +}; + +static void ltrf216a_reset(struct iio_dev *indio_dev) +{ + struct ltrf216a_data *data = iio_priv(indio_dev); + + /* reset sensor, chip fails to respond to this, so ignore any errors */ + regmap_write(data->regmap, LTRF216A_MAIN_CTRL, LTRF216A_ALS_RESET_MASK); + + /* reset time */ + usleep_range(1000, 2000); +} + +static int ltrf216a_enable(struct iio_dev *indio_dev) +{ + struct ltrf216a_data *data = iio_priv(indio_dev); + struct device *dev = &data->client->dev; + int ret; + + /* enable sensor */ + ret = regmap_set_bits(data->regmap, + LTRF216A_MAIN_CTRL, LTRF216A_ALS_ENABLE_MASK); + if (ret) { + dev_err(dev, "failed to enable sensor: %d\n", ret); + return ret; + } + + /* sleep for one integration cycle after enabling the device */ + msleep(ltrf216a_int_time_reg[0][0]); + + return 0; +} + +static int ltrf216a_disable(struct iio_dev *indio_dev) +{ + struct ltrf216a_data *data = iio_priv(indio_dev); + struct device *dev = &data->client->dev; + int ret; + + ret = regmap_write(data->regmap, LTRF216A_MAIN_CTRL, 0); + if (ret) + dev_err(dev, "failed to disable sensor: %d\n", ret); + + return ret; +} + +static void ltrf216a_cleanup(void *data) +{ + struct iio_dev *indio_dev = data; + + ltrf216a_disable(indio_dev); +} + +static int ltrf216a_set_int_time(struct ltrf216a_data *data, int itime) +{ + struct device *dev = &data->client->dev; + unsigned int i; + u8 reg_val; + int ret; + + for (i = 0; i < ARRAY_SIZE(ltrf216a_int_time_available); i++) { + if (ltrf216a_int_time_available[i][1] == itime) + break; + } + if (i == ARRAY_SIZE(ltrf216a_int_time_available)) + return -EINVAL; + + reg_val = ltrf216a_int_time_reg[i][1]; + + ret = regmap_write(data->regmap, LTRF216A_ALS_MEAS_RES, reg_val); + if (ret) { + dev_err(dev, "failed to set integration time: %d\n", ret); + return ret; + } + + data->int_time_fac = ltrf216a_int_time_reg[i][0]; + data->int_time = itime; + + return 0; +} + +static int ltrf216a_get_int_time(struct ltrf216a_data *data, + int *val, int *val2) +{ + *val = 0; + *val2 = data->int_time; + return IIO_VAL_INT_PLUS_MICRO; +} + +static int ltrf216a_set_power_state(struct ltrf216a_data *data, bool on) +{ + struct device *dev = &data->client->dev; + int ret = 0; + + if (on) { + ret = pm_runtime_resume_and_get(dev); + if (ret) { + dev_err(dev, "failed to resume runtime PM: %d\n", ret); + return ret; + } + } else { + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + } + + return ret; +} + +static int ltrf216a_read_data(struct ltrf216a_data *data, u8 addr) +{ + struct device *dev = &data->client->dev; + int ret, val; + u8 buf[3]; + + ret = regmap_read_poll_timeout(data->regmap, LTRF216A_MAIN_STATUS, + val, val & LTRF216A_ALS_DATA_STATUS, + LTRF216A_ALS_READ_DATA_DELAY_US, + LTRF216A_ALS_READ_DATA_DELAY_US * 50); + if (ret) { + dev_err(dev, "failed to wait for measurement data: %d\n", ret); + return ret; + } + + ret = regmap_bulk_read(data->regmap, addr, buf, sizeof(buf)); + if (ret) { + dev_err(dev, "failed to read measurement data: %d\n", ret); + return ret; + } + + return get_unaligned_le24(&buf[0]); +} + +static int ltrf216a_get_lux(struct ltrf216a_data *data) +{ + int ret, greendata; + u64 lux, div; + + ret = ltrf216a_set_power_state(data, true); + if (ret) + return ret; + + greendata = ltrf216a_read_data(data, LTRF216A_ALS_DATA_0); + if (greendata < 0) + return greendata; + + ltrf216a_set_power_state(data, false); + + lux = greendata * 45 * LTRF216A_WIN_FAC * 100; + div = data->als_gain_fac * data->int_time_fac * 100; + + return div_u64(lux, div); +} + +static int ltrf216a_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct ltrf216a_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = ltrf216a_set_power_state(data, true); + if (ret) + return ret; + mutex_lock(&data->lock); + ret = ltrf216a_read_data(data, LTRF216A_ALS_DATA_0); + mutex_unlock(&data->lock); + ltrf216a_set_power_state(data, false); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_PROCESSED: + mutex_lock(&data->lock); + ret = ltrf216a_get_lux(data); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + mutex_lock(&data->lock); + ret = ltrf216a_get_int_time(data, val, val2); + mutex_unlock(&data->lock); + return ret; + default: + return -EINVAL; + } +} + +static int ltrf216a_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct ltrf216a_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + if (val != 0) + return -EINVAL; + mutex_lock(&data->lock); + ret = ltrf216a_set_int_time(data, val2); + mutex_unlock(&data->lock); + return ret; + default: + return -EINVAL; + } +} + +static int ltrf216a_read_available(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *length = ARRAY_SIZE(ltrf216a_int_time_available) * 2; + *vals = (const int *)ltrf216a_int_time_available; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static const struct iio_info ltrf216a_info = { + .read_raw = ltrf216a_read_raw, + .write_raw = ltrf216a_write_raw, + .read_avail = ltrf216a_read_available, +}; + +static bool ltrf216a_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case LTRF216A_MAIN_CTRL: + case LTRF216A_ALS_MEAS_RES: + case LTRF216A_ALS_GAIN: + case LTRF216A_PART_ID: + case LTRF216A_MAIN_STATUS: + case LTRF216A_ALS_CLEAR_DATA_0: + case LTRF216A_ALS_CLEAR_DATA_1: + case LTRF216A_ALS_CLEAR_DATA_2: + case LTRF216A_ALS_DATA_0: + case LTRF216A_ALS_DATA_1: + case LTRF216A_ALS_DATA_2: + case LTRF216A_INT_CFG: + case LTRF216A_INT_PST: + case LTRF216A_ALS_THRES_UP_0: + case LTRF216A_ALS_THRES_UP_1: + case LTRF216A_ALS_THRES_UP_2: + case LTRF216A_ALS_THRES_LOW_0: + case LTRF216A_ALS_THRES_LOW_1: + case LTRF216A_ALS_THRES_LOW_2: + return true; + default: + return false; + } +} + +static bool ltrf216a_writable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case LTRF216A_MAIN_CTRL: + case LTRF216A_ALS_MEAS_RES: + case LTRF216A_ALS_GAIN: + case LTRF216A_INT_CFG: + case LTRF216A_INT_PST: + case LTRF216A_ALS_THRES_UP_0: + case LTRF216A_ALS_THRES_UP_1: + case LTRF216A_ALS_THRES_UP_2: + case LTRF216A_ALS_THRES_LOW_0: + case LTRF216A_ALS_THRES_LOW_1: + case LTRF216A_ALS_THRES_LOW_2: + return true; + default: + return false; + } +} + +static bool ltrf216a_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case LTRF216A_MAIN_STATUS: + case LTRF216A_ALS_CLEAR_DATA_0: + case LTRF216A_ALS_CLEAR_DATA_1: + case LTRF216A_ALS_CLEAR_DATA_2: + case LTRF216A_ALS_DATA_0: + case LTRF216A_ALS_DATA_1: + case LTRF216A_ALS_DATA_2: + return true; + default: + return false; + } +} + +static bool ltrf216a_precious_reg(struct device *dev, unsigned int reg) +{ + return reg == LTRF216A_MAIN_STATUS; +} + +static const struct regmap_config ltrf216a_regmap_config = { + .name = "ltrf216a", + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .max_register = LTRF216A_ALS_THRES_LOW_2, + .readable_reg = ltrf216a_readable_reg, + .writeable_reg = ltrf216a_writable_reg, + .volatile_reg = ltrf216a_volatile_reg, + .precious_reg = ltrf216a_precious_reg, + .disable_locking = true, +}; + +static int ltrf216a_probe(struct i2c_client *client) +{ + struct ltrf216a_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + + data->regmap = devm_regmap_init_i2c(client, <rf216a_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(&client->dev, PTR_ERR(data->regmap), + "regmap initialization failed\n"); + + i2c_set_clientdata(client, indio_dev); + data->client = client; + + mutex_init(&data->lock); + + indio_dev->info = <rf216a_info; + indio_dev->name = "ltrf216a"; + indio_dev->channels = ltrf216a_channels; + indio_dev->num_channels = ARRAY_SIZE(ltrf216a_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = pm_runtime_set_active(&client->dev); + if (ret) + return ret; + + /* reset sensor, chip fails to respond to this, so ignore any errors */ + ltrf216a_reset(indio_dev); + + ret = regmap_reinit_cache(data->regmap, <rf216a_regmap_config); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to reinit regmap cache\n"); + + ret = ltrf216a_enable(indio_dev); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&client->dev, ltrf216a_cleanup, + indio_dev); + if (ret) + return ret; + + ret = devm_pm_runtime_enable(&client->dev); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to enable runtime PM\n"); + + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + + data->int_time = 100000; + data->int_time_fac = 100; + data->als_gain_fac = 3; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static int ltrf216a_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct ltrf216a_data *data = iio_priv(indio_dev); + int ret; + + ret = ltrf216a_disable(indio_dev); + if (ret) + return ret; + + regcache_cache_only(data->regmap, true); + + return 0; +} + +static int ltrf216a_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct ltrf216a_data *data = iio_priv(indio_dev); + int ret; + + regcache_cache_only(data->regmap, false); + regcache_mark_dirty(data->regmap); + ret = regcache_sync(data->regmap); + if (ret) + goto cache_only; + + ret = ltrf216a_enable(indio_dev); + if (ret) + goto cache_only; + + return 0; + +cache_only: + regcache_cache_only(data->regmap, true); + + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(ltrf216a_pm_ops, ltrf216a_runtime_suspend, + ltrf216a_runtime_resume, NULL); + +static const struct i2c_device_id ltrf216a_id[] = { + { "ltrf216a" }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ltrf216a_id); + +static const struct of_device_id ltrf216a_of_match[] = { + { .compatible = "liteon,ltrf216a" }, + { .compatible = "ltr,ltrf216a" }, + {} +}; +MODULE_DEVICE_TABLE(of, ltrf216a_of_match); + +static struct i2c_driver ltrf216a_driver = { + .driver = { + .name = "ltrf216a", + .pm = pm_ptr(<rf216a_pm_ops), + .of_match_table = ltrf216a_of_match, + }, + .probe_new = ltrf216a_probe, + .id_table = ltrf216a_id, +}; +module_i2c_driver(ltrf216a_driver); + +MODULE_AUTHOR("Shreeya Patel <shreeya.patel@collabora.com>"); +MODULE_AUTHOR("Shi Zhigang <Zhigang.Shi@liteon.com>"); +MODULE_DESCRIPTION("LTRF216A ambient light sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index a326d47afc9b..a26d1c3f9543 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -794,7 +794,7 @@ static int opt3001_probe(struct i2c_client *client, return 0; } -static int opt3001_remove(struct i2c_client *client) +static void opt3001_remove(struct i2c_client *client) { struct iio_dev *iio = i2c_get_clientdata(client); struct opt3001 *opt = iio_priv(iio); @@ -808,7 +808,7 @@ static int opt3001_remove(struct i2c_client *client) if (ret < 0) { dev_err(opt->dev, "failed to read register %02x\n", OPT3001_CONFIGURATION); - return 0; + return; } reg = ret; @@ -820,8 +820,6 @@ static int opt3001_remove(struct i2c_client *client) dev_err(opt->dev, "failed to write register %02x\n", OPT3001_CONFIGURATION); } - - return 0; } static const struct i2c_device_id opt3001_id[] = { diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c index 772874e707ae..3cb2de51f4aa 100644 --- a/drivers/iio/light/pa12203001.c +++ b/drivers/iio/light/pa12203001.c @@ -394,7 +394,7 @@ out_err: return ret; } -static int pa12203001_remove(struct i2c_client *client) +static void pa12203001_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); int ret; @@ -408,8 +408,6 @@ static int pa12203001_remove(struct i2c_client *client) if (ret) dev_warn(&client->dev, "Failed to power down (%pe)\n", ERR_PTR(ret)); - - return 0; } #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM) diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index dabdd05f0e2c..d1c16dd76058 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -1041,7 +1041,7 @@ err_poweroff: return ret; } -static int rpr0521_remove(struct i2c_client *client) +static void rpr0521_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); @@ -1051,8 +1051,6 @@ static int rpr0521_remove(struct i2c_client *client) pm_runtime_set_suspended(&client->dev); rpr0521_poweroff(iio_priv(indio_dev)); - - return 0; } static int rpr0521_runtime_suspend(struct device *dev) diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c index 3d4cc1180b6a..c737d3e193ae 100644 --- a/drivers/iio/light/st_uvis25_core.c +++ b/drivers/iio/light/st_uvis25_core.c @@ -325,7 +325,7 @@ int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap) } EXPORT_SYMBOL_NS(st_uvis25_probe, IIO_UVIS25); -static int __maybe_unused st_uvis25_suspend(struct device *dev) +static int st_uvis25_suspend(struct device *dev) { struct iio_dev *iio_dev = dev_get_drvdata(dev); struct st_uvis25_hw *hw = iio_priv(iio_dev); @@ -334,7 +334,7 @@ static int __maybe_unused st_uvis25_suspend(struct device *dev) ST_UVIS25_REG_ODR_MASK, 0); } -static int __maybe_unused st_uvis25_resume(struct device *dev) +static int st_uvis25_resume(struct device *dev) { struct iio_dev *iio_dev = dev_get_drvdata(dev); struct st_uvis25_hw *hw = iio_priv(iio_dev); @@ -346,10 +346,7 @@ static int __maybe_unused st_uvis25_resume(struct device *dev) return 0; } -const struct dev_pm_ops st_uvis25_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(st_uvis25_suspend, st_uvis25_resume) -}; -EXPORT_SYMBOL_NS(st_uvis25_pm_ops, IIO_UVIS25); +EXPORT_NS_SIMPLE_DEV_PM_OPS(st_uvis25_pm_ops, st_uvis25_suspend, st_uvis25_resume, IIO_UVIS25); MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>"); MODULE_DESCRIPTION("STMicroelectronics uvis25 sensor driver"); diff --git a/drivers/iio/light/st_uvis25_i2c.c b/drivers/iio/light/st_uvis25_i2c.c index b06d09af28a3..c982b0b255cf 100644 --- a/drivers/iio/light/st_uvis25_i2c.c +++ b/drivers/iio/light/st_uvis25_i2c.c @@ -55,7 +55,7 @@ MODULE_DEVICE_TABLE(i2c, st_uvis25_i2c_id_table); static struct i2c_driver st_uvis25_driver = { .driver = { .name = "st_uvis25_i2c", - .pm = &st_uvis25_pm_ops, + .pm = pm_sleep_ptr(&st_uvis25_pm_ops), .of_match_table = st_uvis25_i2c_of_match, }, .probe = st_uvis25_i2c_probe, diff --git a/drivers/iio/light/st_uvis25_spi.c b/drivers/iio/light/st_uvis25_spi.c index 3a4dc6d7180c..86a232320d7d 100644 --- a/drivers/iio/light/st_uvis25_spi.c +++ b/drivers/iio/light/st_uvis25_spi.c @@ -55,7 +55,7 @@ MODULE_DEVICE_TABLE(spi, st_uvis25_spi_id_table); static struct spi_driver st_uvis25_driver = { .driver = { .name = "st_uvis25_spi", - .pm = &st_uvis25_pm_ops, + .pm = pm_sleep_ptr(&st_uvis25_pm_ops), .of_match_table = st_uvis25_spi_of_match, }, .probe = st_uvis25_spi_probe, diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index f7cc7a6c0c8d..7b8e0da6aabc 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -649,14 +649,12 @@ err_standby: return ret; } -static int stk3310_remove(struct i2c_client *client) +static void stk3310_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); iio_device_unregister(indio_dev); stk3310_set_state(iio_priv(indio_dev), STK3310_STATE_STANDBY); - - return 0; } static int stk3310_suspend(struct device *dev) diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 823435f59bb6..db17fec634be 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -559,7 +559,7 @@ static int tcs3472_powerdown(struct tcs3472_data *data) return ret; } -static int tcs3472_remove(struct i2c_client *client) +static void tcs3472_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); @@ -568,8 +568,6 @@ static int tcs3472_remove(struct i2c_client *client) free_irq(client->irq, indio_dev); iio_triggered_buffer_cleanup(indio_dev); tcs3472_powerdown(iio_priv(indio_dev)); - - return 0; } static int tcs3472_suspend(struct device *dev) diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index bbb577459fb9..951f35ef3f41 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -796,7 +796,7 @@ fail: return err; } -static int tsl2563_remove(struct i2c_client *client) +static void tsl2563_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct tsl2563_chip *chip = iio_priv(indio_dev); @@ -809,8 +809,6 @@ static int tsl2563_remove(struct i2c_client *client) i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | TSL2563_REG_INT, chip->intr); tsl2563_set_power(chip, 0); - - return 0; } static int tsl2563_suspend(struct device *dev) diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c index 82662dab87c0..0a2ca1a8146d 100644 --- a/drivers/iio/light/tsl2583.c +++ b/drivers/iio/light/tsl2583.c @@ -873,7 +873,7 @@ static int tsl2583_probe(struct i2c_client *clientp, return 0; } -static int tsl2583_remove(struct i2c_client *client) +static void tsl2583_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct tsl2583_chip *chip = iio_priv(indio_dev); @@ -884,8 +884,6 @@ static int tsl2583_remove(struct i2c_client *client) pm_runtime_set_suspended(&client->dev); tsl2583_set_power_state(chip, TSL2583_CNTL_PWR_OFF); - - return 0; } static int tsl2583_suspend(struct device *dev) diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c index 6ae1b27e50b6..090038fed889 100644 --- a/drivers/iio/light/tsl4531.c +++ b/drivers/iio/light/tsl4531.c @@ -207,12 +207,10 @@ static int tsl4531_powerdown(struct i2c_client *client) TSL4531_MODE_POWERDOWN); } -static int tsl4531_remove(struct i2c_client *client) +static void tsl4531_remove(struct i2c_client *client) { iio_device_unregister(i2c_get_clientdata(client)); tsl4531_powerdown(client); - - return 0; } static int tsl4531_suspend(struct device *dev) diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index 80d2299da561..3e652d7f3b0e 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -904,7 +904,7 @@ out_err: } -static int us5182d_remove(struct i2c_client *client) +static void us5182d_remove(struct i2c_client *client) { struct us5182d_data *data = iio_priv(i2c_get_clientdata(client)); int ret; @@ -918,8 +918,6 @@ static int us5182d_remove(struct i2c_client *client) if (ret) dev_warn(&client->dev, "Failed to shut down (%pe)\n", ERR_PTR(ret)); - - return 0; } static int us5182d_suspend(struct device *dev) diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 3db4e26731bb..f6c83ecaad8b 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1111,7 +1111,7 @@ static const struct of_device_id vcnl_4000_of_match[] = { }; MODULE_DEVICE_TABLE(of, vcnl_4000_of_match); -static int vcnl4000_remove(struct i2c_client *client) +static void vcnl4000_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct vcnl4000_data *data = iio_priv(indio_dev); @@ -1126,8 +1126,6 @@ static int vcnl4000_remove(struct i2c_client *client) if (ret) dev_warn(&client->dev, "Failed to power down (%pe)\n", ERR_PTR(ret)); - - return 0; } static int vcnl4000_runtime_suspend(struct device *dev) diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 6a196cf2270b..3ed37f6057fb 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -601,7 +601,7 @@ fail_poweroff: return ret; } -static int vcnl4035_remove(struct i2c_client *client) +static void vcnl4035_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); int ret; @@ -616,8 +616,6 @@ static int vcnl4035_remove(struct i2c_client *client) if (ret) dev_warn(&client->dev, "Failed to put device into standby (%pe)\n", ERR_PTR(ret)); - - return 0; } static int vcnl4035_runtime_suspend(struct device *dev) diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c index 1e55e09a8d16..cfa4e9e7c803 100644 --- a/drivers/iio/light/veml6070.c +++ b/drivers/iio/light/veml6070.c @@ -180,15 +180,13 @@ fail: return ret; } -static int veml6070_remove(struct i2c_client *client) +static void veml6070_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct veml6070_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); i2c_unregister_device(data->client2); - - return 0; } static const struct i2c_device_id veml6070_id[] = { |