diff options
Diffstat (limited to 'drivers/iio/light')
51 files changed, 1576 insertions, 47 deletions
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 6fa31fcd71a1..45edba797e4c 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -289,6 +289,20 @@ config JSA1212 To compile this driver as a module, choose M here: the module will be called jsa1212. +config ROHM_BU27008 + tristate "ROHM BU27008 color (RGB+C/IR) sensor" + depends on I2C + select REGMAP_I2C + select IIO_GTS_HELPER + help + Enable support for the ROHM BU27008 color sensor. + The ROHM BU27008 is a sensor with 5 photodiodes (red, green, + blue, clear and IR) with four configurable channels. Red and + green being always available and two out of the rest three + (blue, clear, IR) can be selected to be simultaneously measured. + Typical application is adjusting LCD backlight of TVs, + mobile phones and tablet PCs. + config ROHM_BU27034 tristate "ROHM BU27034 ambient light sensor" depends on I2C @@ -413,6 +427,17 @@ config OPT3001 If built as a dynamically linked module, it will be called opt3001. +config OPT4001 + tristate "Texas Instruments OPT4001 Light Sensor" + depends on I2C + select REGMAP_I2C + help + If you say Y or M here, you get support for Texas Instruments + OPT4001 Ambient Light Sensor. + + If built as a dynamically linked module, it will be called + opt4001. + config PA12203001 tristate "TXC PA12203001 light and proximity sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 985f6feaccd4..c0db4c4c36ec 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -37,7 +37,9 @@ obj-$(CONFIG_MAX44000) += max44000.o obj-$(CONFIG_MAX44009) += max44009.o obj-$(CONFIG_NOA1305) += noa1305.o obj-$(CONFIG_OPT3001) += opt3001.o +obj-$(CONFIG_OPT4001) += opt4001.o obj-$(CONFIG_PA12203001) += pa12203001.o +obj-$(CONFIG_ROHM_BU27008) += rohm-bu27008.o obj-$(CONFIG_ROHM_BU27034) += rohm-bu27034.o obj-$(CONFIG_RPR0521) += rpr0521.o obj-$(CONFIG_SI1133) += si1133.o diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index 210a90f44c53..5fd775a20176 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -270,7 +270,7 @@ static struct i2c_driver adjd_s311_driver = { .driver = { .name = ADJD_S311_DRV_NAME, }, - .probe_new = adjd_s311_probe, + .probe = adjd_s311_probe, .id_table = adjd_s311_id, }; module_i2c_driver(adjd_s311_driver); diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c index 606075350d01..aa4a6c78f0aa 100644 --- a/drivers/iio/light/adux1020.c +++ b/drivers/iio/light/adux1020.c @@ -837,7 +837,7 @@ static struct i2c_driver adux1020_driver = { .name = ADUX1020_DRV_NAME, .of_match_table = adux1020_of_match, }, - .probe_new = adux1020_probe, + .probe = adux1020_probe, .id_table = adux1020_id, }; module_i2c_driver(adux1020_driver); diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c index 69cc723e2ac4..8f0119f392b7 100644 --- a/drivers/iio/light/al3010.c +++ b/drivers/iio/light/al3010.c @@ -229,7 +229,7 @@ static struct i2c_driver al3010_driver = { .of_match_table = al3010_of_match, .pm = pm_sleep_ptr(&al3010_pm_ops), }, - .probe_new = al3010_probe, + .probe = al3010_probe, .id_table = al3010_id, }; module_i2c_driver(al3010_driver); diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c index 9ff28bbf34bb..d5957d85c278 100644 --- a/drivers/iio/light/al3320a.c +++ b/drivers/iio/light/al3320a.c @@ -16,6 +16,7 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -247,13 +248,20 @@ static const struct of_device_id al3320a_of_match[] = { }; MODULE_DEVICE_TABLE(of, al3320a_of_match); +static const struct acpi_device_id al3320a_acpi_match[] = { + {"CALS0001"}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, al3320a_acpi_match); + static struct i2c_driver al3320a_driver = { .driver = { .name = AL3320A_DRV_NAME, .of_match_table = al3320a_of_match, .pm = pm_sleep_ptr(&al3320a_pm_ops), + .acpi_match_table = al3320a_acpi_match, }, - .probe_new = al3320a_probe, + .probe = al3320a_probe, .id_table = al3320a_id, }; diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 15dfb753734f..0f978b30a232 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -504,7 +504,7 @@ static struct i2c_driver apds9300_driver = { .name = APDS9300_DRV_NAME, .pm = pm_sleep_ptr(&apds9300_pm_ops), }, - .probe_new = apds9300_probe, + .probe = apds9300_probe, .remove = apds9300_remove, .id_table = apds9300_id, }; diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index cc5974a95bd3..1065a340b12b 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -1131,7 +1131,7 @@ static struct i2c_driver apds9960_driver = { .pm = &apds9960_pm_ops, .acpi_match_table = apds9960_acpi_match, }, - .probe_new = apds9960_probe, + .probe = apds9960_probe, .remove = apds9960_remove, .id_table = apds9960_id, }; diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c index 2307fc531752..ec97a3a46839 100644 --- a/drivers/iio/light/as73211.c +++ b/drivers/iio/light/as73211.c @@ -790,7 +790,7 @@ static struct i2c_driver as73211_driver = { .of_match_table = as73211_of_match, .pm = pm_sleep_ptr(&as73211_pm_ops), }, - .probe_new = as73211_probe, + .probe = as73211_probe, .id_table = as73211_id, }; module_i2c_driver(as73211_driver); diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c index 390c5b3ad4f6..4b869fa9e5b1 100644 --- a/drivers/iio/light/bh1750.c +++ b/drivers/iio/light/bh1750.c @@ -320,7 +320,7 @@ static struct i2c_driver bh1750_driver = { .of_match_table = bh1750_of_match, .pm = pm_sleep_ptr(&bh1750_pm_ops), }, - .probe_new = bh1750_probe, + .probe = bh1750_probe, .remove = bh1750_remove, .id_table = bh1750_id, diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index da9039e5a839..b84166c5fa06 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -269,7 +269,7 @@ static const struct of_device_id of_bh1780_match[] = { MODULE_DEVICE_TABLE(of, of_bh1780_match); static struct i2c_driver bh1780_driver = { - .probe_new = bh1780_probe, + .probe = bh1780_probe, .remove = bh1780_remove, .id_table = bh1780_id, .driver = { diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index d4a34a3bf00d..9df85b3999fa 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -542,7 +542,7 @@ static struct i2c_driver cm32181_driver = { .of_match_table = cm32181_of_match, .pm = pm_sleep_ptr(&cm32181_pm_ops), }, - .probe_new = cm32181_probe, + .probe = cm32181_probe, }; module_i2c_driver(cm32181_driver); diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 43e492f5051d..d48a70efca69 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -417,7 +417,7 @@ static struct i2c_driver cm3232_driver = { .pm = pm_sleep_ptr(&cm3232_pm_ops), }, .id_table = cm3232_id, - .probe_new = cm3232_probe, + .probe = cm3232_probe, .remove = cm3232_remove, }; diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index e5ce7d0fd272..35d20207a648 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -266,7 +266,7 @@ static struct i2c_driver cm3323_driver = { .name = CM3323_DRV_NAME, .of_match_table = cm3323_of_match, }, - .probe_new = cm3323_probe, + .probe = cm3323_probe, .id_table = cm3323_id, }; diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 1707dbf2ce26..97e559acba2b 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -730,7 +730,7 @@ static struct i2c_driver cm36651_driver = { .name = "cm36651", .of_match_table = cm36651_of_match, }, - .probe_new = cm36651_probe, + .probe = cm36651_probe, .remove = cm36651_remove, .id_table = cm36651_id, }; diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c index c0430db0038a..fec10d5e037e 100644 --- a/drivers/iio/light/gp2ap002.c +++ b/drivers/iio/light/gp2ap002.c @@ -710,7 +710,7 @@ static struct i2c_driver gp2ap002_driver = { .of_match_table = gp2ap002_of_match, .pm = pm_ptr(&gp2ap002_dev_pm_ops), }, - .probe_new = gp2ap002_probe, + .probe = gp2ap002_probe, .remove = gp2ap002_remove, .id_table = gp2ap002_id_table, }; diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index a5bf9da0d2f3..9f41724819b6 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1609,7 +1609,7 @@ static struct i2c_driver gp2ap020a00f_driver = { .name = GP2A_I2C_NAME, .of_match_table = gp2ap020a00f_of_match, }, - .probe_new = gp2ap020a00f_probe, + .probe = gp2ap020a00f_probe, .remove = gp2ap020a00f_remove, .id_table = gp2ap020a00f_id, }; diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index 141845fb47f9..43484c18b101 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -865,7 +865,7 @@ static struct i2c_driver isl29018_driver = { .pm = pm_sleep_ptr(&isl29018_pm_ops), .of_match_table = isl29018_of_match, }, - .probe_new = isl29018_probe, + .probe = isl29018_probe, .id_table = isl29018_id, }; module_i2c_driver(isl29018_driver); diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c index bcf3a556e41a..5694683389be 100644 --- a/drivers/iio/light/isl29028.c +++ b/drivers/iio/light/isl29028.c @@ -698,7 +698,7 @@ static struct i2c_driver isl29028_driver = { .pm = pm_ptr(&isl29028_pm_ops), .of_match_table = isl29028_of_match, }, - .probe_new = isl29028_probe, + .probe = isl29028_probe, .remove = isl29028_remove, .id_table = isl29028_id, }; diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index b4bd656ca169..f1d3356d3369 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -337,7 +337,7 @@ static struct i2c_driver isl29125_driver = { .name = ISL29125_DRV_NAME, .pm = pm_sleep_ptr(&isl29125_pm_ops), }, - .probe_new = isl29125_probe, + .probe = isl29125_probe, .remove = isl29125_remove, .id_table = isl29125_id, }; diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index d3834d0a0635..37e2807041a1 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -440,7 +440,7 @@ static struct i2c_driver jsa1212_driver = { .pm = pm_sleep_ptr(&jsa1212_pm_ops), .acpi_match_table = ACPI_PTR(jsa1212_acpi_match), }, - .probe_new = jsa1212_probe, + .probe = jsa1212_probe, .remove = jsa1212_remove, .id_table = jsa1212_id, }; diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index bdbd918213e4..061c122fdc5e 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -1641,7 +1641,7 @@ static struct i2c_driver ltr501_driver = { .pm = pm_sleep_ptr(<r501_pm_ops), .acpi_match_table = ACPI_PTR(ltr_acpi_match), }, - .probe_new = ltr501_probe, + .probe = ltr501_probe, .remove = ltr501_remove, .id_table = ltr501_id, }; diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c index 4b8ef36b6912..8de4dd849936 100644 --- a/drivers/iio/light/ltrf216a.c +++ b/drivers/iio/light/ltrf216a.c @@ -539,7 +539,7 @@ static struct i2c_driver ltrf216a_driver = { .pm = pm_ptr(<rf216a_pm_ops), .of_match_table = ltrf216a_of_match, }, - .probe_new = ltrf216a_probe, + .probe = ltrf216a_probe, .id_table = ltrf216a_id, }; module_i2c_driver(ltrf216a_driver); diff --git a/drivers/iio/light/lv0104cs.c b/drivers/iio/light/lv0104cs.c index c041fa0faa5d..a5445d58fddf 100644 --- a/drivers/iio/light/lv0104cs.c +++ b/drivers/iio/light/lv0104cs.c @@ -520,7 +520,7 @@ static struct i2c_driver lv0104cs_i2c_driver = { .name = "lv0104cs", }, .id_table = lv0104cs_id, - .probe_new = lv0104cs_probe, + .probe = lv0104cs_probe, }; module_i2c_driver(lv0104cs_i2c_driver); diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index 5dcabc43a30e..db96c5b73100 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -616,7 +616,7 @@ static struct i2c_driver max44000_driver = { .name = MAX44000_DRV_NAME, .acpi_match_table = ACPI_PTR(max44000_acpi_match), }, - .probe_new = max44000_probe, + .probe = max44000_probe, .id_table = max44000_id, }; diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c index 176dcad6e8e8..61ce276e86f7 100644 --- a/drivers/iio/light/max44009.c +++ b/drivers/iio/light/max44009.c @@ -544,7 +544,7 @@ static struct i2c_driver max44009_driver = { .name = MAX44009_DRV_NAME, .of_match_table = max44009_of_match, }, - .probe_new = max44009_probe, + .probe = max44009_probe, .id_table = max44009_id, }; module_i2c_driver(max44009_driver); diff --git a/drivers/iio/light/noa1305.c b/drivers/iio/light/noa1305.c index eaf548d4649e..1574310020e3 100644 --- a/drivers/iio/light/noa1305.c +++ b/drivers/iio/light/noa1305.c @@ -278,7 +278,7 @@ static struct i2c_driver noa1305_driver = { .name = NOA1305_DRIVER_NAME, .of_match_table = noa1305_of_match, }, - .probe_new = noa1305_probe, + .probe = noa1305_probe, .id_table = noa1305_ids, }; diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index ec4f5c2369c4..cb41e5ee8ec1 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -834,7 +834,7 @@ static const struct of_device_id opt3001_of_match[] = { MODULE_DEVICE_TABLE(of, opt3001_of_match); static struct i2c_driver opt3001_driver = { - .probe_new = opt3001_probe, + .probe = opt3001_probe, .remove = opt3001_remove, .id_table = opt3001_id, diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c new file mode 100644 index 000000000000..502946bf9f94 --- /dev/null +++ b/drivers/iio/light/opt4001.c @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Axis Communications AB + * + * Datasheet: https://www.ti.com/lit/gpn/opt4001 + * + * Device driver for the Texas Instruments OPT4001. + */ + +#include <linux/bitfield.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/math64.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +/* OPT4001 register set */ +#define OPT4001_LIGHT1_MSB 0x00 +#define OPT4001_LIGHT1_LSB 0x01 +#define OPT4001_CTRL 0x0A +#define OPT4001_DEVICE_ID 0x11 + +/* OPT4001 register mask */ +#define OPT4001_EXPONENT_MASK GENMASK(15, 12) +#define OPT4001_MSB_MASK GENMASK(11, 0) +#define OPT4001_LSB_MASK GENMASK(15, 8) +#define OPT4001_COUNTER_MASK GENMASK(7, 4) +#define OPT4001_CRC_MASK GENMASK(3, 0) + +/* OPT4001 device id mask */ +#define OPT4001_DEVICE_ID_MASK GENMASK(11, 0) + +/* OPT4001 control registers mask */ +#define OPT4001_CTRL_QWAKE_MASK GENMASK(15, 15) +#define OPT4001_CTRL_RANGE_MASK GENMASK(13, 10) +#define OPT4001_CTRL_CONV_TIME_MASK GENMASK(9, 6) +#define OPT4001_CTRL_OPER_MODE_MASK GENMASK(5, 4) +#define OPT4001_CTRL_LATCH_MASK GENMASK(3, 3) +#define OPT4001_CTRL_INT_POL_MASK GENMASK(2, 2) +#define OPT4001_CTRL_FAULT_COUNT GENMASK(0, 1) + +/* OPT4001 constants */ +#define OPT4001_DEVICE_ID_VAL 0x121 + +/* OPT4001 operating modes */ +#define OPT4001_CTRL_OPER_MODE_OFF 0x0 +#define OPT4001_CTRL_OPER_MODE_FORCED 0x1 +#define OPT4001_CTRL_OPER_MODE_ONE_SHOT 0x2 +#define OPT4001_CTRL_OPER_MODE_CONTINUOUS 0x3 + +/* OPT4001 conversion control register definitions */ +#define OPT4001_CTRL_CONVERSION_0_6MS 0x0 +#define OPT4001_CTRL_CONVERSION_1MS 0x1 +#define OPT4001_CTRL_CONVERSION_1_8MS 0x2 +#define OPT4001_CTRL_CONVERSION_3_4MS 0x3 +#define OPT4001_CTRL_CONVERSION_6_5MS 0x4 +#define OPT4001_CTRL_CONVERSION_12_7MS 0x5 +#define OPT4001_CTRL_CONVERSION_25MS 0x6 +#define OPT4001_CTRL_CONVERSION_50MS 0x7 +#define OPT4001_CTRL_CONVERSION_100MS 0x8 +#define OPT4001_CTRL_CONVERSION_200MS 0x9 +#define OPT4001_CTRL_CONVERSION_400MS 0xa +#define OPT4001_CTRL_CONVERSION_800MS 0xb + +/* OPT4001 scale light level range definitions */ +#define OPT4001_CTRL_LIGHT_SCALE_AUTO 12 + +/* OPT4001 default values */ +#define OPT4001_DEFAULT_CONVERSION_TIME OPT4001_CTRL_CONVERSION_800MS + +/* + * The different packaging of OPT4001 has different constants used when calculating + * lux values. + */ +struct opt4001_chip_info { + int mul; + int div; + const char *name; +}; + +struct opt4001_chip { + struct regmap *regmap; + struct i2c_client *client; + u8 int_time; + const struct opt4001_chip_info *chip_info; +}; + +static const struct opt4001_chip_info opt4001_sot_5x3_info = { + .mul = 4375, + .div = 10000000, + .name = "opt4001-sot-5x3" +}; + +static const struct opt4001_chip_info opt4001_picostar_info = { + .mul = 3125, + .div = 10000000, + .name = "opt4001-picostar" +}; + +static const int opt4001_int_time_available[][2] = { + { 0, 600 }, + { 0, 1000 }, + { 0, 1800 }, + { 0, 3400 }, + { 0, 6500 }, + { 0, 12700 }, + { 0, 25000 }, + { 0, 50000 }, + { 0, 100000 }, + { 0, 200000 }, + { 0, 400000 }, + { 0, 800000 }, +}; + +/* + * Conversion time is integration time + time to set register + * this is used as integration time. + */ +static const int opt4001_int_time_reg[][2] = { + { 600, OPT4001_CTRL_CONVERSION_0_6MS }, + { 1000, OPT4001_CTRL_CONVERSION_1MS }, + { 1800, OPT4001_CTRL_CONVERSION_1_8MS }, + { 3400, OPT4001_CTRL_CONVERSION_3_4MS }, + { 6500, OPT4001_CTRL_CONVERSION_6_5MS }, + { 12700, OPT4001_CTRL_CONVERSION_12_7MS }, + { 25000, OPT4001_CTRL_CONVERSION_25MS }, + { 50000, OPT4001_CTRL_CONVERSION_50MS }, + { 100000, OPT4001_CTRL_CONVERSION_100MS }, + { 200000, OPT4001_CTRL_CONVERSION_200MS }, + { 400000, OPT4001_CTRL_CONVERSION_400MS }, + { 800000, OPT4001_CTRL_CONVERSION_800MS }, +}; + +static int opt4001_als_time_to_index(const u32 als_integration_time) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(opt4001_int_time_available); i++) { + if (als_integration_time == opt4001_int_time_available[i][1]) + return i; + } + + return -EINVAL; +} + +static u8 opt4001_calculate_crc(u8 exp, u32 mantissa, u8 count) +{ + u8 crc; + + crc = (hweight32(mantissa) + hweight32(exp) + hweight32(count)) % 2; + crc |= ((hweight32(mantissa & 0xAAAAA) + hweight32(exp & 0xA) + + hweight32(count & 0xA)) % 2) << 1; + crc |= ((hweight32(mantissa & 0x88888) + hweight32(exp & 0x8) + + hweight32(count & 0x8)) % 2) << 2; + crc |= (hweight32(mantissa & 0x80808) % 2) << 3; + + return crc; +} + +static int opt4001_read_lux_value(struct iio_dev *indio_dev, + int *val, int *val2) +{ + struct opt4001_chip *chip = iio_priv(indio_dev); + struct device *dev = &chip->client->dev; + unsigned int light1; + unsigned int light2; + u16 msb; + u16 lsb; + u8 exp; + u8 count; + u8 crc; + u8 calc_crc; + u64 lux_raw; + int ret; + + ret = regmap_read(chip->regmap, OPT4001_LIGHT1_MSB, &light1); + if (ret < 0) { + dev_err(dev, "Failed to read data bytes"); + return ret; + } + + ret = regmap_read(chip->regmap, OPT4001_LIGHT1_LSB, &light2); + if (ret < 0) { + dev_err(dev, "Failed to read data bytes"); + return ret; + } + + count = FIELD_GET(OPT4001_COUNTER_MASK, light2); + exp = FIELD_GET(OPT4001_EXPONENT_MASK, light1); + crc = FIELD_GET(OPT4001_CRC_MASK, light2); + msb = FIELD_GET(OPT4001_MSB_MASK, light1); + lsb = FIELD_GET(OPT4001_LSB_MASK, light2); + lux_raw = (msb << 8) + lsb; + calc_crc = opt4001_calculate_crc(exp, lux_raw, count); + if (calc_crc != crc) + return -EIO; + + lux_raw = lux_raw << exp; + lux_raw = lux_raw * chip->chip_info->mul; + *val = div_u64_rem(lux_raw, chip->chip_info->div, val2); + *val2 = *val2 * 100; + + return IIO_VAL_INT_PLUS_NANO; +} + +static int opt4001_set_conf(struct opt4001_chip *chip) +{ + struct device *dev = &chip->client->dev; + u16 reg; + int ret; + + reg = FIELD_PREP(OPT4001_CTRL_RANGE_MASK, OPT4001_CTRL_LIGHT_SCALE_AUTO); + reg |= FIELD_PREP(OPT4001_CTRL_CONV_TIME_MASK, chip->int_time); + reg |= FIELD_PREP(OPT4001_CTRL_OPER_MODE_MASK, OPT4001_CTRL_OPER_MODE_CONTINUOUS); + + ret = regmap_write(chip->regmap, OPT4001_CTRL, reg); + if (ret) + dev_err(dev, "Failed to set configuration\n"); + + return ret; +} + +static int opt4001_power_down(struct opt4001_chip *chip) +{ + struct device *dev = &chip->client->dev; + int ret; + unsigned int reg; + + ret = regmap_read(chip->regmap, OPT4001_DEVICE_ID, ®); + if (ret) { + dev_err(dev, "Failed to read configuration\n"); + return ret; + } + + /* MODE_OFF is 0x0 so just set bits to 0 */ + reg &= ~OPT4001_CTRL_OPER_MODE_MASK; + + ret = regmap_write(chip->regmap, OPT4001_CTRL, reg); + if (ret) + dev_err(dev, "Failed to set configuration to power down\n"); + + return ret; +} + +static void opt4001_chip_off_action(void *data) +{ + struct opt4001_chip *chip = data; + + opt4001_power_down(chip); +} + +static const struct iio_chan_spec opt4001_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) + }, +}; + +static int opt4001_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct opt4001_chip *chip = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + return opt4001_read_lux_value(indio_dev, val, val2); + case IIO_CHAN_INFO_INT_TIME: + *val = 0; + *val2 = opt4001_int_time_reg[chip->int_time][0]; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int opt4001_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct opt4001_chip *chip = iio_priv(indio_dev); + int int_time; + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + int_time = opt4001_als_time_to_index(val2); + if (int_time < 0) + return int_time; + chip->int_time = int_time; + return opt4001_set_conf(chip); + default: + return -EINVAL; + } +} + +static int opt4001_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(opt4001_int_time_available) * 2; + *vals = (const int *)opt4001_int_time_available; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + + default: + return -EINVAL; + } +} + +static const struct iio_info opt4001_info_no_irq = { + .read_raw = opt4001_read_raw, + .write_raw = opt4001_write_raw, + .read_avail = opt4001_read_available, +}; + +static int opt4001_load_defaults(struct opt4001_chip *chip) +{ + chip->int_time = OPT4001_DEFAULT_CONVERSION_TIME; + + return opt4001_set_conf(chip); +} + +static bool opt4001_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case OPT4001_LIGHT1_MSB: + case OPT4001_LIGHT1_LSB: + case OPT4001_CTRL: + case OPT4001_DEVICE_ID: + return true; + default: + return false; + } +} + +static bool opt4001_writable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case OPT4001_CTRL: + return true; + default: + return false; + } +} + +static bool opt4001_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case OPT4001_LIGHT1_MSB: + case OPT4001_LIGHT1_LSB: + return true; + default: + return false; + } +} + +static const struct regmap_config opt4001_regmap_config = { + .name = "opt4001", + .reg_bits = 8, + .val_bits = 16, + .cache_type = REGCACHE_RBTREE, + .max_register = OPT4001_DEVICE_ID, + .readable_reg = opt4001_readable_reg, + .writeable_reg = opt4001_writable_reg, + .volatile_reg = opt4001_volatile_reg, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static int opt4001_probe(struct i2c_client *client) +{ + struct opt4001_chip *chip; + struct iio_dev *indio_dev; + int ret; + uint dev_id; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + + chip = iio_priv(indio_dev); + + ret = devm_regulator_get_enable(&client->dev, "vdd"); + if (ret) + return dev_err_probe(&client->dev, ret, "Failed to enable vdd supply\n"); + + chip->regmap = devm_regmap_init_i2c(client, &opt4001_regmap_config); + if (IS_ERR(chip->regmap)) + return dev_err_probe(&client->dev, PTR_ERR(chip->regmap), + "regmap initialization failed\n"); + chip->client = client; + + indio_dev->info = &opt4001_info_no_irq; + + ret = regmap_reinit_cache(chip->regmap, &opt4001_regmap_config); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to reinit regmap cache\n"); + + ret = regmap_read(chip->regmap, OPT4001_DEVICE_ID, &dev_id); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to read the device ID register\n"); + + dev_id = FIELD_GET(OPT4001_DEVICE_ID_MASK, dev_id); + if (dev_id != OPT4001_DEVICE_ID_VAL) + dev_warn(&client->dev, "Device ID: %#04x unknown\n", dev_id); + + chip->chip_info = device_get_match_data(&client->dev); + + indio_dev->channels = opt4001_channels; + indio_dev->num_channels = ARRAY_SIZE(opt4001_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = chip->chip_info->name; + + ret = opt4001_load_defaults(chip); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to set sensor defaults\n"); + + ret = devm_add_action_or_reset(&client->dev, + opt4001_chip_off_action, + chip); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to setup power off action\n"); + + return devm_iio_device_register(&client->dev, indio_dev); +} + +/* + * The compatible string determines which constants to use depending on + * opt4001 packaging + */ +static const struct i2c_device_id opt4001_id[] = { + { "opt4001-sot-5x3", (kernel_ulong_t)&opt4001_sot_5x3_info }, + { "opt4001-picostar", (kernel_ulong_t)&opt4001_picostar_info }, + { } +}; +MODULE_DEVICE_TABLE(i2c, opt4001_id); + +static const struct of_device_id opt4001_of_match[] = { + { .compatible = "ti,opt4001-sot-5x3", .data = &opt4001_sot_5x3_info}, + { .compatible = "ti,opt4001-picostar", .data = &opt4001_picostar_info}, + {} +}; +MODULE_DEVICE_TABLE(of, opt4001_of_match); + +static struct i2c_driver opt4001_driver = { + .driver = { + .name = "opt4001", + .of_match_table = opt4001_of_match, + }, + .probe = opt4001_probe, + .id_table = opt4001_id, +}; +module_i2c_driver(opt4001_driver); + +MODULE_AUTHOR("Stefan Windfeldt-Prytz <stefan.windfeldt-prytz@axis.com>"); +MODULE_DESCRIPTION("Texas Instruments opt4001 ambient light sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c index 15a666f15c27..ed241598aefb 100644 --- a/drivers/iio/light/pa12203001.c +++ b/drivers/iio/light/pa12203001.c @@ -474,7 +474,7 @@ static struct i2c_driver pa12203001_driver = { .pm = &pa12203001_pm_ops, .acpi_match_table = ACPI_PTR(pa12203001_acpi_match), }, - .probe_new = pa12203001_probe, + .probe = pa12203001_probe, .remove = pa12203001_remove, .id_table = pa12203001_id, diff --git a/drivers/iio/light/rohm-bu27008.c b/drivers/iio/light/rohm-bu27008.c new file mode 100644 index 000000000000..489902bed7f0 --- /dev/null +++ b/drivers/iio/light/rohm-bu27008.c @@ -0,0 +1,1026 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * BU27008 ROHM Colour Sensor + * + * Copyright (c) 2023, ROHM Semiconductor. + */ + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/units.h> + +#include <linux/iio/iio.h> +#include <linux/iio/iio-gts-helper.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define BU27008_REG_SYSTEM_CONTROL 0x40 +#define BU27008_MASK_SW_RESET BIT(7) +#define BU27008_MASK_PART_ID GENMASK(5, 0) +#define BU27008_ID 0x1a +#define BU27008_REG_MODE_CONTROL1 0x41 +#define BU27008_MASK_MEAS_MODE GENMASK(2, 0) +#define BU27008_MASK_CHAN_SEL GENMASK(3, 2) + +#define BU27008_REG_MODE_CONTROL2 0x42 +#define BU27008_MASK_RGBC_GAIN GENMASK(7, 3) +#define BU27008_MASK_IR_GAIN_LO GENMASK(2, 0) +#define BU27008_SHIFT_IR_GAIN 3 + +#define BU27008_REG_MODE_CONTROL3 0x43 +#define BU27008_MASK_VALID BIT(7) +#define BU27008_MASK_INT_EN BIT(1) +#define BU27008_INT_EN BU27008_MASK_INT_EN +#define BU27008_INT_DIS 0 +#define BU27008_MASK_MEAS_EN BIT(0) +#define BU27008_MEAS_EN BIT(0) +#define BU27008_MEAS_DIS 0 + +#define BU27008_REG_DATA0_LO 0x50 +#define BU27008_REG_DATA1_LO 0x52 +#define BU27008_REG_DATA2_LO 0x54 +#define BU27008_REG_DATA3_LO 0x56 +#define BU27008_REG_DATA3_HI 0x57 +#define BU27008_REG_MANUFACTURER_ID 0x92 +#define BU27008_REG_MAX BU27008_REG_MANUFACTURER_ID + +/** + * enum bu27008_chan_type - BU27008 channel types + * @BU27008_RED: Red channel. Always via data0. + * @BU27008_GREEN: Green channel. Always via data1. + * @BU27008_BLUE: Blue channel. Via data2 (when used). + * @BU27008_CLEAR: Clear channel. Via data2 or data3 (when used). + * @BU27008_IR: IR channel. Via data3 (when used). + * @BU27008_NUM_CHANS: Number of channel types. + */ +enum bu27008_chan_type { + BU27008_RED, + BU27008_GREEN, + BU27008_BLUE, + BU27008_CLEAR, + BU27008_IR, + BU27008_NUM_CHANS +}; + +/** + * enum bu27008_chan - BU27008 physical data channel + * @BU27008_DATA0: Always red. + * @BU27008_DATA1: Always green. + * @BU27008_DATA2: Blue or clear. + * @BU27008_DATA3: IR or clear. + * @BU27008_NUM_HW_CHANS: Number of physical channels + */ +enum bu27008_chan { + BU27008_DATA0, + BU27008_DATA1, + BU27008_DATA2, + BU27008_DATA3, + BU27008_NUM_HW_CHANS +}; + +/* We can always measure red and green at same time */ +#define ALWAYS_SCANNABLE (BIT(BU27008_RED) | BIT(BU27008_GREEN)) + +/* We use these data channel configs. Ensure scan_masks below follow them too */ +#define BU27008_BLUE2_CLEAR3 0x0 /* buffer is R, G, B, C */ +#define BU27008_CLEAR2_IR3 0x1 /* buffer is R, G, C, IR */ +#define BU27008_BLUE2_IR3 0x2 /* buffer is R, G, B, IR */ + +static const unsigned long bu27008_scan_masks[] = { + /* buffer is R, G, B, C */ + ALWAYS_SCANNABLE | BIT(BU27008_BLUE) | BIT(BU27008_CLEAR), + /* buffer is R, G, C, IR */ + ALWAYS_SCANNABLE | BIT(BU27008_CLEAR) | BIT(BU27008_IR), + /* buffer is R, G, B, IR */ + ALWAYS_SCANNABLE | BIT(BU27008_BLUE) | BIT(BU27008_IR), + 0 +}; + +/* + * Available scales with gain 1x - 1024x, timings 55, 100, 200, 400 mS + * Time impacts to gain: 1x, 2x, 4x, 8x. + * + * => Max total gain is HWGAIN * gain by integration time (8 * 1024) = 8192 + * + * Max amplification is (HWGAIN * MAX integration-time multiplier) 1024 * 8 + * = 8192. With NANO scale we get rid of accuracy loss when we start with the + * scale 16.0 for HWGAIN1, INT-TIME 55 mS. This way the nano scale for MAX + * total gain 8192 will be 1953125 + */ +#define BU27008_SCALE_1X 16 + +/* See the data sheet for the "Gain Setting" table */ +#define BU27008_GSEL_1X 0x00 +#define BU27008_GSEL_4X 0x08 +#define BU27008_GSEL_8X 0x09 +#define BU27008_GSEL_16X 0x0a +#define BU27008_GSEL_32X 0x0b +#define BU27008_GSEL_64X 0x0c +#define BU27008_GSEL_256X 0x18 +#define BU27008_GSEL_512X 0x19 +#define BU27008_GSEL_1024X 0x1a + +static const struct iio_gain_sel_pair bu27008_gains[] = { + GAIN_SCALE_GAIN(1, BU27008_GSEL_1X), + GAIN_SCALE_GAIN(4, BU27008_GSEL_4X), + GAIN_SCALE_GAIN(8, BU27008_GSEL_8X), + GAIN_SCALE_GAIN(16, BU27008_GSEL_16X), + GAIN_SCALE_GAIN(32, BU27008_GSEL_32X), + GAIN_SCALE_GAIN(64, BU27008_GSEL_64X), + GAIN_SCALE_GAIN(256, BU27008_GSEL_256X), + GAIN_SCALE_GAIN(512, BU27008_GSEL_512X), + GAIN_SCALE_GAIN(1024, BU27008_GSEL_1024X), +}; + +static const struct iio_gain_sel_pair bu27008_gains_ir[] = { + GAIN_SCALE_GAIN(2, BU27008_GSEL_1X), + GAIN_SCALE_GAIN(4, BU27008_GSEL_4X), + GAIN_SCALE_GAIN(8, BU27008_GSEL_8X), + GAIN_SCALE_GAIN(16, BU27008_GSEL_16X), + GAIN_SCALE_GAIN(32, BU27008_GSEL_32X), + GAIN_SCALE_GAIN(64, BU27008_GSEL_64X), + GAIN_SCALE_GAIN(256, BU27008_GSEL_256X), + GAIN_SCALE_GAIN(512, BU27008_GSEL_512X), + GAIN_SCALE_GAIN(1024, BU27008_GSEL_1024X), +}; + +#define BU27008_MEAS_MODE_100MS 0x00 +#define BU27008_MEAS_MODE_55MS 0x01 +#define BU27008_MEAS_MODE_200MS 0x02 +#define BU27008_MEAS_MODE_400MS 0x04 +#define BU27008_MEAS_TIME_MAX_MS 400 + +static const struct iio_itime_sel_mul bu27008_itimes[] = { + GAIN_SCALE_ITIME_US(400000, BU27008_MEAS_MODE_400MS, 8), + GAIN_SCALE_ITIME_US(200000, BU27008_MEAS_MODE_200MS, 4), + GAIN_SCALE_ITIME_US(100000, BU27008_MEAS_MODE_100MS, 2), + GAIN_SCALE_ITIME_US(55000, BU27008_MEAS_MODE_55MS, 1), +}; + +/* + * All the RGBC channels share the same gain. + * IR gain can be fine-tuned from the gain set for the RGBC by 2 bit, but this + * would yield quite complex gain setting. Especially since not all bit + * compinations are supported. And in any case setting GAIN for RGBC will + * always also change the IR-gain. + * + * On top of this, the selector '0' which corresponds to hw-gain 1X on RGBC, + * corresponds to gain 2X on IR. Rest of the selctors correspond to same gains + * though. This, however, makes it not possible to use shared gain for all + * RGBC and IR settings even though they are all changed at the one go. + */ +#define BU27008_CHAN(color, data, separate_avail) \ +{ \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .channel2 = IIO_MOD_LIGHT_##color, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_separate_available = (separate_avail), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \ + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), \ + .address = BU27008_REG_##data##_LO, \ + .scan_index = BU27008_##color, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ +} + +/* For raw reads we always configure DATA3 for CLEAR */ +static const struct iio_chan_spec bu27008_channels[] = { + BU27008_CHAN(RED, DATA0, BIT(IIO_CHAN_INFO_SCALE)), + BU27008_CHAN(GREEN, DATA1, BIT(IIO_CHAN_INFO_SCALE)), + BU27008_CHAN(BLUE, DATA2, BIT(IIO_CHAN_INFO_SCALE)), + BU27008_CHAN(CLEAR, DATA2, BIT(IIO_CHAN_INFO_SCALE)), + /* + * We don't allow setting scale for IR (because of shared gain bits). + * Hence we don't advertise available ones either. + */ + BU27008_CHAN(IR, DATA3, 0), + IIO_CHAN_SOFT_TIMESTAMP(BU27008_NUM_CHANS), +}; + +struct bu27008_data { + struct regmap *regmap; + struct iio_trigger *trig; + struct device *dev; + struct iio_gts gts; + struct iio_gts gts_ir; + int irq; + + /* + * Prevent changing gain/time config when scale is read/written. + * Similarly, protect the integration_time read/change sequence. + * Prevent changing gain/time when data is read. + */ + struct mutex mutex; +}; + +static const struct regmap_range bu27008_volatile_ranges[] = { + { + .range_min = BU27008_REG_SYSTEM_CONTROL, /* SWRESET */ + .range_max = BU27008_REG_SYSTEM_CONTROL, + }, { + .range_min = BU27008_REG_MODE_CONTROL3, /* VALID */ + .range_max = BU27008_REG_MODE_CONTROL3, + }, { + .range_min = BU27008_REG_DATA0_LO, /* DATA */ + .range_max = BU27008_REG_DATA3_HI, + }, +}; + +static const struct regmap_access_table bu27008_volatile_regs = { + .yes_ranges = &bu27008_volatile_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bu27008_volatile_ranges), +}; + +static const struct regmap_range bu27008_read_only_ranges[] = { + { + .range_min = BU27008_REG_DATA0_LO, + .range_max = BU27008_REG_DATA3_HI, + }, { + .range_min = BU27008_REG_MANUFACTURER_ID, + .range_max = BU27008_REG_MANUFACTURER_ID, + }, +}; + +static const struct regmap_access_table bu27008_ro_regs = { + .no_ranges = &bu27008_read_only_ranges[0], + .n_no_ranges = ARRAY_SIZE(bu27008_read_only_ranges), +}; + +static const struct regmap_config bu27008_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = BU27008_REG_MAX, + .cache_type = REGCACHE_RBTREE, + .volatile_table = &bu27008_volatile_regs, + .wr_table = &bu27008_ro_regs, + /* + * All register writes are serialized by the mutex which protects the + * scale setting/getting. This is needed because scale is combined by + * gain and integration time settings and we need to ensure those are + * not read / written when scale is being computed. + * + * As a result of this serializing, we don't need regmap locking. Note, + * this is not true if we add any configurations which are not + * serialized by the mutex and which may need for example a protected + * read-modify-write cycle (eg. regmap_update_bits()). Please, revise + * this when adding features to the driver. + */ + .disable_locking = true, +}; + +#define BU27008_MAX_VALID_RESULT_WAIT_US 50000 +#define BU27008_VALID_RESULT_WAIT_QUANTA_US 1000 + +static int bu27008_chan_read_data(struct bu27008_data *data, int reg, int *val) +{ + int ret, valid; + __le16 tmp; + + ret = regmap_read_poll_timeout(data->regmap, BU27008_REG_MODE_CONTROL3, + valid, (valid & BU27008_MASK_VALID), + BU27008_VALID_RESULT_WAIT_QUANTA_US, + BU27008_MAX_VALID_RESULT_WAIT_US); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, reg, &tmp, sizeof(tmp)); + if (ret) + dev_err(data->dev, "Reading channel data failed\n"); + + *val = le16_to_cpu(tmp); + + return ret; +} + +static int bu27008_get_gain(struct bu27008_data *data, struct iio_gts *gts, int *gain) +{ + int ret, sel; + + ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL2, &sel); + if (ret) + return ret; + + sel = FIELD_GET(BU27008_MASK_RGBC_GAIN, sel); + + ret = iio_gts_find_gain_by_sel(gts, sel); + if (ret < 0) { + dev_err(data->dev, "unknown gain value 0x%x\n", sel); + return ret; + } + + *gain = ret; + + return 0; +} + +static int bu27008_write_gain_sel(struct bu27008_data *data, int sel) +{ + int regval; + + regval = FIELD_PREP(BU27008_MASK_RGBC_GAIN, sel); + + /* + * We do always set also the LOW bits of IR-gain because othervice we + * would risk resulting an invalid GAIN register value. + * + * We could allow setting separate gains for RGBC and IR when the + * values were such that HW could support both gain settings. + * Eg, when the shared bits were same for both gain values. + * + * This, however, has a negligible benefit compared to the increased + * software complexity when we would need to go through the gains + * for both channels separately when the integration time changes. + * This would end up with nasty logic for computing gain values for + * both channels - and rejecting them if shared bits changed. + * + * We should then build the logic by guessing what a user prefers. + * RGBC or IR gains correctly set while other jumps to odd value? + * Maybe look-up a value where both gains are somehow optimized + * <what this somehow is, is ATM unknown to us>. Or maybe user would + * expect us to reject changes when optimal gains can't be set to both + * channels w/given integration time. At best that would result + * solution that works well for a very specific subset of + * configurations but causes unexpected corner-cases. + * + * So, we keep it simple. Always set same selector to IR and RGBC. + * We disallow setting IR (as I expect that most of the users are + * interested in RGBC). This way we can show the user that the scales + * for RGBC and IR channels are different (1X Vs 2X with sel 0) while + * still keeping the operation deterministic. + */ + regval |= FIELD_PREP(BU27008_MASK_IR_GAIN_LO, sel); + + return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL2, + BU27008_MASK_RGBC_GAIN, regval); +} + +static int bu27008_set_gain(struct bu27008_data *data, int gain) +{ + int ret; + + ret = iio_gts_find_sel_by_gain(&data->gts, gain); + if (ret < 0) + return ret; + + return bu27008_write_gain_sel(data, ret); +} + +static int bu27008_get_int_time_sel(struct bu27008_data *data, int *sel) +{ + int ret, val; + + ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL1, &val); + *sel = FIELD_GET(BU27008_MASK_MEAS_MODE, val); + + return ret; +} + +static int bu27008_set_int_time_sel(struct bu27008_data *data, int sel) +{ + return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL1, + BU27008_MASK_MEAS_MODE, sel); +} + +static int bu27008_get_int_time_us(struct bu27008_data *data) +{ + int ret, sel; + + ret = bu27008_get_int_time_sel(data, &sel); + if (ret) + return ret; + + return iio_gts_find_int_time_by_sel(&data->gts, sel); +} + +static int _bu27008_get_scale(struct bu27008_data *data, bool ir, int *val, + int *val2) +{ + struct iio_gts *gts; + int gain, ret; + + if (ir) + gts = &data->gts_ir; + else + gts = &data->gts; + + ret = bu27008_get_gain(data, gts, &gain); + if (ret) + return ret; + + ret = bu27008_get_int_time_us(data); + if (ret < 0) + return ret; + + return iio_gts_get_scale(gts, gain, ret, val, val2); +} + +static int bu27008_get_scale(struct bu27008_data *data, bool ir, int *val, + int *val2) +{ + int ret; + + mutex_lock(&data->mutex); + ret = _bu27008_get_scale(data, ir, val, val2); + mutex_unlock(&data->mutex); + + return ret; +} + +static int bu27008_set_int_time(struct bu27008_data *data, int time) +{ + int ret; + + ret = iio_gts_find_sel_by_int_time(&data->gts, time); + if (ret < 0) + return ret; + + return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL1, + BU27008_MASK_MEAS_MODE, ret); +} + +/* Try to change the time so that the scale is maintained */ +static int bu27008_try_set_int_time(struct bu27008_data *data, int int_time_new) +{ + int ret, old_time_sel, new_time_sel, old_gain, new_gain; + + mutex_lock(&data->mutex); + + ret = bu27008_get_int_time_sel(data, &old_time_sel); + if (ret < 0) + goto unlock_out; + + if (!iio_gts_valid_time(&data->gts, int_time_new)) { + dev_dbg(data->dev, "Unsupported integration time %u\n", + int_time_new); + + ret = -EINVAL; + goto unlock_out; + } + + /* If we already use requested time, then we're done */ + new_time_sel = iio_gts_find_sel_by_int_time(&data->gts, int_time_new); + if (new_time_sel == old_time_sel) + goto unlock_out; + + ret = bu27008_get_gain(data, &data->gts, &old_gain); + if (ret) + goto unlock_out; + + ret = iio_gts_find_new_gain_sel_by_old_gain_time(&data->gts, old_gain, + old_time_sel, new_time_sel, &new_gain); + if (ret) { + int scale1, scale2; + bool ok; + + _bu27008_get_scale(data, false, &scale1, &scale2); + dev_dbg(data->dev, + "Can't support time %u with current scale %u %u\n", + int_time_new, scale1, scale2); + + if (new_gain < 0) + goto unlock_out; + + /* + * If caller requests for integration time change and we + * can't support the scale - then the caller should be + * prepared to 'pick up the pieces and deal with the + * fact that the scale changed'. + */ + ret = iio_find_closest_gain_low(&data->gts, new_gain, &ok); + if (!ok) + dev_dbg(data->dev, "optimal gain out of range\n"); + + if (ret < 0) { + dev_dbg(data->dev, + "Total gain increase. Risk of saturation"); + ret = iio_gts_get_min_gain(&data->gts); + if (ret < 0) + goto unlock_out; + } + new_gain = ret; + dev_dbg(data->dev, "scale changed, new gain %u\n", new_gain); + } + + ret = bu27008_set_gain(data, new_gain); + if (ret) + goto unlock_out; + + ret = bu27008_set_int_time(data, int_time_new); + +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bu27008_meas_set(struct bu27008_data *data, int state) +{ + return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3, + BU27008_MASK_MEAS_EN, state); +} + +static int bu27008_chan_cfg(struct bu27008_data *data, + struct iio_chan_spec const *chan) +{ + int chan_sel; + + if (chan->scan_index == BU27008_BLUE) + chan_sel = BU27008_BLUE2_CLEAR3; + else + chan_sel = BU27008_CLEAR2_IR3; + + chan_sel = FIELD_PREP(BU27008_MASK_CHAN_SEL, chan_sel); + + return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3, + BU27008_MASK_CHAN_SEL, chan_sel); +} + +static int bu27008_read_one(struct bu27008_data *data, struct iio_dev *idev, + struct iio_chan_spec const *chan, int *val, int *val2) +{ + int ret, int_time; + + ret = bu27008_chan_cfg(data, chan); + if (ret) + return ret; + + ret = bu27008_meas_set(data, BU27008_MEAS_EN); + if (ret) + return ret; + + ret = bu27008_get_int_time_us(data); + if (ret < 0) + int_time = BU27008_MEAS_TIME_MAX_MS; + else + int_time = ret / USEC_PER_MSEC; + + msleep(int_time); + + ret = bu27008_chan_read_data(data, chan->address, val); + if (!ret) + ret = IIO_VAL_INT; + + if (bu27008_meas_set(data, BU27008_MEAS_DIS)) + dev_warn(data->dev, "measurement disabling failed\n"); + + return ret; +} + +static int bu27008_read_raw(struct iio_dev *idev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bu27008_data *data = iio_priv(idev); + int busy, ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + busy = iio_device_claim_direct_mode(idev); + if (busy) + return -EBUSY; + + mutex_lock(&data->mutex); + ret = bu27008_read_one(data, idev, chan, val, val2); + mutex_unlock(&data->mutex); + + iio_device_release_direct_mode(idev); + + return ret; + + case IIO_CHAN_INFO_SCALE: + ret = bu27008_get_scale(data, chan->scan_index == BU27008_IR, + val, val2); + if (ret) + return ret; + + return IIO_VAL_INT_PLUS_NANO; + + case IIO_CHAN_INFO_INT_TIME: + ret = bu27008_get_int_time_us(data); + if (ret < 0) + return ret; + + *val = 0; + *val2 = ret; + + return IIO_VAL_INT_PLUS_MICRO; + + default: + return -EINVAL; + } +} + +/* Called if the new scale could not be supported with existing int-time */ +static int bu27008_try_find_new_time_gain(struct bu27008_data *data, int val, + int val2, int *gain_sel) +{ + int i, ret, new_time_sel; + + for (i = 0; i < data->gts.num_itime; i++) { + new_time_sel = data->gts.itime_table[i].sel; + ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, + new_time_sel, val, val2 * 1000, gain_sel); + if (!ret) + break; + } + if (i == data->gts.num_itime) { + dev_err(data->dev, "Can't support scale %u %u\n", val, val2); + + return -EINVAL; + } + + return bu27008_set_int_time_sel(data, new_time_sel); +} + +static int bu27008_set_scale(struct bu27008_data *data, + struct iio_chan_spec const *chan, + int val, int val2) +{ + int ret, gain_sel, time_sel; + + if (chan->scan_index == BU27008_IR) + return -EINVAL; + + mutex_lock(&data->mutex); + + ret = bu27008_get_int_time_sel(data, &time_sel); + if (ret < 0) + goto unlock_out; + + ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel, + val, val2 * 1000, &gain_sel); + if (ret) { + ret = bu27008_try_find_new_time_gain(data, val, val2, &gain_sel); + if (ret) + goto unlock_out; + + } + ret = bu27008_write_gain_sel(data, gain_sel); + +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bu27008_write_raw(struct iio_dev *idev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bu27008_data *data = iio_priv(idev); + int ret; + + /* + * Do not allow changing scale when measurement is ongoing as doing so + * could make values in the buffer inconsistent. + */ + ret = iio_device_claim_direct_mode(idev); + if (ret) + return ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + ret = bu27008_set_scale(data, chan, val, val2); + break; + case IIO_CHAN_INFO_INT_TIME: + if (val) { + ret = -EINVAL; + break; + } + ret = bu27008_try_set_int_time(data, val2); + break; + default: + ret = -EINVAL; + break; + } + iio_device_release_direct_mode(idev); + + return ret; +} + +static int bu27008_read_avail(struct iio_dev *idev, + struct iio_chan_spec const *chan, const int **vals, + int *type, int *length, long mask) +{ + struct bu27008_data *data = iio_priv(idev); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + return iio_gts_avail_times(&data->gts, vals, type, length); + case IIO_CHAN_INFO_SCALE: + if (chan->channel2 == IIO_MOD_LIGHT_IR) + return iio_gts_all_avail_scales(&data->gts_ir, vals, + type, length); + return iio_gts_all_avail_scales(&data->gts, vals, type, length); + default: + return -EINVAL; + } +} + +static int bu27008_update_scan_mode(struct iio_dev *idev, + const unsigned long *scan_mask) +{ + struct bu27008_data *data = iio_priv(idev); + int chan_sel; + + /* Configure channel selection */ + if (test_bit(BU27008_BLUE, idev->active_scan_mask)) { + if (test_bit(BU27008_CLEAR, idev->active_scan_mask)) + chan_sel = BU27008_BLUE2_CLEAR3; + else + chan_sel = BU27008_BLUE2_IR3; + } else { + chan_sel = BU27008_CLEAR2_IR3; + } + + chan_sel = FIELD_PREP(BU27008_MASK_CHAN_SEL, chan_sel); + + return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3, + BU27008_MASK_CHAN_SEL, chan_sel); +} + +static const struct iio_info bu27008_info = { + .read_raw = &bu27008_read_raw, + .write_raw = &bu27008_write_raw, + .read_avail = &bu27008_read_avail, + .update_scan_mode = bu27008_update_scan_mode, + .validate_trigger = iio_validate_own_trigger, +}; + +static int bu27008_chip_init(struct bu27008_data *data) +{ + int ret; + + ret = regmap_write_bits(data->regmap, BU27008_REG_SYSTEM_CONTROL, + BU27008_MASK_SW_RESET, BU27008_MASK_SW_RESET); + if (ret) + return dev_err_probe(data->dev, ret, "Sensor reset failed\n"); + + /* + * The data-sheet does not tell how long performing the IC reset takes. + * However, the data-sheet says the minimum time it takes the IC to be + * able to take inputs after power is applied, is 100 uS. I'd assume + * > 1 mS is enough. + */ + msleep(1); + + ret = regmap_reinit_cache(data->regmap, &bu27008_regmap); + if (ret) + dev_err(data->dev, "Failed to reinit reg cache\n"); + + return ret; +} + +static int bu27008_set_drdy_irq(struct bu27008_data *data, int state) +{ + return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3, + BU27008_MASK_INT_EN, state); +} + +static int bu27008_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct bu27008_data *data = iio_trigger_get_drvdata(trig); + int ret; + + if (state) + ret = bu27008_set_drdy_irq(data, BU27008_INT_EN); + else + ret = bu27008_set_drdy_irq(data, BU27008_INT_DIS); + if (ret) + dev_err(data->dev, "Failed to set trigger state\n"); + + return ret; +} + +static void bu27008_trigger_reenable(struct iio_trigger *trig) +{ + struct bu27008_data *data = iio_trigger_get_drvdata(trig); + + enable_irq(data->irq); +} + +static const struct iio_trigger_ops bu27008_trigger_ops = { + .set_trigger_state = bu27008_trigger_set_state, + .reenable = bu27008_trigger_reenable, +}; + +static irqreturn_t bu27008_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *idev = pf->indio_dev; + struct bu27008_data *data = iio_priv(idev); + struct { + __le16 chan[BU27008_NUM_HW_CHANS]; + s64 ts __aligned(8); + } raw; + int ret, dummy; + + memset(&raw, 0, sizeof(raw)); + + /* + * After some measurements, it seems reading the + * BU27008_REG_MODE_CONTROL3 debounces the IRQ line + */ + ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL3, &dummy); + if (ret < 0) + goto err_read; + + ret = regmap_bulk_read(data->regmap, BU27008_REG_DATA0_LO, &raw.chan, + sizeof(raw.chan)); + if (ret < 0) + goto err_read; + + iio_push_to_buffers_with_timestamp(idev, &raw, pf->timestamp); +err_read: + iio_trigger_notify_done(idev->trig); + + return IRQ_HANDLED; +} + +static int bu27008_buffer_preenable(struct iio_dev *idev) +{ + struct bu27008_data *data = iio_priv(idev); + + return bu27008_meas_set(data, BU27008_MEAS_EN); +} + +static int bu27008_buffer_postdisable(struct iio_dev *idev) +{ + struct bu27008_data *data = iio_priv(idev); + + return bu27008_meas_set(data, BU27008_MEAS_DIS); +} + +static const struct iio_buffer_setup_ops bu27008_buffer_ops = { + .preenable = bu27008_buffer_preenable, + .postdisable = bu27008_buffer_postdisable, +}; + +static irqreturn_t bu27008_data_rdy_poll(int irq, void *private) +{ + /* + * The BU27008 keeps IRQ asserted until we read the VALID bit from + * a register. We need to keep the IRQ disabled until then. + */ + disable_irq_nosync(irq); + iio_trigger_poll(private); + + return IRQ_HANDLED; +} + +static int bu27008_setup_trigger(struct bu27008_data *data, struct iio_dev *idev) +{ + struct iio_trigger *itrig; + char *name; + int ret; + + ret = devm_iio_triggered_buffer_setup(data->dev, idev, + &iio_pollfunc_store_time, + bu27008_trigger_handler, + &bu27008_buffer_ops); + if (ret) + return dev_err_probe(data->dev, ret, + "iio_triggered_buffer_setup_ext FAIL\n"); + + itrig = devm_iio_trigger_alloc(data->dev, "%sdata-rdy-dev%d", + idev->name, iio_device_id(idev)); + if (!itrig) + return -ENOMEM; + + data->trig = itrig; + + itrig->ops = &bu27008_trigger_ops; + iio_trigger_set_drvdata(itrig, data); + + name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-bu27008", + dev_name(data->dev)); + + ret = devm_request_irq(data->dev, data->irq, + &bu27008_data_rdy_poll, + 0, name, itrig); + if (ret) + return dev_err_probe(data->dev, ret, "Could not request IRQ\n"); + + ret = devm_iio_trigger_register(data->dev, itrig); + if (ret) + return dev_err_probe(data->dev, ret, + "Trigger registration failed\n"); + + /* set default trigger */ + idev->trig = iio_trigger_get(itrig); + + return 0; +} + +static int bu27008_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct bu27008_data *data; + struct regmap *regmap; + unsigned int part_id, reg; + struct iio_dev *idev; + int ret; + + regmap = devm_regmap_init_i2c(i2c, &bu27008_regmap); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to initialize Regmap\n"); + + idev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!idev) + return -ENOMEM; + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulator\n"); + + data = iio_priv(idev); + + ret = regmap_read(regmap, BU27008_REG_SYSTEM_CONTROL, ®); + if (ret) + return dev_err_probe(dev, ret, "Failed to access sensor\n"); + + part_id = FIELD_GET(BU27008_MASK_PART_ID, reg); + + if (part_id != BU27008_ID) + dev_warn(dev, "unknown device 0x%x\n", part_id); + + ret = devm_iio_init_iio_gts(dev, BU27008_SCALE_1X, 0, bu27008_gains, + ARRAY_SIZE(bu27008_gains), bu27008_itimes, + ARRAY_SIZE(bu27008_itimes), &data->gts); + if (ret) + return ret; + + ret = devm_iio_init_iio_gts(dev, BU27008_SCALE_1X, 0, bu27008_gains_ir, + ARRAY_SIZE(bu27008_gains_ir), bu27008_itimes, + ARRAY_SIZE(bu27008_itimes), &data->gts_ir); + if (ret) + return ret; + + mutex_init(&data->mutex); + data->regmap = regmap; + data->dev = dev; + data->irq = i2c->irq; + + idev->channels = bu27008_channels; + idev->num_channels = ARRAY_SIZE(bu27008_channels); + idev->name = "bu27008"; + idev->info = &bu27008_info; + idev->modes = INDIO_DIRECT_MODE; + idev->available_scan_masks = bu27008_scan_masks; + + ret = bu27008_chip_init(data); + if (ret) + return ret; + + if (i2c->irq) { + ret = bu27008_setup_trigger(data, idev); + if (ret) + return ret; + } else { + dev_info(dev, "No IRQ, buffered mode disabled\n"); + } + + ret = devm_iio_device_register(dev, idev); + if (ret) + return dev_err_probe(dev, ret, + "Unable to register iio device\n"); + + return 0; +} + +static const struct of_device_id bu27008_of_match[] = { + { .compatible = "rohm,bu27008" }, + { } +}; +MODULE_DEVICE_TABLE(of, bu27008_of_match); + +static struct i2c_driver bu27008_i2c_driver = { + .driver = { + .name = "bu27008", + .of_match_table = bu27008_of_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = bu27008_probe, +}; +module_i2c_driver(bu27008_i2c_driver); + +MODULE_DESCRIPTION("ROHM BU27008 colour sensor driver"); +MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_GTS_HELPER); diff --git a/drivers/iio/light/rohm-bu27034.c b/drivers/iio/light/rohm-bu27034.c index f85194fda6b0..e63ef5789cde 100644 --- a/drivers/iio/light/rohm-bu27034.c +++ b/drivers/iio/light/rohm-bu27034.c @@ -1500,8 +1500,9 @@ static struct i2c_driver bu27034_i2c_driver = { .driver = { .name = "bu27034-als", .of_match_table = bu27034_of_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe_new = bu27034_probe, + .probe = bu27034_probe, }; module_i2c_driver(bu27034_i2c_driver); diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 9d0218b7426e..bbb8581622f2 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -1121,7 +1121,7 @@ static struct i2c_driver rpr0521_driver = { .pm = pm_ptr(&rpr0521_pm_ops), .acpi_match_table = ACPI_PTR(rpr0521_acpi_match), }, - .probe_new = rpr0521_probe, + .probe = rpr0521_probe, .remove = rpr0521_remove, .id_table = rpr0521_id, }; diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index a08fbc8f5adb..ea2c437199c0 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -1064,7 +1064,7 @@ static struct i2c_driver si1133_driver = { .driver = { .name = "si1133", }, - .probe_new = si1133_probe, + .probe = si1133_probe, .id_table = si1133_ids, }; diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c index f7126235f94c..77666b780a5c 100644 --- a/drivers/iio/light/si1145.c +++ b/drivers/iio/light/si1145.c @@ -1352,7 +1352,7 @@ static struct i2c_driver si1145_driver = { .driver = { .name = "si1145", }, - .probe_new = si1145_probe, + .probe = si1145_probe, .id_table = si1145_ids, }; diff --git a/drivers/iio/light/st_uvis25_i2c.c b/drivers/iio/light/st_uvis25_i2c.c index 2160e87bb498..6bc2ddfb77ca 100644 --- a/drivers/iio/light/st_uvis25_i2c.c +++ b/drivers/iio/light/st_uvis25_i2c.c @@ -57,7 +57,7 @@ static struct i2c_driver st_uvis25_driver = { .pm = pm_sleep_ptr(&st_uvis25_pm_ops), .of_match_table = st_uvis25_i2c_of_match, }, - .probe_new = st_uvis25_i2c_probe, + .probe = st_uvis25_i2c_probe, .id_table = st_uvis25_i2c_id_table, }; module_i2c_driver(st_uvis25_driver); diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 48ae6ff0015e..72b08d870d33 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -714,7 +714,7 @@ static struct i2c_driver stk3310_driver = { .pm = pm_sleep_ptr(&stk3310_pm_ops), .acpi_match_table = ACPI_PTR(stk3310_acpi_id), }, - .probe_new = stk3310_probe, + .probe = stk3310_probe, .remove = stk3310_remove, .id_table = stk3310_i2c_id, }; diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index 5100732fbaf0..dcdd85b006be 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -373,7 +373,7 @@ static struct i2c_driver tcs3414_driver = { .name = TCS3414_DRV_NAME, .pm = pm_sleep_ptr(&tcs3414_pm_ops), }, - .probe_new = tcs3414_probe, + .probe = tcs3414_probe, .id_table = tcs3414_id, }; module_i2c_driver(tcs3414_driver); diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 6187c5487916..75fcf2c93717 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -609,7 +609,7 @@ static struct i2c_driver tcs3472_driver = { .name = TCS3472_DRV_NAME, .pm = pm_sleep_ptr(&tcs3472_pm_ops), }, - .probe_new = tcs3472_probe, + .probe = tcs3472_probe, .remove = tcs3472_remove, .id_table = tcs3472_id, }; diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index f2f55239a072..1a6f514bced6 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -862,7 +862,7 @@ static struct i2c_driver tsl2563_i2c_driver = { .of_match_table = tsl2563_of_match, .pm = pm_sleep_ptr(&tsl2563_pm_ops), }, - .probe_new = tsl2563_probe, + .probe = tsl2563_probe, .remove = tsl2563_remove, .id_table = tsl2563_id, }; diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c index a05f1c0453d1..02ad11611b9c 100644 --- a/drivers/iio/light/tsl2583.c +++ b/drivers/iio/light/tsl2583.c @@ -942,7 +942,7 @@ static struct i2c_driver tsl2583_driver = { .of_match_table = tsl2583_of_match, }, .id_table = tsl2583_idtable, - .probe_new = tsl2583_probe, + .probe = tsl2583_probe, .remove = tsl2583_remove, }; module_i2c_driver(tsl2583_driver); diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c index e485a556e6da..7bdbfe72f0f0 100644 --- a/drivers/iio/light/tsl2591.c +++ b/drivers/iio/light/tsl2591.c @@ -1214,7 +1214,7 @@ static struct i2c_driver tsl2591_driver = { .pm = pm_ptr(&tsl2591_pm_ops), .of_match_table = tsl2591_of_match, }, - .probe_new = tsl2591_probe + .probe = tsl2591_probe }; module_i2c_driver(tsl2591_driver); diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index e823c145f679..cab468a82b61 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -1932,7 +1932,7 @@ static struct i2c_driver tsl2772_driver = { .pm = &tsl2772_pm_ops, }, .id_table = tsl2772_idtable, - .probe_new = tsl2772_probe, + .probe = tsl2772_probe, }; module_i2c_driver(tsl2772_driver); diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c index d95397eb1526..4da7d78906d4 100644 --- a/drivers/iio/light/tsl4531.c +++ b/drivers/iio/light/tsl4531.c @@ -237,7 +237,7 @@ static struct i2c_driver tsl4531_driver = { .name = TSL4531_DRV_NAME, .pm = pm_sleep_ptr(&tsl4531_pm_ops), }, - .probe_new = tsl4531_probe, + .probe = tsl4531_probe, .remove = tsl4531_remove, .id_table = tsl4531_id, }; diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index 8b2a0c99c8e6..61b3b2aea626 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -974,7 +974,7 @@ static struct i2c_driver us5182d_driver = { .of_match_table = us5182d_of_match, .acpi_match_table = ACPI_PTR(us5182d_acpi_match), }, - .probe_new = us5182d_probe, + .probe = us5182d_probe, .remove = us5182d_remove, .id_table = us5182d_id, diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 56d3963d3d66..7c7362e28821 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1500,7 +1500,7 @@ static struct i2c_driver vcnl4000_driver = { .pm = pm_ptr(&vcnl4000_pm_ops), .of_match_table = vcnl_4000_of_match, }, - .probe_new = vcnl4000_probe, + .probe = vcnl4000_probe, .id_table = vcnl4000_id, .remove = vcnl4000_remove, }; diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 94f5d611e98c..56bbefbc0ae6 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -670,7 +670,7 @@ static struct i2c_driver vcnl4035_driver = { .pm = pm_ptr(&vcnl4035_pm_ops), .of_match_table = vcnl4035_of_match, }, - .probe_new = vcnl4035_probe, + .probe = vcnl4035_probe, .remove = vcnl4035_remove, .id_table = vcnl4035_id, }; diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c index e7d2d5d177d4..043f233d9bdb 100644 --- a/drivers/iio/light/veml6030.c +++ b/drivers/iio/light/veml6030.c @@ -892,7 +892,7 @@ static struct i2c_driver veml6030_driver = { .of_match_table = veml6030_of_match, .pm = pm_ptr(&veml6030_pm_ops), }, - .probe_new = veml6030_probe, + .probe = veml6030_probe, .id_table = veml6030_id, }; module_i2c_driver(veml6030_driver); diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c index ee76a68deb24..d99bf3ae0fe8 100644 --- a/drivers/iio/light/veml6070.c +++ b/drivers/iio/light/veml6070.c @@ -198,7 +198,7 @@ static struct i2c_driver veml6070_driver = { .driver = { .name = VEML6070_DRV_NAME, }, - .probe_new = veml6070_probe, + .probe = veml6070_probe, .remove = veml6070_remove, .id_table = veml6070_id, }; diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index 8b56df26c59e..d4948dfc31ff 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -538,7 +538,7 @@ static struct i2c_driver vl6180_driver = { .name = VL6180_DRV_NAME, .of_match_table = vl6180_of_match, }, - .probe_new = vl6180_probe, + .probe = vl6180_probe, .id_table = vl6180_id, }; diff --git a/drivers/iio/light/zopt2201.c b/drivers/iio/light/zopt2201.c index e3bac8b56380..d370193a4742 100644 --- a/drivers/iio/light/zopt2201.c +++ b/drivers/iio/light/zopt2201.c @@ -554,7 +554,7 @@ static struct i2c_driver zopt2201_driver = { .driver = { .name = ZOPT2201_DRV_NAME, }, - .probe_new = zopt2201_probe, + .probe = zopt2201_probe, .id_table = zopt2201_id, }; |