diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-07-03 12:46:47 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-07-03 12:46:47 -0700 |
commit | 44aeec836da880c73a8deb2c7735c6e7c36f47c3 (patch) | |
tree | 52dc7a419c35124536373bd5025a74fb023680c3 /drivers/iio | |
parent | 0a8d6c9c7128a93689fba384cdd7f72b0ce19abd (diff) | |
parent | adfdaf81f9d48d8618a4d8296567248170fe7bcc (diff) | |
download | linux-44aeec836da880c73a8deb2c7735c6e7c36f47c3.tar.gz linux-44aeec836da880c73a8deb2c7735c6e7c36f47c3.tar.bz2 linux-44aeec836da880c73a8deb2c7735c6e7c36f47c3.zip |
Merge tag 'char-misc-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull Char/Misc updates from Greg KH:
"Here is the big set of char/misc and other driver subsystem updates
for 6.5-rc1.
Lots of different, tiny, stuff in here, from a range of smaller driver
subsystems, including pulls from some substems directly:
- IIO driver updates and additions
- W1 driver updates and fixes (and a new maintainer!)
- FPGA driver updates and fixes
- Counter driver updates
- Extcon driver updates
- Interconnect driver updates
- Coresight driver updates
- mfd tree tag merge needed for other updates on top of that, lots of
small driver updates as patches, including:
- static const updates for class structures
- nvmem driver updates
- pcmcia driver fix
- lots of other small driver updates and fixes
All of these have been in linux-next for a while with no reported
problems"
* tag 'char-misc-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (243 commits)
bsr: fix build problem with bsr_class static cleanup
comedi: make all 'class' structures const
char: xillybus: make xillybus_class a static const structure
xilinx_hwicap: make icap_class a static const structure
virtio_console: make port class a static const structure
ppdev: make ppdev_class a static const structure
char: misc: make misc_class a static const structure
/dev/mem: make mem_class a static const structure
char: lp: make lp_class a static const structure
dsp56k: make dsp56k_class a static const structure
bsr: make bsr_class a static const structure
oradax: make 'cl' a static const structure
hwtracing: hisi_ptt: Fix potential sleep in atomic context
hwtracing: hisi_ptt: Advertise PERF_PMU_CAP_NO_EXCLUDE for PTT PMU
hwtracing: hisi_ptt: Export available filters through sysfs
hwtracing: hisi_ptt: Add support for dynamically updating the filter list
hwtracing: hisi_ptt: Factor out filter allocation and release operation
samples: pfsm: add CC_CAN_LINK dependency
misc: fastrpc: check return value of devm_kasprintf()
coresight: dummy: Update type of mode parameter in dummy_{sink,source}_enable()
...
Diffstat (limited to 'drivers/iio')
226 files changed, 2936 insertions, 467 deletions
diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c index 99cc7fc29488..524327ea3663 100644 --- a/drivers/iio/accel/adxl313_i2c.c +++ b/drivers/iio/accel/adxl313_i2c.c @@ -85,7 +85,7 @@ static struct i2c_driver adxl313_i2c_driver = { .name = "adxl313_i2c", .of_match_table = adxl313_of_match, }, - .probe_new = adxl313_i2c_probe, + .probe = adxl313_i2c_probe, .id_table = adxl313_i2c_id, }; diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index 098cd83f95b2..e47d12f19602 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -56,7 +56,7 @@ static struct i2c_driver adxl345_i2c_driver = { .of_match_table = adxl345_of_match, .acpi_match_table = adxl345_acpi_match, }, - .probe_new = adxl345_i2c_probe, + .probe = adxl345_i2c_probe, .id_table = adxl345_i2c_id, }; module_i2c_driver(adxl345_i2c_driver); diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c index 6cde5ccac06b..d5beea61479d 100644 --- a/drivers/iio/accel/adxl355_i2c.c +++ b/drivers/iio/accel/adxl355_i2c.c @@ -68,7 +68,7 @@ static struct i2c_driver adxl355_i2c_driver = { .name = "adxl355_i2c", .of_match_table = adxl355_of_match, }, - .probe_new = adxl355_i2c_probe, + .probe = adxl355_i2c_probe, .id_table = adxl355_i2c_id, }; module_i2c_driver(adxl355_i2c_driver); diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c index 070aad724abd..b595fe94f3a3 100644 --- a/drivers/iio/accel/adxl367_i2c.c +++ b/drivers/iio/accel/adxl367_i2c.c @@ -77,7 +77,7 @@ static struct i2c_driver adxl367_i2c_driver = { .name = "adxl367_i2c", .of_match_table = adxl367_of_match, }, - .probe_new = adxl367_i2c_probe, + .probe = adxl367_i2c_probe, .id_table = adxl367_i2c_id, }; diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c index e5f310ea65ff..d0690417fd36 100644 --- a/drivers/iio/accel/adxl372_i2c.c +++ b/drivers/iio/accel/adxl372_i2c.c @@ -58,7 +58,7 @@ static struct i2c_driver adxl372_i2c_driver = { .name = "adxl372_i2c", .of_match_table = adxl372_of_match, }, - .probe_new = adxl372_i2c_probe, + .probe = adxl372_i2c_probe, .id_table = adxl372_i2c_id, }; diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index eb697eeb4301..e8ab0d249351 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -1134,7 +1134,7 @@ static struct i2c_driver bma180_driver = { .pm = pm_sleep_ptr(&bma180_pm_ops), .of_match_table = bma180_of_match, }, - .probe_new = bma180_probe, + .probe = bma180_probe, .remove = bma180_remove, .id_table = bma180_ids, }; diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index a68b845f5b4f..e90e2f01550a 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -868,8 +868,7 @@ static int bma400_init(struct bma400_data *data) ARRAY_SIZE(regulator_names), regulator_names); if (ret) - return dev_err_probe(data->dev, ret, "Failed to get regulators: %d\n", - ret); + return dev_err_probe(data->dev, ret, "Failed to get regulators\n"); /* Try to read chip_id register. It must return 0x90. */ ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val); diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c index 688b06dae669..adf4e3fd2e1d 100644 --- a/drivers/iio/accel/bma400_i2c.c +++ b/drivers/iio/accel/bma400_i2c.c @@ -44,7 +44,7 @@ static struct i2c_driver bma400_i2c_driver = { .name = "bma400", .of_match_table = bma400_of_i2c_match, }, - .probe_new = bma400_i2c_probe, + .probe = bma400_i2c_probe, .id_table = bma400_i2c_ids, }; diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c index 509cab2bd694..ee1ba134ad42 100644 --- a/drivers/iio/accel/bmc150-accel-i2c.c +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -269,7 +269,7 @@ static struct i2c_driver bmc150_accel_driver = { .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), .pm = &bmc150_accel_pm_ops, }, - .probe_new = bmc150_accel_probe, + .probe = bmc150_accel_probe, .remove = bmc150_accel_remove, .id_table = bmc150_accel_id, }; diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c index 38a7d811610e..2f27a5ded94c 100644 --- a/drivers/iio/accel/da280.c +++ b/drivers/iio/accel/da280.c @@ -184,7 +184,7 @@ static struct i2c_driver da280_driver = { .acpi_match_table = ACPI_PTR(da280_acpi_match), .pm = pm_sleep_ptr(&da280_pm_ops), }, - .probe_new = da280_probe, + .probe = da280_probe, .id_table = da280_i2c_id, }; diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c index 080335fa2ad6..8f919920ced5 100644 --- a/drivers/iio/accel/da311.c +++ b/drivers/iio/accel/da311.c @@ -278,7 +278,7 @@ static struct i2c_driver da311_driver = { .name = "da311", .pm = pm_sleep_ptr(&da311_pm_ops), }, - .probe_new = da311_probe, + .probe = da311_probe, .id_table = da311_i2c_id, }; diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c index 7390509aaac0..2e719d60fff8 100644 --- a/drivers/iio/accel/dmard06.c +++ b/drivers/iio/accel/dmard06.c @@ -217,7 +217,7 @@ static const struct of_device_id dmard06_of_match[] = { MODULE_DEVICE_TABLE(of, dmard06_of_match); static struct i2c_driver dmard06_driver = { - .probe_new = dmard06_probe, + .probe = dmard06_probe, .id_table = dmard06_id, .driver = { .name = DMARD06_DRV_NAME, diff --git a/drivers/iio/accel/dmard09.c b/drivers/iio/accel/dmard09.c index 4b7a537f617d..fa98623de579 100644 --- a/drivers/iio/accel/dmard09.c +++ b/drivers/iio/accel/dmard09.c @@ -135,7 +135,7 @@ static struct i2c_driver dmard09_driver = { .driver = { .name = DMARD09_DRV_NAME }, - .probe_new = dmard09_probe, + .probe = dmard09_probe, .id_table = dmard09_id, }; diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c index 07e68aed8a13..7745b6ffd1ad 100644 --- a/drivers/iio/accel/dmard10.c +++ b/drivers/iio/accel/dmard10.c @@ -241,7 +241,7 @@ static struct i2c_driver dmard10_driver = { .name = "dmard10", .pm = pm_sleep_ptr(&dmard10_pm_ops), }, - .probe_new = dmard10_probe, + .probe = dmard10_probe, .id_table = dmard10_i2c_id, }; diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 0d672b1469e8..be8a15cb945f 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -724,8 +724,7 @@ static const struct iio_event_spec fxls8962af_event[] = { .sign = 's', \ .realbits = 12, \ .storagebits = 16, \ - .shift = 4, \ - .endianness = IIO_BE, \ + .endianness = IIO_LE, \ }, \ .event_spec = fxls8962af_event, \ .num_event_specs = ARRAY_SIZE(fxls8962af_event), \ @@ -904,9 +903,10 @@ static int fxls8962af_fifo_transfer(struct fxls8962af_data *data, int total_length = samples * sample_length; int ret; - if (i2c_verify_client(dev)) + if (i2c_verify_client(dev) && + data->chip_info->chip_id == FXLS8962AF_DEVICE_ID) /* - * Due to errata bug: + * Due to errata bug (only applicable on fxls8962af): * E3: FIFO burst read operation error using I2C interface * We have to avoid burst reads on I2C.. */ diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c index 22640eaebac7..160124673308 100644 --- a/drivers/iio/accel/fxls8962af-i2c.c +++ b/drivers/iio/accel/fxls8962af-i2c.c @@ -47,7 +47,7 @@ static struct i2c_driver fxls8962af_driver = { .of_match_table = fxls8962af_of_match, .pm = pm_ptr(&fxls8962af_pm_ops), }, - .probe_new = fxls8962af_probe, + .probe = fxls8962af_probe, .id_table = fxls8962af_id, }; module_i2c_driver(fxls8962af_driver); diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c index e6fd02d931b6..b0ac78e85dad 100644 --- a/drivers/iio/accel/kionix-kx022a-i2c.c +++ b/drivers/iio/accel/kionix-kx022a-i2c.c @@ -40,8 +40,9 @@ static struct i2c_driver kx022a_i2c_driver = { .driver = { .name = "kx022a-i2c", .of_match_table = kx022a_of_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe_new = kx022a_i2c_probe, + .probe = kx022a_i2c_probe, }; module_i2c_driver(kx022a_i2c_driver); diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c index 9cd047f7b346..f45a46899a5f 100644 --- a/drivers/iio/accel/kionix-kx022a-spi.c +++ b/drivers/iio/accel/kionix-kx022a-spi.c @@ -46,6 +46,7 @@ static struct spi_driver kx022a_spi_driver = { .driver = { .name = "kx022a-spi", .of_match_table = kx022a_of_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = kx022a_spi_probe, .id_table = kx022a_id, diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index b8636fa8eaeb..4ea3c6718ed4 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -516,17 +516,6 @@ static int kx022a_read_raw(struct iio_dev *idev, return -EINVAL; }; -static int kx022a_validate_trigger(struct iio_dev *idev, - struct iio_trigger *trig) -{ - struct kx022a_data *data = iio_priv(idev); - - if (data->trig != trig) - return -EINVAL; - - return 0; -} - static int kx022a_set_watermark(struct iio_dev *idev, unsigned int val) { struct kx022a_data *data = iio_priv(idev); @@ -725,7 +714,7 @@ static const struct iio_info kx022a_info = { .write_raw = &kx022a_write_raw, .read_avail = &kx022a_read_avail, - .validate_trigger = kx022a_validate_trigger, + .validate_trigger = iio_validate_own_trigger, .hwfifo_set_watermark = kx022a_set_watermark, .hwfifo_flush_to_buffer = kx022a_fifo_flush, }; diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 98da4bda22df..894709286b0c 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1732,7 +1732,7 @@ static struct i2c_driver kxcjk1013_driver = { .of_match_table = kxcjk1013_of_match, .pm = &kxcjk1013_pm_ops, }, - .probe_new = kxcjk1013_probe, + .probe = kxcjk1013_probe, .remove = kxcjk1013_remove, .id_table = kxcjk1013_id, }; diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c index 6b3683ddce36..3bc9ee1f9db3 100644 --- a/drivers/iio/accel/kxsd9-i2c.c +++ b/drivers/iio/accel/kxsd9-i2c.c @@ -54,7 +54,7 @@ static struct i2c_driver kxsd9_i2c_driver = { .of_match_table = kxsd9_of_match, .pm = pm_ptr(&kxsd9_dev_pm_ops), }, - .probe_new = kxsd9_i2c_probe, + .probe = kxsd9_i2c_probe, .remove = kxsd9_i2c_remove, .id_table = kxsd9_i2c_id, }; diff --git a/drivers/iio/accel/mc3230.c b/drivers/iio/accel/mc3230.c index efc21871de42..6b87c2c9945c 100644 --- a/drivers/iio/accel/mc3230.c +++ b/drivers/iio/accel/mc3230.c @@ -190,7 +190,7 @@ static struct i2c_driver mc3230_driver = { .name = "mc3230", .pm = pm_sleep_ptr(&mc3230_pm_ops), }, - .probe_new = mc3230_probe, + .probe = mc3230_probe, .remove = mc3230_remove, .id_table = mc3230_i2c_id, }; diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c index a3864dbe2761..14f7850a22f0 100644 --- a/drivers/iio/accel/mma7455_i2c.c +++ b/drivers/iio/accel/mma7455_i2c.c @@ -46,7 +46,7 @@ static const struct of_device_id mma7455_of_match[] = { MODULE_DEVICE_TABLE(of, mma7455_of_match); static struct i2c_driver mma7455_i2c_driver = { - .probe_new = mma7455_i2c_probe, + .probe = mma7455_i2c_probe, .remove = mma7455_i2c_remove, .id_table = mma7455_i2c_ids, .driver = { diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index b279ca4dcdc0..260cbceaa151 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -266,7 +266,7 @@ static struct i2c_driver mma7660_driver = { .of_match_table = mma7660_of_match, .acpi_match_table = mma7660_acpi_id, }, - .probe_new = mma7660_probe, + .probe = mma7660_probe, .remove = mma7660_remove, .id_table = mma7660_i2c_id, }; diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index ea14e3aaa30a..6e7399e72221 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1846,7 +1846,7 @@ static struct i2c_driver mma8452_driver = { .of_match_table = mma8452_dt_ids, .pm = &mma8452_pm_ops, }, - .probe_new = mma8452_probe, + .probe = mma8452_probe, .remove = mma8452_remove, .id_table = mma8452_id, }; diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index aa4f5842859e..d823f2edc6d4 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -607,7 +607,7 @@ static struct i2c_driver mma9551_driver = { .acpi_match_table = ACPI_PTR(mma9551_acpi_match), .pm = pm_ptr(&mma9551_pm_ops), }, - .probe_new = mma9551_probe, + .probe = mma9551_probe, .remove = mma9551_remove, .id_table = mma9551_id, }; diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 0af578ef9d3d..d01aba4aecba 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1246,7 +1246,7 @@ static struct i2c_driver mma9553_driver = { .acpi_match_table = ACPI_PTR(mma9553_acpi_match), .pm = pm_ptr(&mma9553_pm_ops), }, - .probe_new = mma9553_probe, + .probe = mma9553_probe, .remove = mma9553_remove, .id_table = mma9553_id, }; diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index 6690fa37da8f..6ddcc3c2f840 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -1294,7 +1294,7 @@ static struct i2c_driver msa311_driver = { .of_match_table = msa311_of_match, .pm = pm_ptr(&msa311_pm_ops), }, - .probe_new = msa311_probe, + .probe = msa311_probe, .id_table = msa311_i2c_id, }; module_i2c_driver(msa311_driver); diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index b146fc82738f..75d142bc14b4 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -488,7 +488,7 @@ static struct i2c_driver mxc4005_driver = { .name = MXC4005_DRV_NAME, .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), }, - .probe_new = mxc4005_probe, + .probe = mxc4005_probe, .id_table = mxc4005_id, }; diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c index aa2e660545f8..33c2253561e6 100644 --- a/drivers/iio/accel/mxc6255.c +++ b/drivers/iio/accel/mxc6255.c @@ -183,7 +183,7 @@ static struct i2c_driver mxc6255_driver = { .name = MXC6255_DRV_NAME, .acpi_match_table = ACPI_PTR(mxc6255_acpi_match), }, - .probe_new = mxc6255_probe, + .probe = mxc6255_probe, .id_table = mxc6255_id, }; diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 282e539157f8..d2104e14e255 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -1007,6 +1007,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM9DS0_IMU_DEV_NAME, + [1] = LSM303D_IMU_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_accel_16bit_channels, .odr = { diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index fb9e2d6f4210..71ee861b2980 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -206,7 +206,7 @@ static struct i2c_driver st_accel_driver = { .of_match_table = st_accel_of_match, .acpi_match_table = ACPI_PTR(st_accel_acpi_match), }, - .probe_new = st_accel_i2c_probe, + .probe = st_accel_i2c_probe, .id_table = st_accel_id_table, }; module_i2c_driver(st_accel_driver); diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 68f680db7505..ef0ae7672253 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -644,7 +644,7 @@ static struct i2c_driver stk8312_driver = { .name = STK8312_DRIVER_NAME, .pm = pm_sleep_ptr(&stk8312_pm_ops), }, - .probe_new = stk8312_probe, + .probe = stk8312_probe, .remove = stk8312_remove, .id_table = stk8312_i2c_id, }; diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 44f6e0fbdfcc..3415ac1b4495 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -543,7 +543,7 @@ static struct i2c_driver stk8ba50_driver = { .pm = pm_sleep_ptr(&stk8ba50_pm_ops), .acpi_match_table = ACPI_PTR(stk8ba50_acpi_id), }, - .probe_new = stk8ba50_probe, + .probe = stk8ba50_probe, .remove = stk8ba50_remove, .id_table = stk8ba50_i2c_id, }; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 08b8f27afbbf..dc14bde31ac1 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -145,7 +145,7 @@ config AD7606 config AD7606_IFACE_PARALLEL tristate "Analog Devices AD7606 ADC driver with parallel interface support" - depends on HAS_IOMEM + depends on HAS_IOPORT select AD7606 help Say yes here to build parallel interface support for Analog Devices: diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c index 7d6709da1005..2f048527b7b7 100644 --- a/drivers/iio/adc/ad7091r5.c +++ b/drivers/iio/adc/ad7091r5.c @@ -103,7 +103,7 @@ static struct i2c_driver ad7091r5_driver = { .name = "ad7091r5", .of_match_table = ad7091r5_dt_ids, }, - .probe_new = ad7091r5_i2c_probe, + .probe = ad7091r5_i2c_probe, .id_table = ad7091r5_i2c_ids, }; module_i2c_driver(ad7091r5_driver); diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 99bb604b78c8..8685e0b58a83 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -367,7 +367,7 @@ static int ad7192_of_clock_select(struct ad7192_state *st) clock_sel = AD7192_CLK_INT; /* use internal clock */ - if (st->mclk) { + if (!st->mclk) { if (of_property_read_bool(np, "adi,int-clock-output-enable")) clock_sel = AD7192_CLK_INT_CO; } else { @@ -380,9 +380,9 @@ static int ad7192_of_clock_select(struct ad7192_state *st) return clock_sel; } -static int ad7192_setup(struct ad7192_state *st, struct device_node *np) +static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np) { - struct iio_dev *indio_dev = spi_get_drvdata(st->sd.spi); + struct ad7192_state *st = iio_priv(indio_dev); bool rej60_en, refin2_en; bool buf_en, bipolar, burnout_curr_en; unsigned long long scale_uv; @@ -1069,7 +1069,7 @@ static int ad7192_probe(struct spi_device *spi) } } - ret = ad7192_setup(st, spi->dev.of_node); + ret = ad7192_setup(indio_dev, spi->dev.of_node); if (ret) return ret; diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c index f9ee189925de..14d02b085d3b 100644 --- a/drivers/iio/adc/ad7291.c +++ b/drivers/iio/adc/ad7291.c @@ -553,7 +553,7 @@ static struct i2c_driver ad7291_driver = { .name = KBUILD_MODNAME, .of_match_table = ad7291_of_match, }, - .probe_new = ad7291_probe, + .probe = ad7291_probe, .id_table = ad7291_id, }; module_i2c_driver(ad7291_driver); diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 8f0a3a35e727..b757cc45c4de 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -968,7 +968,7 @@ static struct i2c_driver ad799x_driver = { .name = "ad799x", .pm = pm_sleep_ptr(&ad799x_pm_ops), }, - .probe_new = ad799x_probe, + .probe = ad799x_probe, .remove = ad799x_remove, .id_table = ad799x_id, }; diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 38d9d7b2313e..213526c1592f 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -1090,7 +1090,7 @@ static struct i2c_driver ina2xx_driver = { .name = KBUILD_MODNAME, .of_match_table = ina2xx_of_match, }, - .probe_new = ina2xx_probe, + .probe = ina2xx_probe, .remove = ina2xx_remove, .id_table = ina2xx_id, }; diff --git a/drivers/iio/adc/ltc2471.c b/drivers/iio/adc/ltc2471.c index eeb2945829eb..97c417c3a4eb 100644 --- a/drivers/iio/adc/ltc2471.c +++ b/drivers/iio/adc/ltc2471.c @@ -146,7 +146,7 @@ static struct i2c_driver ltc2471_i2c_driver = { .driver = { .name = "ltc2471", }, - .probe_new = ltc2471_i2c_probe, + .probe = ltc2471_i2c_probe, .id_table = ltc2471_i2c_id, }; diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c index 6a23427344ec..859e4314cfa2 100644 --- a/drivers/iio/adc/ltc2485.c +++ b/drivers/iio/adc/ltc2485.c @@ -133,7 +133,7 @@ static struct i2c_driver ltc2485_driver = { .driver = { .name = "ltc2485", }, - .probe_new = ltc2485_probe, + .probe = ltc2485_probe, .id_table = ltc2485_id, }; module_i2c_driver(ltc2485_driver); diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c index ec198c6f13d6..5bdd40729611 100644 --- a/drivers/iio/adc/ltc2497.c +++ b/drivers/iio/adc/ltc2497.c @@ -163,7 +163,7 @@ static struct i2c_driver ltc2497_driver = { .name = "ltc2497", .of_match_table = ltc2497_of_match, }, - .probe_new = ltc2497_probe, + .probe = ltc2497_probe, .remove = ltc2497_remove, .id_table = ltc2497_id, }; diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 73b783b430d7..b31581616ce3 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1718,7 +1718,7 @@ static struct i2c_driver max1363_driver = { .name = "max1363", .of_match_table = max1363_of_match, }, - .probe_new = max1363_probe, + .probe = max1363_probe, .id_table = max1363_id, }; module_i2c_driver(max1363_driver); diff --git a/drivers/iio/adc/max9611.c b/drivers/iio/adc/max9611.c index cb7f4785423a..76e517b7b1e4 100644 --- a/drivers/iio/adc/max9611.c +++ b/drivers/iio/adc/max9611.c @@ -556,7 +556,7 @@ static struct i2c_driver max9611_driver = { .name = DRIVER_NAME, .of_match_table = max9611_of_table, }, - .probe_new = max9611_probe, + .probe = max9611_probe, }; module_i2c_driver(max9611_driver); diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index ada844c3f7ec..0778a8fb6866 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -417,7 +417,7 @@ static struct i2c_driver mcp3422_driver = { .name = "mcp3422", .of_match_table = mcp3422_of_match, }, - .probe_new = mcp3422_probe, + .probe = mcp3422_probe, .id_table = mcp3422_id, }; module_i2c_driver(mcp3422_driver); diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 18937a262af6..af6bfcc19075 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -72,7 +72,7 @@ #define MESON_SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK GENMASK(20, 18) #define MESON_SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK GENMASK(17, 16) #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT 10 - #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH 5 + #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH 6 #define MESON_SAR_ADC_REG3_BLOCK_DLY_SEL_MASK GENMASK(9, 8) #define MESON_SAR_ADC_REG3_BLOCK_DLY_MASK GENMASK(7, 0) diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c index c1261ecd400c..d9e1696df7ae 100644 --- a/drivers/iio/adc/nau7802.c +++ b/drivers/iio/adc/nau7802.c @@ -544,7 +544,7 @@ static const struct of_device_id nau7802_dt_ids[] = { MODULE_DEVICE_TABLE(of, nau7802_dt_ids); static struct i2c_driver nau7802_driver = { - .probe_new = nau7802_probe, + .probe = nau7802_probe, .id_table = nau7802_i2c_id, .driver = { .name = "nau7802", diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 7dfc9c927a23..27b2632c1037 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -14,7 +14,6 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/delay.h> -#include <linux/i2c.h> #include <linux/pm.h> #include <linux/mfd/palmas.h> #include <linux/completion.h> diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index c2d5e06f137a..0a4fd3a46113 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -114,7 +114,7 @@ enum adc5_cal_val { * that is an average of multiple measurements. * @scale_fn_type: Represents the scaling function to convert voltage * physical units desired by the client for the channel. - * @datasheet_name: Channel name used in device tree. + * @channel_name: Channel name used in device tree. */ struct adc5_channel_prop { unsigned int channel; @@ -126,7 +126,7 @@ struct adc5_channel_prop { unsigned int hw_settle_time; unsigned int avg_samples; enum vadc_scale_fn_type scale_fn_type; - const char *datasheet_name; + const char *channel_name; }; /** @@ -657,8 +657,7 @@ static int adc5_get_fw_channel_data(struct adc5_chip *adc, chan = chan & ADC_CHANNEL_MASK; } - if (chan > ADC5_PARALLEL_ISENSE_VBAT_IDATA || - !data->adc_chans[chan].datasheet_name) { + if (chan > ADC5_PARALLEL_ISENSE_VBAT_IDATA) { dev_err(dev, "%s invalid channel number %d\n", name, chan); return -EINVAL; } @@ -669,9 +668,9 @@ static int adc5_get_fw_channel_data(struct adc5_chip *adc, ret = fwnode_property_read_string(fwnode, "label", &channel_name); if (ret) - channel_name = name; + channel_name = data->adc_chans[chan].datasheet_name; - prop->datasheet_name = channel_name; + prop->channel_name = channel_name; ret = fwnode_property_read_u32(fwnode, "qcom,decimation", &value); if (!ret) { @@ -861,8 +860,8 @@ static int adc5_get_fw_data(struct adc5_chip *adc) adc_chan = &adc->data->adc_chans[prop.channel]; iio_chan->channel = prop.channel; - iio_chan->datasheet_name = prop.datasheet_name; - iio_chan->extend_name = prop.datasheet_name; + iio_chan->datasheet_name = adc_chan->datasheet_name; + iio_chan->extend_name = prop.channel_name; iio_chan->info_mask_separate = adc_chan->info_mask; iio_chan->type = adc_chan->type; iio_chan->address = index; diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c index bcff0f62b70e..f5c6f1f27b2c 100644 --- a/drivers/iio/adc/qcom-spmi-vadc.c +++ b/drivers/iio/adc/qcom-spmi-vadc.c @@ -84,6 +84,7 @@ * that is an average of multiple measurements. * @scale_fn_type: Represents the scaling function to convert voltage * physical units desired by the client for the channel. + * @channel_name: Channel name used in device tree. */ struct vadc_channel_prop { unsigned int channel; @@ -93,6 +94,7 @@ struct vadc_channel_prop { unsigned int hw_settle_time; unsigned int avg_samples; enum vadc_scale_fn_type scale_fn_type; + const char *channel_name; }; /** @@ -495,8 +497,18 @@ static int vadc_fwnode_xlate(struct iio_dev *indio_dev, return -EINVAL; } +static int vadc_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, char *label) +{ + struct vadc_priv *vadc = iio_priv(indio_dev); + const char *name = vadc->chan_props[chan->address].channel_name; + + return sysfs_emit(label, "%s\n", name); +} + static const struct iio_info vadc_info = { .read_raw = vadc_read_raw, + .read_label = vadc_read_label, .fwnode_xlate = vadc_fwnode_xlate, }; @@ -652,7 +664,7 @@ static int vadc_get_fw_channel_data(struct device *dev, struct vadc_channel_prop *prop, struct fwnode_handle *fwnode) { - const char *name = fwnode_get_name(fwnode); + const char *name = fwnode_get_name(fwnode), *label; u32 chan, value, varr[2]; int ret; @@ -667,6 +679,11 @@ static int vadc_get_fw_channel_data(struct device *dev, return -EINVAL; } + ret = fwnode_property_read_string(fwnode, "label", &label); + if (ret) + label = vadc_chans[chan].datasheet_name; + prop->channel_name = label; + /* the channel has DT description */ prop->channel = chan; diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index 79448c5ffc2a..4b011f7eddec 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -4,6 +4,7 @@ * Copyright (C) 2014 ROCKCHIP, Inc. */ +#include <linux/bitfield.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> @@ -38,10 +39,31 @@ #define SARADC_TIMEOUT msecs_to_jiffies(100) #define SARADC_MAX_CHANNELS 8 +/* v2 registers */ +#define SARADC2_CONV_CON 0x000 +#define SARADC_T_PD_SOC 0x004 +#define SARADC_T_DAS_SOC 0x00c +#define SARADC2_END_INT_EN 0x104 +#define SARADC2_ST_CON 0x108 +#define SARADC2_STATUS 0x10c +#define SARADC2_END_INT_ST 0x110 +#define SARADC2_DATA_BASE 0x120 + +#define SARADC2_EN_END_INT BIT(0) +#define SARADC2_START BIT(4) +#define SARADC2_SINGLE_MODE BIT(5) + +#define SARADC2_CONV_CHANNELS GENMASK(15, 0) + +struct rockchip_saradc; + struct rockchip_saradc_data { const struct iio_chan_spec *channels; int num_channels; unsigned long clk_rate; + void (*start)(struct rockchip_saradc *info, int chn); + int (*read)(struct rockchip_saradc *info); + void (*power_down)(struct rockchip_saradc *info); }; struct rockchip_saradc { @@ -60,27 +82,81 @@ struct rockchip_saradc { struct notifier_block nb; }; -static void rockchip_saradc_power_down(struct rockchip_saradc *info) +static void rockchip_saradc_reset_controller(struct reset_control *reset); + +static void rockchip_saradc_start_v1(struct rockchip_saradc *info, int chn) +{ + /* 8 clock periods as delay between power up and start cmd */ + writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC); + /* Select the channel to be used and trigger conversion */ + writel(SARADC_CTRL_POWER_CTRL | (chn & SARADC_CTRL_CHN_MASK) | + SARADC_CTRL_IRQ_ENABLE, info->regs + SARADC_CTRL); +} + +static void rockchip_saradc_start_v2(struct rockchip_saradc *info, int chn) +{ + int val; + + if (info->reset) + rockchip_saradc_reset_controller(info->reset); + + writel_relaxed(0xc, info->regs + SARADC_T_DAS_SOC); + writel_relaxed(0x20, info->regs + SARADC_T_PD_SOC); + val = FIELD_PREP(SARADC2_EN_END_INT, 1); + val |= val << 16; + writel_relaxed(val, info->regs + SARADC2_END_INT_EN); + val = FIELD_PREP(SARADC2_START, 1) | + FIELD_PREP(SARADC2_SINGLE_MODE, 1) | + FIELD_PREP(SARADC2_CONV_CHANNELS, chn); + val |= val << 16; + writel(val, info->regs + SARADC2_CONV_CON); +} + +static void rockchip_saradc_start(struct rockchip_saradc *info, int chn) +{ + info->data->start(info, chn); +} + +static int rockchip_saradc_read_v1(struct rockchip_saradc *info) +{ + return readl_relaxed(info->regs + SARADC_DATA); +} + +static int rockchip_saradc_read_v2(struct rockchip_saradc *info) +{ + int offset; + + /* Clear irq */ + writel_relaxed(0x1, info->regs + SARADC2_END_INT_ST); + + offset = SARADC2_DATA_BASE + info->last_chan->channel * 0x4; + + return readl_relaxed(info->regs + offset); +} + +static int rockchip_saradc_read(struct rockchip_saradc *info) +{ + return info->data->read(info); +} + +static void rockchip_saradc_power_down_v1(struct rockchip_saradc *info) { - /* Clear irq & power down adc */ writel_relaxed(0, info->regs + SARADC_CTRL); } +static void rockchip_saradc_power_down(struct rockchip_saradc *info) +{ + if (info->data->power_down) + info->data->power_down(info); +} + static int rockchip_saradc_conversion(struct rockchip_saradc *info, - struct iio_chan_spec const *chan) + struct iio_chan_spec const *chan) { reinit_completion(&info->completion); - /* 8 clock periods as delay between power up and start cmd */ - writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC); - info->last_chan = chan; - - /* Select the channel to be used and trigger conversion */ - writel(SARADC_CTRL_POWER_CTRL - | (chan->channel & SARADC_CTRL_CHN_MASK) - | SARADC_CTRL_IRQ_ENABLE, - info->regs + SARADC_CTRL); + rockchip_saradc_start(info, chan->channel); if (!wait_for_completion_timeout(&info->completion, SARADC_TIMEOUT)) return -ETIMEDOUT; @@ -123,7 +199,7 @@ static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id) struct rockchip_saradc *info = dev_id; /* Read value */ - info->last_val = readl_relaxed(info->regs + SARADC_DATA); + info->last_val = rockchip_saradc_read(info); info->last_val &= GENMASK(info->last_chan->scan_type.realbits - 1, 0); rockchip_saradc_power_down(info); @@ -163,6 +239,9 @@ static const struct rockchip_saradc_data saradc_data = { .channels = rockchip_saradc_iio_channels, .num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels), .clk_rate = 1000000, + .start = rockchip_saradc_start_v1, + .read = rockchip_saradc_read_v1, + .power_down = rockchip_saradc_power_down_v1, }; static const struct iio_chan_spec rockchip_rk3066_tsadc_iio_channels[] = { @@ -174,6 +253,9 @@ static const struct rockchip_saradc_data rk3066_tsadc_data = { .channels = rockchip_rk3066_tsadc_iio_channels, .num_channels = ARRAY_SIZE(rockchip_rk3066_tsadc_iio_channels), .clk_rate = 50000, + .start = rockchip_saradc_start_v1, + .read = rockchip_saradc_read_v1, + .power_down = rockchip_saradc_power_down_v1, }; static const struct iio_chan_spec rockchip_rk3399_saradc_iio_channels[] = { @@ -189,6 +271,9 @@ static const struct rockchip_saradc_data rk3399_saradc_data = { .channels = rockchip_rk3399_saradc_iio_channels, .num_channels = ARRAY_SIZE(rockchip_rk3399_saradc_iio_channels), .clk_rate = 1000000, + .start = rockchip_saradc_start_v1, + .read = rockchip_saradc_read_v1, + .power_down = rockchip_saradc_power_down_v1, }; static const struct iio_chan_spec rockchip_rk3568_saradc_iio_channels[] = { @@ -206,6 +291,28 @@ static const struct rockchip_saradc_data rk3568_saradc_data = { .channels = rockchip_rk3568_saradc_iio_channels, .num_channels = ARRAY_SIZE(rockchip_rk3568_saradc_iio_channels), .clk_rate = 1000000, + .start = rockchip_saradc_start_v1, + .read = rockchip_saradc_read_v1, + .power_down = rockchip_saradc_power_down_v1, +}; + +static const struct iio_chan_spec rockchip_rk3588_saradc_iio_channels[] = { + SARADC_CHANNEL(0, "adc0", 12), + SARADC_CHANNEL(1, "adc1", 12), + SARADC_CHANNEL(2, "adc2", 12), + SARADC_CHANNEL(3, "adc3", 12), + SARADC_CHANNEL(4, "adc4", 12), + SARADC_CHANNEL(5, "adc5", 12), + SARADC_CHANNEL(6, "adc6", 12), + SARADC_CHANNEL(7, "adc7", 12), +}; + +static const struct rockchip_saradc_data rk3588_saradc_data = { + .channels = rockchip_rk3588_saradc_iio_channels, + .num_channels = ARRAY_SIZE(rockchip_rk3588_saradc_iio_channels), + .clk_rate = 1000000, + .start = rockchip_saradc_start_v2, + .read = rockchip_saradc_read_v2, }; static const struct of_device_id rockchip_saradc_match[] = { @@ -221,6 +328,9 @@ static const struct of_device_id rockchip_saradc_match[] = { }, { .compatible = "rockchip,rk3568-saradc", .data = &rk3568_saradc_data, + }, { + .compatible = "rockchip,rk3588-saradc", + .data = &rk3588_saradc_data, }, {}, }; @@ -236,20 +346,6 @@ static void rockchip_saradc_reset_controller(struct reset_control *reset) reset_control_deassert(reset); } -static void rockchip_saradc_clk_disable(void *data) -{ - struct rockchip_saradc *info = data; - - clk_disable_unprepare(info->clk); -} - -static void rockchip_saradc_pclk_disable(void *data) -{ - struct rockchip_saradc *info = data; - - clk_disable_unprepare(info->pclk); -} - static void rockchip_saradc_regulator_disable(void *data) { struct rockchip_saradc *info = data; @@ -298,8 +394,7 @@ out: } static int rockchip_saradc_volt_notify(struct notifier_block *nb, - unsigned long event, - void *data) + unsigned long event, void *data) { struct rockchip_saradc *info = container_of(nb, struct rockchip_saradc, nb); @@ -319,10 +414,10 @@ static void rockchip_saradc_regulator_unreg_notifier(void *data) static int rockchip_saradc_probe(struct platform_device *pdev) { + const struct rockchip_saradc_data *match_data; struct rockchip_saradc *info = NULL; struct device_node *np = pdev->dev.of_node; struct iio_dev *indio_dev = NULL; - const struct of_device_id *match; int ret; int irq; @@ -330,25 +425,23 @@ static int rockchip_saradc_probe(struct platform_device *pdev) return -ENODEV; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info)); - if (!indio_dev) { - dev_err(&pdev->dev, "failed allocating iio device\n"); - return -ENOMEM; - } + if (!indio_dev) + return dev_err_probe(&pdev->dev, -ENOMEM, + "failed allocating iio device\n"); + info = iio_priv(indio_dev); - match = of_match_device(rockchip_saradc_match, &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "failed to match device\n"); - return -ENODEV; - } + match_data = of_device_get_match_data(&pdev->dev); + if (!match_data) + return dev_err_probe(&pdev->dev, -ENODEV, + "failed to match device\n"); - info->data = match->data; + info->data = match_data; /* Sanity check for possible later IP variants with more channels */ - if (info->data->num_channels > SARADC_MAX_CHANNELS) { - dev_err(&pdev->dev, "max channels exceeded"); - return -EINVAL; - } + if (info->data->num_channels > SARADC_MAX_CHANNELS) + return dev_err_probe(&pdev->dev, -EINVAL, + "max channels exceeded"); info->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(info->regs)) @@ -383,16 +476,6 @@ static int rockchip_saradc_probe(struct platform_device *pdev) return ret; } - info->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); - if (IS_ERR(info->pclk)) - return dev_err_probe(&pdev->dev, PTR_ERR(info->pclk), - "failed to get pclk\n"); - - info->clk = devm_clk_get(&pdev->dev, "saradc"); - if (IS_ERR(info->clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(info->clk), - "failed to get adc clock\n"); - info->vref = devm_regulator_get(&pdev->dev, "vref"); if (IS_ERR(info->vref)) return dev_err_probe(&pdev->dev, PTR_ERR(info->vref), @@ -406,23 +489,20 @@ static int rockchip_saradc_probe(struct platform_device *pdev) * This may become user-configurable in the future. */ ret = clk_set_rate(info->clk, info->data->clk_rate); - if (ret < 0) { - dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "failed to set adc clk rate\n"); ret = regulator_enable(info->vref); - if (ret < 0) { - dev_err(&pdev->dev, "failed to enable vref regulator\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "failed to enable vref regulator\n"); + ret = devm_add_action_or_reset(&pdev->dev, rockchip_saradc_regulator_disable, info); - if (ret) { - dev_err(&pdev->dev, "failed to register devm action, %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to register devm action\n"); ret = regulator_get_voltage(info->vref); if (ret < 0) @@ -430,31 +510,15 @@ static int rockchip_saradc_probe(struct platform_device *pdev) info->uv_vref = ret; - ret = clk_prepare_enable(info->pclk); - if (ret < 0) { - dev_err(&pdev->dev, "failed to enable pclk\n"); - return ret; - } - ret = devm_add_action_or_reset(&pdev->dev, - rockchip_saradc_pclk_disable, info); - if (ret) { - dev_err(&pdev->dev, "failed to register devm action, %d\n", - ret); - return ret; - } + info->pclk = devm_clk_get_enabled(&pdev->dev, "apb_pclk"); + if (IS_ERR(info->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(info->pclk), + "failed to get pclk\n"); - ret = clk_prepare_enable(info->clk); - if (ret < 0) { - dev_err(&pdev->dev, "failed to enable converter clock\n"); - return ret; - } - ret = devm_add_action_or_reset(&pdev->dev, - rockchip_saradc_clk_disable, info); - if (ret) { - dev_err(&pdev->dev, "failed to register devm action, %d\n", - ret); - return ret; - } + info->clk = devm_clk_get_enabled(&pdev->dev, "saradc"); + if (IS_ERR(info->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(info->clk), + "failed to get adc clock\n"); platform_set_drvdata(pdev, indio_dev); diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c index c1b2e8dc9a26..ad4cea6839b2 100644 --- a/drivers/iio/adc/rtq6056.c +++ b/drivers/iio/adc/rtq6056.c @@ -652,7 +652,7 @@ static struct i2c_driver rtq6056_driver = { .of_match_table = rtq6056_device_match, .pm = pm_ptr(&rtq6056_pm_ops), }, - .probe_new = rtq6056_probe, + .probe = rtq6056_probe, }; module_i2c_driver(rtq6056_driver); diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index bd7e2408bf28..f7613efb870d 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1993,6 +1993,8 @@ static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm const struct stm32_adc_info *adc_info = adc->cfg->adc_info; int num_channels = 0, ret; + dev_dbg(&indio_dev->dev, "using legacy channel config\n"); + ret = device_property_count_u32(dev, "st,adc-channels"); if (ret > adc_info->max_channels) { dev_err(&indio_dev->dev, "Bad st,adc-channels?\n"); diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index c663dc59d459..50c450e7a55f 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -235,7 +235,7 @@ static struct i2c_driver adc081c_driver = { .of_match_table = adc081c_of_match, .acpi_match_table = adc081c_acpi_match, }, - .probe_new = adc081c_probe, + .probe = adc081c_probe, .id_table = adc081c_id, }; module_i2c_driver(adc081c_driver); diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 56af5e148802..075c75a87544 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -1195,7 +1195,7 @@ static struct i2c_driver ads1015_driver = { .of_match_table = ads1015_of_match, .pm = &ads1015_pm_ops, }, - .probe_new = ads1015_probe, + .probe = ads1015_probe, .remove = ads1015_remove, .id_table = ads1015_id, }; diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c index 6b5aebb82455..1e46f07a9ca6 100644 --- a/drivers/iio/adc/ti-ads1100.c +++ b/drivers/iio/adc/ti-ads1100.c @@ -434,7 +434,7 @@ static struct i2c_driver ads1100_driver = { .of_match_table = ads1100_of_match, .pm = pm_ptr(&ads1100_pm_ops), }, - .probe_new = ads1100_probe, + .probe = ads1100_probe, .id_table = ads1100_id, }; diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c index b02abb026966..afdbd04778a8 100644 --- a/drivers/iio/adc/ti-ads7924.c +++ b/drivers/iio/adc/ti-ads7924.c @@ -463,7 +463,7 @@ static struct i2c_driver ads7924_driver = { .name = "ads7924", .of_match_table = ads7924_of_match, }, - .probe_new = ads7924_probe, + .probe = ads7924_probe, .id_table = ads7924_id, }; diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index e3366cf5eb31..6b0e8218f150 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -1317,13 +1317,14 @@ static int ad74413r_setup_gpios(struct ad74413r_state *st) } if (config->func == CH_FUNC_DIGITAL_INPUT_LOGIC || - config->func == CH_FUNC_DIGITAL_INPUT_LOOP_POWER) + config->func == CH_FUNC_DIGITAL_INPUT_LOOP_POWER) { st->comp_gpio_offsets[comp_gpio_i++] = i; - strength = config->drive_strength; - ret = ad74413r_set_comp_drive_strength(st, i, strength); - if (ret) - return ret; + strength = config->drive_strength; + ret = ad74413r_set_comp_drive_strength(st, i, strength); + if (ret) + return ret; + } ret = ad74413r_set_gpo_config(st, i, gpo_config); if (ret) diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c index f2c2ea79a07f..8d8c8ea94258 100644 --- a/drivers/iio/amplifiers/ad8366.c +++ b/drivers/iio/amplifiers/ad8366.c @@ -281,7 +281,7 @@ static int ad8366_probe(struct spi_device *spi) indio_dev->info = &ad8366_info; indio_dev->modes = INDIO_DIRECT_MODE; - ret = ad8366_write(indio_dev, 0 , 0); + ret = ad8366_write(indio_dev, 0, 0); if (ret < 0) goto error_disable_reg; diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c index 79aeb0aaea67..d656d2f12755 100644 --- a/drivers/iio/cdc/ad7150.c +++ b/drivers/iio/cdc/ad7150.c @@ -647,7 +647,7 @@ static struct i2c_driver ad7150_driver = { .name = "ad7150", .of_match_table = ad7150_of_match, }, - .probe_new = ad7150_probe, + .probe = ad7150_probe, .id_table = ad7150_id, }; module_i2c_driver(ad7150_driver); diff --git a/drivers/iio/cdc/ad7746.c b/drivers/iio/cdc/ad7746.c index a1db5469f2d1..d11bc3496dda 100644 --- a/drivers/iio/cdc/ad7746.c +++ b/drivers/iio/cdc/ad7746.c @@ -809,7 +809,7 @@ static struct i2c_driver ad7746_driver = { .name = KBUILD_MODNAME, .of_match_table = ad7746_of_match, }, - .probe_new = ad7746_probe, + .probe = ad7746_probe, .id_table = ad7746_id, }; module_i2c_driver(ad7746_driver); diff --git a/drivers/iio/chemical/ams-iaq-core.c b/drivers/iio/chemical/ams-iaq-core.c index 0a0fbcdd4469..164facac5db6 100644 --- a/drivers/iio/chemical/ams-iaq-core.c +++ b/drivers/iio/chemical/ams-iaq-core.c @@ -179,7 +179,7 @@ static struct i2c_driver ams_iaqcore_driver = { .name = "ams-iaq-core", .of_match_table = ams_iaqcore_dt_ids, }, - .probe_new = ams_iaqcore_probe, + .probe = ams_iaqcore_probe, .id_table = ams_iaqcore_id, }; module_i2c_driver(ams_iaqcore_driver); diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c index 307c3488f4bd..8fc926a2d33b 100644 --- a/drivers/iio/chemical/atlas-ezo-sensor.c +++ b/drivers/iio/chemical/atlas-ezo-sensor.c @@ -238,7 +238,7 @@ static struct i2c_driver atlas_ezo_driver = { .name = ATLAS_EZO_DRV_NAME, .of_match_table = atlas_ezo_dt_ids, }, - .probe_new = atlas_ezo_probe, + .probe = atlas_ezo_probe, .id_table = atlas_ezo_id, }; module_i2c_driver(atlas_ezo_driver); diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index 024657bc59e1..fb15bb216019 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -767,7 +767,7 @@ static struct i2c_driver atlas_driver = { .of_match_table = atlas_dt_ids, .pm = pm_ptr(&atlas_pm_ops), }, - .probe_new = atlas_probe, + .probe = atlas_probe, .remove = atlas_remove, .id_table = atlas_id, }; diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c index 61b12079858d..1c7076cf91ca 100644 --- a/drivers/iio/chemical/bme680_i2c.c +++ b/drivers/iio/chemical/bme680_i2c.c @@ -52,7 +52,7 @@ static struct i2c_driver bme680_i2c_driver = { .name = "bme680_i2c", .of_match_table = bme680_of_i2c_match, }, - .probe_new = bme680_i2c_probe, + .probe = bme680_i2c_probe, .id_table = bme680_i2c_id, }; module_i2c_driver(bme680_i2c_driver); diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c index 6ead80c08924..87741f155c32 100644 --- a/drivers/iio/chemical/ccs811.c +++ b/drivers/iio/chemical/ccs811.c @@ -567,7 +567,7 @@ static struct i2c_driver ccs811_driver = { .name = "ccs811", .of_match_table = ccs811_dt_ids, }, - .probe_new = ccs811_probe, + .probe = ccs811_probe, .remove = ccs811_remove, .id_table = ccs811_id, }; diff --git a/drivers/iio/chemical/scd30_i2c.c b/drivers/iio/chemical/scd30_i2c.c index bae479a4721f..bd3b01ded246 100644 --- a/drivers/iio/chemical/scd30_i2c.c +++ b/drivers/iio/chemical/scd30_i2c.c @@ -130,7 +130,7 @@ static struct i2c_driver scd30_i2c_driver = { .of_match_table = scd30_i2c_of_match, .pm = pm_sleep_ptr(&scd30_pm_ops), }, - .probe_new = scd30_i2c_probe, + .probe = scd30_i2c_probe, }; module_i2c_driver(scd30_i2c_driver); diff --git a/drivers/iio/chemical/scd4x.c b/drivers/iio/chemical/scd4x.c index f7ed9455b3c8..a4f22d926400 100644 --- a/drivers/iio/chemical/scd4x.c +++ b/drivers/iio/chemical/scd4x.c @@ -690,7 +690,7 @@ static struct i2c_driver scd4x_i2c_driver = { .of_match_table = scd4x_dt_ids, .pm = pm_sleep_ptr(&scd4x_pm_ops), }, - .probe_new = scd4x_probe, + .probe = scd4x_probe, }; module_i2c_driver(scd4x_i2c_driver); diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c index 9d0c68485b63..b509cff9ce37 100644 --- a/drivers/iio/chemical/sgp30.c +++ b/drivers/iio/chemical/sgp30.c @@ -575,7 +575,7 @@ static struct i2c_driver sgp_driver = { .name = "sgp30", .of_match_table = sgp_dt_ids, }, - .probe_new = sgp_probe, + .probe = sgp_probe, .remove = sgp_remove, .id_table = sgp_id, }; diff --git a/drivers/iio/chemical/sgp40.c b/drivers/iio/chemical/sgp40.c index c0ea01300908..7f0de14a1956 100644 --- a/drivers/iio/chemical/sgp40.c +++ b/drivers/iio/chemical/sgp40.c @@ -368,7 +368,7 @@ static struct i2c_driver sgp40_driver = { .name = "sgp40", .of_match_table = sgp40_dt_ids, }, - .probe_new = sgp40_probe, + .probe = sgp40_probe, .id_table = sgp40_id, }; module_i2c_driver(sgp40_driver); diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c index 0cb5d9b65d62..5c31299813ec 100644 --- a/drivers/iio/chemical/sps30_i2c.c +++ b/drivers/iio/chemical/sps30_i2c.c @@ -249,7 +249,7 @@ static struct i2c_driver sps30_i2c_driver = { .of_match_table = sps30_i2c_of_match, }, .id_table = sps30_i2c_id, - .probe_new = sps30_i2c_probe, + .probe = sps30_i2c_probe, }; module_i2c_driver(sps30_i2c_driver); diff --git a/drivers/iio/chemical/sunrise_co2.c b/drivers/iio/chemical/sunrise_co2.c index 8440dc0c77cf..cdb8696a4e81 100644 --- a/drivers/iio/chemical/sunrise_co2.c +++ b/drivers/iio/chemical/sunrise_co2.c @@ -528,7 +528,7 @@ static struct i2c_driver sunrise_driver = { .name = DRIVER_NAME, .of_match_table = sunrise_of_match, }, - .probe_new = sunrise_probe, + .probe = sunrise_probe, }; module_i2c_driver(sunrise_driver); diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index d4604f7ccd1e..13555f4f401a 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c @@ -402,7 +402,7 @@ static struct i2c_driver vz89x_driver = { .name = "vz89x", .of_match_table = vz89x_dt_ids, }, - .probe_new = vz89x_probe, + .probe = vz89x_probe, .id_table = vz89x_id, }; module_i2c_driver(vz89x_driver); diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index f01249c1ba93..7712dc6be608 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -1056,7 +1056,7 @@ static struct i2c_driver ad5064_i2c_driver = { .driver = { .name = "ad5064", }, - .probe_new = ad5064_i2c_probe, + .probe = ad5064_i2c_probe, .id_table = ad5064_i2c_ids, }; diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 64b4519f8f5e..2e3e33f92bc0 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -589,7 +589,7 @@ static struct i2c_driver ad5380_i2c_driver = { .driver = { .name = "ad5380", }, - .probe_new = ad5380_i2c_probe, + .probe = ad5380_i2c_probe, .remove = ad5380_i2c_remove, .id_table = ad5380_i2c_ids, }; diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index aa3130b33456..8103d2cd13f6 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -595,7 +595,7 @@ static struct i2c_driver ad5446_i2c_driver = { .driver = { .name = "ad5446", }, - .probe_new = ad5446_i2c_probe, + .probe = ad5446_i2c_probe, .remove = ad5446_i2c_remove, .id_table = ad5446_i2c_ids, }; diff --git a/drivers/iio/dac/ad5593r.c b/drivers/iio/dac/ad5593r.c index d311567ab324..fae5e5a0e72f 100644 --- a/drivers/iio/dac/ad5593r.c +++ b/drivers/iio/dac/ad5593r.c @@ -138,7 +138,7 @@ static struct i2c_driver ad5593r_driver = { .of_match_table = ad5593r_of_match, .acpi_match_table = ad5593r_acpi_match, }, - .probe_new = ad5593r_i2c_probe, + .probe = ad5593r_i2c_probe, .remove = ad5593r_i2c_remove, .id_table = ad5593r_i2c_ids, }; diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index 8a95f0278018..81541f755a3e 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -115,7 +115,7 @@ static struct i2c_driver ad5686_i2c_driver = { .name = "ad5696", .of_match_table = ad5686_of_match, }, - .probe_new = ad5686_i2c_probe, + .probe = ad5686_i2c_probe, .remove = ad5686_i2c_remove, .id_table = ad5686_i2c_id, }; diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c index a16a6a934d9d..e89e4c054653 100644 --- a/drivers/iio/dac/ds4424.c +++ b/drivers/iio/dac/ds4424.c @@ -312,7 +312,7 @@ static struct i2c_driver ds4424_driver = { .of_match_table = ds4424_of_match, .pm = pm_sleep_ptr(&ds4424_pm_ops), }, - .probe_new = ds4424_probe, + .probe = ds4424_probe, .remove = ds4424_remove, .id_table = ds4424_id, }; diff --git a/drivers/iio/dac/m62332.c b/drivers/iio/dac/m62332.c index b692459b0f23..ae53baccec91 100644 --- a/drivers/iio/dac/m62332.c +++ b/drivers/iio/dac/m62332.c @@ -238,7 +238,7 @@ static struct i2c_driver m62332_driver = { .name = "m62332", .pm = pm_sleep_ptr(&m62332_pm_ops), }, - .probe_new = m62332_probe, + .probe = m62332_probe, .remove = m62332_remove, .id_table = m62332_id, }; diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c index 25967c39365d..685980184d3c 100644 --- a/drivers/iio/dac/max517.c +++ b/drivers/iio/dac/max517.c @@ -203,7 +203,7 @@ static struct i2c_driver max517_driver = { .name = MAX517_DRV_NAME, .pm = pm_sleep_ptr(&max517_pm_ops), }, - .probe_new = max517_probe, + .probe = max517_probe, .id_table = max517_id, }; module_i2c_driver(max517_driver); diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c index 23da345b9250..18ba3eaaad75 100644 --- a/drivers/iio/dac/max5821.c +++ b/drivers/iio/dac/max5821.c @@ -377,7 +377,7 @@ static struct i2c_driver max5821_driver = { .of_match_table = max5821_of_match, .pm = pm_sleep_ptr(&max5821_pm_ops), }, - .probe_new = max5821_probe, + .probe = max5821_probe, .id_table = max5821_id, }; module_i2c_driver(max5821_driver); diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 3f5661a3718f..f4a3124d29f2 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -536,7 +536,7 @@ static struct i2c_driver mcp4725_driver = { .of_match_table = mcp4725_of_match, .pm = pm_sleep_ptr(&mcp4725_pm_ops), }, - .probe_new = mcp4725_probe, + .probe = mcp4725_probe, .remove = mcp4725_remove, .id_table = mcp4725_id, }; diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index 40191947fea3..bab11b9adc25 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -426,7 +426,7 @@ static struct i2c_driver dac5571_driver = { .name = "ti-dac5571", .of_match_table = dac5571_of_id, }, - .probe_new = dac5571_probe, + .probe = dac5571_probe, .remove = dac5571_remove, .id_table = dac5571_id, }; diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c index 2b019ee5b2eb..2f9675596138 100644 --- a/drivers/iio/gyro/bmg160_i2c.c +++ b/drivers/iio/gyro/bmg160_i2c.c @@ -70,7 +70,7 @@ static struct i2c_driver bmg160_i2c_driver = { .of_match_table = bmg160_of_match, .pm = &bmg160_pm_ops, }, - .probe_new = bmg160_i2c_probe, + .probe = bmg160_i2c_probe, .remove = bmg160_i2c_remove, .id_table = bmg160_i2c_id, }; diff --git a/drivers/iio/gyro/fxas21002c_i2c.c b/drivers/iio/gyro/fxas21002c_i2c.c index 9e2d0f34a672..ee7f21b718e2 100644 --- a/drivers/iio/gyro/fxas21002c_i2c.c +++ b/drivers/iio/gyro/fxas21002c_i2c.c @@ -56,7 +56,7 @@ static struct i2c_driver fxas21002c_i2c_driver = { .pm = pm_ptr(&fxas21002c_pm_ops), .of_match_table = fxas21002c_i2c_of_match, }, - .probe_new = fxas21002c_i2c_probe, + .probe = fxas21002c_i2c_probe, .remove = fxas21002c_i2c_remove, .id_table = fxas21002c_i2c_id, }; diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index ceacd863d3ea..53fb92f0ac7e 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -405,7 +405,7 @@ static struct i2c_driver itg3200_driver = { .pm = pm_sleep_ptr(&itg3200_pm_ops), }, .id_table = itg3200_id, - .probe_new = itg3200_probe, + .probe = itg3200_probe, .remove = itg3200_remove, }; diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c index 2116798226bf..52b6feed2637 100644 --- a/drivers/iio/gyro/mpu3050-i2c.c +++ b/drivers/iio/gyro/mpu3050-i2c.c @@ -108,7 +108,7 @@ static const struct of_device_id mpu3050_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, mpu3050_i2c_of_match); static struct i2c_driver mpu3050_i2c_driver = { - .probe_new = mpu3050_i2c_probe, + .probe = mpu3050_i2c_probe, .remove = mpu3050_i2c_remove, .id_table = mpu3050_i2c_id, .driver = { diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index 797a1c6a0402..5a10a3556ab0 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -111,7 +111,7 @@ static struct i2c_driver st_gyro_driver = { .name = "st-gyro-i2c", .of_match_table = st_gyro_of_match, }, - .probe_new = st_gyro_i2c_probe, + .probe = st_gyro_i2c_probe, .id_table = st_gyro_id_table, }; module_i2c_driver(st_gyro_driver); diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 21a6378b7052..ede1e8201311 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -609,7 +609,7 @@ static struct i2c_driver afe4404_i2c_driver = { .of_match_table = afe4404_of_match, .pm = pm_sleep_ptr(&afe4404_pm_ops), }, - .probe_new = afe4404_probe, + .probe = afe4404_probe, .remove = afe4404_remove, .id_table = afe4404_ids, }; diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index a80fa9852c22..6236b4d96137 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -499,7 +499,7 @@ static struct i2c_driver max30100_driver = { .name = MAX30100_DRV_NAME, .of_match_table = max30100_dt_ids, }, - .probe_new = max30100_probe, + .probe = max30100_probe, .remove = max30100_remove, .id_table = max30100_id, }; diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index 7edcf9e05687..37e619827e8a 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -631,7 +631,7 @@ static struct i2c_driver max30102_driver = { .name = MAX30102_DRV_NAME, .of_match_table = max30102_dt_ids, }, - .probe_new = max30102_probe, + .probe = max30102_probe, .remove = max30102_remove, .id_table = max30102_id, }; diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index f246516bd45e..37a35d1153d5 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -262,7 +262,7 @@ static struct i2c_driver am2315_driver = { .driver = { .name = "am2315", }, - .probe_new = am2315_probe, + .probe = am2315_probe, .id_table = am2315_i2c_id, }; diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index 49a950d739e4..202014da2785 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -428,7 +428,7 @@ static struct i2c_driver hdc100x_driver = { .of_match_table = hdc100x_dt_ids, .acpi_match_table = hdc100x_acpi_match, }, - .probe_new = hdc100x_probe, + .probe = hdc100x_probe, .id_table = hdc100x_id, }; module_i2c_driver(hdc100x_driver); diff --git a/drivers/iio/humidity/hdc2010.c b/drivers/iio/humidity/hdc2010.c index c8fddd612e06..f5867659e00f 100644 --- a/drivers/iio/humidity/hdc2010.c +++ b/drivers/iio/humidity/hdc2010.c @@ -338,7 +338,7 @@ static struct i2c_driver hdc2010_driver = { .name = "hdc2010", .of_match_table = hdc2010_dt_ids, }, - .probe_new = hdc2010_probe, + .probe = hdc2010_probe, .remove = hdc2010_remove, .id_table = hdc2010_id, }; diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c index d81869423cf0..30f2068ea156 100644 --- a/drivers/iio/humidity/hts221_i2c.c +++ b/drivers/iio/humidity/hts221_i2c.c @@ -65,7 +65,7 @@ static struct i2c_driver hts221_driver = { .of_match_table = hts221_i2c_of_match, .acpi_match_table = ACPI_PTR(hts221_acpi_match), }, - .probe_new = hts221_i2c_probe, + .probe = hts221_i2c_probe, .id_table = hts221_i2c_id_table, }; module_i2c_driver(hts221_driver); diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c index 8411a9f3e828..39e886075299 100644 --- a/drivers/iio/humidity/htu21.c +++ b/drivers/iio/humidity/htu21.c @@ -244,7 +244,7 @@ static const struct of_device_id htu21_of_match[] = { MODULE_DEVICE_TABLE(of, htu21_of_match); static struct i2c_driver htu21_driver = { - .probe_new = htu21_probe, + .probe = htu21_probe, .id_table = htu21_id, .driver = { .name = "htu21", diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c index fa1faf168c8d..ebfb79bc9edc 100644 --- a/drivers/iio/humidity/si7005.c +++ b/drivers/iio/humidity/si7005.c @@ -173,7 +173,7 @@ static struct i2c_driver si7005_driver = { .driver = { .name = "si7005", }, - .probe_new = si7005_probe, + .probe = si7005_probe, .id_table = si7005_id, }; module_i2c_driver(si7005_driver); diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c index 3e50592e8e68..fb1006649328 100644 --- a/drivers/iio/humidity/si7020.c +++ b/drivers/iio/humidity/si7020.c @@ -155,7 +155,7 @@ static struct i2c_driver si7020_driver = { .name = "si7020", .of_match_table = si7020_dt_ids, }, - .probe_new = si7020_probe, + .probe = si7020_probe, .id_table = si7020_id, }; diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index 2ca907d396a0..81652c08e644 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -60,7 +60,7 @@ static struct i2c_driver bmi160_i2c_driver = { .acpi_match_table = bmi160_acpi_match, .of_match_table = bmi160_of_match, }, - .probe_new = bmi160_i2c_probe, + .probe = bmi160_i2c_probe, .id_table = bmi160_i2c_id, }; module_i2c_driver(bmi160_i2c_driver); diff --git a/drivers/iio/imu/bno055/bno055_i2c.c b/drivers/iio/imu/bno055/bno055_i2c.c index c1bbc0fe34f9..6ecd750c6b76 100644 --- a/drivers/iio/imu/bno055/bno055_i2c.c +++ b/drivers/iio/imu/bno055/bno055_i2c.c @@ -46,7 +46,7 @@ static struct i2c_driver bno055_driver = { .name = "bno055-i2c", .of_match_table = bno055_i2c_of_match, }, - .probe_new = bno055_i2c_probe, + .probe = bno055_i2c_probe, .id_table = bno055_i2c_id, }; module_i2c_driver(bno055_driver); diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c index a74a15fda8cb..2ace306d0f9a 100644 --- a/drivers/iio/imu/fxos8700_i2c.c +++ b/drivers/iio/imu/fxos8700_i2c.c @@ -60,7 +60,7 @@ static struct i2c_driver fxos8700_i2c_driver = { .acpi_match_table = ACPI_PTR(fxos8700_acpi_match), .of_match_table = fxos8700_of_match, }, - .probe_new = fxos8700_i2c_probe, + .probe = fxos8700_i2c_probe, .id_table = fxos8700_i2c_id, }; module_i2c_driver(fxos8700_i2c_driver); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index eb2681ad375f..1af559403ba6 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -98,7 +98,7 @@ static struct i2c_driver inv_icm42600_driver = { .of_match_table = inv_icm42600_of_matches, .pm = pm_ptr(&inv_icm42600_pm_ops), }, - .probe_new = inv_icm42600_probe, + .probe = inv_icm42600_probe, }; module_i2c_driver(inv_icm42600_driver); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c index 7f2dc41f807b..37cbf08acb3a 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c @@ -93,8 +93,8 @@ static bool inv_validate_period(uint32_t period, uint32_t mult) return false; } -static bool inv_compute_chip_period(struct inv_icm42600_timestamp *ts, - uint32_t mult, uint32_t period) +static bool inv_update_chip_period(struct inv_icm42600_timestamp *ts, + uint32_t mult, uint32_t period) { uint32_t new_chip_period; @@ -104,10 +104,31 @@ static bool inv_compute_chip_period(struct inv_icm42600_timestamp *ts, /* update chip internal period estimation */ new_chip_period = period / mult; inv_update_acc(&ts->chip_period, new_chip_period); + ts->period = ts->mult * ts->chip_period.val; return true; } +static void inv_align_timestamp_it(struct inv_icm42600_timestamp *ts) +{ + int64_t delta, jitter; + int64_t adjust; + + /* delta time between last sample and last interrupt */ + delta = ts->it.lo - ts->timestamp; + + /* adjust timestamp while respecting jitter */ + jitter = div_s64((int64_t)ts->period * INV_ICM42600_TIMESTAMP_JITTER, 100); + if (delta > jitter) + adjust = jitter; + else if (delta < -jitter) + adjust = -jitter; + else + adjust = 0; + + ts->timestamp += adjust; +} + void inv_icm42600_timestamp_interrupt(struct inv_icm42600_timestamp *ts, uint32_t fifo_period, size_t fifo_nb, size_t sensor_nb, int64_t timestamp) @@ -116,7 +137,6 @@ void inv_icm42600_timestamp_interrupt(struct inv_icm42600_timestamp *ts, int64_t delta, interval; const uint32_t fifo_mult = fifo_period / INV_ICM42600_TIMESTAMP_PERIOD; uint32_t period = ts->period; - int32_t m; bool valid = false; if (fifo_nb == 0) @@ -130,10 +150,7 @@ void inv_icm42600_timestamp_interrupt(struct inv_icm42600_timestamp *ts, if (it->lo != 0) { /* compute period: delta time divided by number of samples */ period = div_s64(delta, fifo_nb); - valid = inv_compute_chip_period(ts, fifo_mult, period); - /* update sensor period if chip internal period is updated */ - if (valid) - ts->period = ts->mult * ts->chip_period.val; + valid = inv_update_chip_period(ts, fifo_mult, period); } /* no previous data, compute theoritical value from interrupt */ @@ -145,22 +162,8 @@ void inv_icm42600_timestamp_interrupt(struct inv_icm42600_timestamp *ts, } /* if interrupt interval is valid, sync with interrupt timestamp */ - if (valid) { - /* compute measured fifo_period */ - fifo_period = fifo_mult * ts->chip_period.val; - /* delta time between last sample and last interrupt */ - delta = it->lo - ts->timestamp; - /* if there are multiple samples, go back to first one */ - while (delta >= (fifo_period * 3 / 2)) - delta -= fifo_period; - /* compute maximal adjustment value */ - m = INV_ICM42600_TIMESTAMP_MAX_PERIOD(ts->period) - ts->period; - if (delta > m) - delta = m; - else if (delta < -m) - delta = -m; - ts->timestamp += delta; - } + if (valid) + inv_align_timestamp_it(ts); } void inv_icm42600_timestamp_apply_odr(struct inv_icm42600_timestamp *ts, diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig index 3636b1bc90f1..64dd73dcc4ba 100644 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -16,7 +16,7 @@ config INV_MPU6050_I2C select REGMAP_I2C help This driver supports the Invensense MPU6050/9150, - MPU6500/6515/6880/9250/9255, ICM20608(D)/20609/20689, ICM20602/ICM20690 + MPU6500/6515/6880/9250/9255, ICM20608(D)/20609/20689, ICM20600/20602/20690 and IAM20680 motion tracking devices over I2C. This driver can be built as a module. The module will be called inv-mpu6050-i2c. @@ -28,7 +28,7 @@ config INV_MPU6050_SPI select REGMAP_SPI help This driver supports the Invensense MPU6000, - MPU6500/6515/6880/9250/9255, ICM20608(D)/20609/20689, ICM20602/ICM20690 + MPU6500/6515/6880/9250/9255, ICM20608(D)/20609/20689, ICM20600/20602/20690 and IAM20680 motion tracking devices over SPI. This driver can be built as a module. The module will be called inv-mpu6050-spi. diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 8a129120b73d..592a6e60b413 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -245,6 +245,15 @@ static const struct inv_mpu6050_hw hw_info[] = { .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, }, { + .whoami = INV_ICM20600_WHOAMI_VALUE, + .name = "ICM20600", + .reg = ®_set_icm20602, + .config = &chip_config_6500, + .fifo_size = 1008, + .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, + .startup_time = {INV_ICM20602_GYRO_STARTUP_TIME, INV_ICM20602_ACCEL_STARTUP_TIME}, + }, + { .whoami = INV_ICM20602_WHOAMI_VALUE, .name = "ICM20602", .reg = ®_set_icm20602, @@ -1597,6 +1606,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels); indio_dev->available_scan_masks = inv_mpu9x50_scan_masks; break; + case INV_ICM20600: case INV_ICM20602: indio_dev->channels = inv_mpu_channels; indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index 2f2da4cb7321..410ea39fd495 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -32,6 +32,7 @@ static bool inv_mpu_i2c_aux_bus(struct device *dev) case INV_ICM20608D: case INV_ICM20609: case INV_ICM20689: + case INV_ICM20600: case INV_ICM20602: case INV_IAM20680: /* no i2c auxiliary bus on the chip */ @@ -183,6 +184,7 @@ static const struct i2c_device_id inv_mpu_id[] = { {"icm20608d", INV_ICM20608D}, {"icm20609", INV_ICM20609}, {"icm20689", INV_ICM20689}, + {"icm20600", INV_ICM20600}, {"icm20602", INV_ICM20602}, {"icm20690", INV_ICM20690}, {"iam20680", INV_IAM20680}, @@ -237,6 +239,10 @@ static const struct of_device_id inv_of_match[] = { .data = (void *)INV_ICM20689 }, { + .compatible = "invensense,icm20600", + .data = (void *)INV_ICM20600 + }, + { .compatible = "invensense,icm20602", .data = (void *)INV_ICM20602 }, @@ -259,7 +265,7 @@ static const struct acpi_device_id inv_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, inv_acpi_match); static struct i2c_driver inv_mpu_driver = { - .probe_new = inv_mpu_probe, + .probe = inv_mpu_probe, .remove = inv_mpu_remove, .id_table = inv_mpu_id, .driver = { diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 94b54c501ec0..b4ab2c397d0f 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -79,6 +79,7 @@ enum inv_devices { INV_ICM20608D, INV_ICM20609, INV_ICM20689, + INV_ICM20600, INV_ICM20602, INV_ICM20690, INV_IAM20680, @@ -398,6 +399,7 @@ struct inv_mpu6050_state { #define INV_ICM20608D_WHOAMI_VALUE 0xAE #define INV_ICM20609_WHOAMI_VALUE 0xA6 #define INV_ICM20689_WHOAMI_VALUE 0x98 +#define INV_ICM20600_WHOAMI_VALUE 0x11 #define INV_ICM20602_WHOAMI_VALUE 0x12 #define INV_ICM20690_WHOAMI_VALUE 0x20 #define INV_IAM20680_WHOAMI_VALUE 0xA9 diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 89f46c2f213d..05451ca1580b 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -76,6 +76,7 @@ static const struct spi_device_id inv_mpu_id[] = { {"icm20608d", INV_ICM20608D}, {"icm20609", INV_ICM20609}, {"icm20689", INV_ICM20689}, + {"icm20600", INV_ICM20600}, {"icm20602", INV_ICM20602}, {"icm20690", INV_ICM20690}, {"iam20680", INV_IAM20680}, @@ -126,6 +127,10 @@ static const struct of_device_id inv_of_match[] = { .data = (void *)INV_ICM20689 }, { + .compatible = "invensense,icm20600", + .data = (void *)INV_ICM20600 + }, + { .compatible = "invensense,icm20602", .data = (void *)INV_ICM20602 }, diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 53ba020fa5d0..958167b31241 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1517,7 +1517,7 @@ static struct i2c_driver kmx61_driver = { .acpi_match_table = ACPI_PTR(kmx61_acpi_match), .pm = pm_ptr(&kmx61_pm_ops), }, - .probe_new = kmx61_probe, + .probe = kmx61_probe, .remove = kmx61_remove, .id_table = kmx61_id, }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index 020717f92363..911444ec57c0 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -179,7 +179,7 @@ static struct i2c_driver st_lsm6dsx_driver = { .of_match_table = st_lsm6dsx_i2c_of_match, .acpi_match_table = st_lsm6dsx_i2c_acpi_match, }, - .probe_new = st_lsm6dsx_i2c_probe, + .probe = st_lsm6dsx_i2c_probe, .id_table = st_lsm6dsx_i2c_id_table, }; module_i2c_driver(st_lsm6dsx_driver); diff --git a/drivers/iio/imu/st_lsm9ds0/Kconfig b/drivers/iio/imu/st_lsm9ds0/Kconfig index d29558edee60..7aef714b6ecb 100644 --- a/drivers/iio/imu/st_lsm9ds0/Kconfig +++ b/drivers/iio/imu/st_lsm9ds0/Kconfig @@ -10,7 +10,8 @@ config IIO_ST_LSM9DS0 help Say yes here to build support for STMicroelectronics LSM9DS0 IMU - sensor. Supported devices: accelerometer/magnetometer of lsm9ds0. + sensor. Supported devices: accelerometer/magnetometer of lsm9ds0 + and lsm303d. To compile this driver as a module, choose M here: the module will be called st_lsm9ds0. diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c index a90138d8b06a..61d855083aa0 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -19,6 +19,10 @@ static const struct of_device_id st_lsm9ds0_of_match[] = { { + .compatible = "st,lsm303d-imu", + .data = LSM303D_IMU_DEV_NAME, + }, + { .compatible = "st,lsm9ds0-imu", .data = LSM9DS0_IMU_DEV_NAME, }, @@ -27,11 +31,18 @@ static const struct of_device_id st_lsm9ds0_of_match[] = { MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); static const struct i2c_device_id st_lsm9ds0_id_table[] = { + { LSM303D_IMU_DEV_NAME }, { LSM9DS0_IMU_DEV_NAME }, {} }; MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table); +static const struct acpi_device_id st_lsm9ds0_acpi_match[] = { + {"ACCL0001", (kernel_ulong_t)LSM303D_IMU_DEV_NAME}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, st_lsm9ds0_acpi_match); + static const struct regmap_config st_lsm9ds0_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -68,8 +79,9 @@ static struct i2c_driver st_lsm9ds0_driver = { .driver = { .name = "st-lsm9ds0-i2c", .of_match_table = st_lsm9ds0_of_match, + .acpi_match_table = st_lsm9ds0_acpi_match, }, - .probe_new = st_lsm9ds0_i2c_probe, + .probe = st_lsm9ds0_i2c_probe, .id_table = st_lsm9ds0_id_table, }; module_i2c_driver(st_lsm9ds0_driver); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c index b743bf3546a7..8cc041d56cf7 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -19,6 +19,10 @@ static const struct of_device_id st_lsm9ds0_of_match[] = { { + .compatible = "st,lsm303d-imu", + .data = LSM303D_IMU_DEV_NAME, + }, + { .compatible = "st,lsm9ds0-imu", .data = LSM9DS0_IMU_DEV_NAME, }, @@ -27,6 +31,7 @@ static const struct of_device_id st_lsm9ds0_of_match[] = { MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); static const struct spi_device_id st_lsm9ds0_id_table[] = { + { LSM303D_IMU_DEV_NAME }, { LSM9DS0_IMU_DEV_NAME }, {} }; diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index a7a080bed180..176d31d9f9d8 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -194,7 +194,7 @@ static ssize_t iio_buffer_write(struct file *filp, const char __user *buf, written = 0; add_wait_queue(&rb->pollq, &wait); do { - if (indio_dev->info == NULL) + if (!indio_dev->info) return -ENODEV; if (!iio_buffer_space_available(rb)) { @@ -210,7 +210,7 @@ static ssize_t iio_buffer_write(struct file *filp, const char __user *buf, } wait_woken(&wait, TASK_INTERRUPTIBLE, - MAX_SCHEDULE_TIMEOUT); + MAX_SCHEDULE_TIMEOUT); continue; } @@ -242,7 +242,7 @@ static __poll_t iio_buffer_poll(struct file *filp, struct iio_buffer *rb = ib->buffer; struct iio_dev *indio_dev = ib->indio_dev; - if (!indio_dev->info || rb == NULL) + if (!indio_dev->info || !rb) return 0; poll_wait(filp, &rb->pollq, wait); @@ -407,9 +407,9 @@ static ssize_t iio_scan_el_show(struct device *dev, /* Note NULL used as error indicator as it doesn't make sense. */ static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks, - unsigned int masklength, - const unsigned long *mask, - bool strict) + unsigned int masklength, + const unsigned long *mask, + bool strict) { if (bitmap_empty(mask, masklength)) return NULL; @@ -427,7 +427,7 @@ static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks, } static bool iio_validate_scan_mask(struct iio_dev *indio_dev, - const unsigned long *mask) + const unsigned long *mask) { if (!indio_dev->setup_ops->validate_scan_mask) return true; @@ -446,7 +446,7 @@ static bool iio_validate_scan_mask(struct iio_dev *indio_dev, * individual buffers request is plausible. */ static int iio_scan_mask_set(struct iio_dev *indio_dev, - struct iio_buffer *buffer, int bit) + struct iio_buffer *buffer, int bit) { const unsigned long *mask; unsigned long *trialmask; @@ -539,7 +539,6 @@ error_ret: mutex_unlock(&iio_dev_opaque->mlock); return ret < 0 ? ret : len; - } static ssize_t iio_scan_el_ts_show(struct device *dev, @@ -706,7 +705,7 @@ static unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev) } static int iio_compute_scan_bytes(struct iio_dev *indio_dev, - const unsigned long *mask, bool timestamp) + const unsigned long *mask, bool timestamp) { unsigned int bytes = 0; int length, i, largest = 0; @@ -732,7 +731,7 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, } static void iio_buffer_activate(struct iio_dev *indio_dev, - struct iio_buffer *buffer) + struct iio_buffer *buffer) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); @@ -753,12 +752,12 @@ static void iio_buffer_deactivate_all(struct iio_dev *indio_dev) struct iio_buffer *buffer, *_buffer; list_for_each_entry_safe(buffer, _buffer, - &iio_dev_opaque->buffer_list, buffer_list) + &iio_dev_opaque->buffer_list, buffer_list) iio_buffer_deactivate(buffer); } static int iio_buffer_enable(struct iio_buffer *buffer, - struct iio_dev *indio_dev) + struct iio_dev *indio_dev) { if (!buffer->access->enable) return 0; @@ -766,7 +765,7 @@ static int iio_buffer_enable(struct iio_buffer *buffer, } static int iio_buffer_disable(struct iio_buffer *buffer, - struct iio_dev *indio_dev) + struct iio_dev *indio_dev) { if (!buffer->access->disable) return 0; @@ -774,7 +773,7 @@ static int iio_buffer_disable(struct iio_buffer *buffer, } static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev, - struct iio_buffer *buffer) + struct iio_buffer *buffer) { unsigned int bytes; @@ -782,13 +781,13 @@ static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev, return; bytes = iio_compute_scan_bytes(indio_dev, buffer->scan_mask, - buffer->scan_timestamp); + buffer->scan_timestamp); buffer->access->set_bytes_per_datum(buffer, bytes); } static int iio_buffer_request_update(struct iio_dev *indio_dev, - struct iio_buffer *buffer) + struct iio_buffer *buffer) { int ret; @@ -797,7 +796,7 @@ static int iio_buffer_request_update(struct iio_dev *indio_dev, ret = buffer->access->request_update(buffer); if (ret) { dev_dbg(&indio_dev->dev, - "Buffer not started: buffer parameter update failed (%d)\n", + "Buffer not started: buffer parameter update failed (%d)\n", ret); return ret; } @@ -807,7 +806,7 @@ static int iio_buffer_request_update(struct iio_dev *indio_dev, } static void iio_free_scan_mask(struct iio_dev *indio_dev, - const unsigned long *mask) + const unsigned long *mask) { /* If the mask is dynamically allocated free it, otherwise do nothing */ if (!indio_dev->available_scan_masks) @@ -823,8 +822,9 @@ struct iio_device_config { }; static int iio_verify_update(struct iio_dev *indio_dev, - struct iio_buffer *insert_buffer, struct iio_buffer *remove_buffer, - struct iio_device_config *config) + struct iio_buffer *insert_buffer, + struct iio_buffer *remove_buffer, + struct iio_device_config *config) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); unsigned long *compound_mask; @@ -864,7 +864,7 @@ static int iio_verify_update(struct iio_dev *indio_dev, if (insert_buffer) { modes &= insert_buffer->access->modes; config->watermark = min(config->watermark, - insert_buffer->watermark); + insert_buffer->watermark); } /* Definitely possible for devices to support both of these. */ @@ -890,7 +890,7 @@ static int iio_verify_update(struct iio_dev *indio_dev, /* What scan mask do we actually have? */ compound_mask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL); - if (compound_mask == NULL) + if (!compound_mask) return -ENOMEM; scan_timestamp = false; @@ -911,18 +911,18 @@ static int iio_verify_update(struct iio_dev *indio_dev, if (indio_dev->available_scan_masks) { scan_mask = iio_scan_mask_match(indio_dev->available_scan_masks, - indio_dev->masklength, - compound_mask, - strict_scanmask); + indio_dev->masklength, + compound_mask, + strict_scanmask); bitmap_free(compound_mask); - if (scan_mask == NULL) + if (!scan_mask) return -EINVAL; } else { scan_mask = compound_mask; } config->scan_bytes = iio_compute_scan_bytes(indio_dev, - scan_mask, scan_timestamp); + scan_mask, scan_timestamp); config->scan_mask = scan_mask; config->scan_timestamp = scan_timestamp; @@ -954,16 +954,16 @@ static void iio_buffer_demux_free(struct iio_buffer *buffer) } static int iio_buffer_add_demux(struct iio_buffer *buffer, - struct iio_demux_table **p, unsigned int in_loc, unsigned int out_loc, - unsigned int length) + struct iio_demux_table **p, unsigned int in_loc, + unsigned int out_loc, + unsigned int length) { - if (*p && (*p)->from + (*p)->length == in_loc && - (*p)->to + (*p)->length == out_loc) { + (*p)->to + (*p)->length == out_loc) { (*p)->length += length; } else { *p = kmalloc(sizeof(**p), GFP_KERNEL); - if (*p == NULL) + if (!(*p)) return -ENOMEM; (*p)->from = in_loc; (*p)->to = out_loc; @@ -1027,7 +1027,7 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, out_loc += length; } buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL); - if (buffer->demux_bounce == NULL) { + if (!buffer->demux_bounce) { ret = -ENOMEM; goto error_clear_mux_table; } @@ -1060,7 +1060,7 @@ error_clear_mux_table: } static int iio_enable_buffers(struct iio_dev *indio_dev, - struct iio_device_config *config) + struct iio_device_config *config) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); struct iio_buffer *buffer, *tmp = NULL; @@ -1078,7 +1078,7 @@ static int iio_enable_buffers(struct iio_dev *indio_dev, ret = indio_dev->setup_ops->preenable(indio_dev); if (ret) { dev_dbg(&indio_dev->dev, - "Buffer not started: buffer preenable failed (%d)\n", ret); + "Buffer not started: buffer preenable failed (%d)\n", ret); goto err_undo_config; } } @@ -1118,7 +1118,7 @@ static int iio_enable_buffers(struct iio_dev *indio_dev, ret = indio_dev->setup_ops->postenable(indio_dev); if (ret) { dev_dbg(&indio_dev->dev, - "Buffer not started: postenable failed (%d)\n", ret); + "Buffer not started: postenable failed (%d)\n", ret); goto err_detach_pollfunc; } } @@ -1194,15 +1194,15 @@ static int iio_disable_buffers(struct iio_dev *indio_dev) } static int __iio_update_buffers(struct iio_dev *indio_dev, - struct iio_buffer *insert_buffer, - struct iio_buffer *remove_buffer) + struct iio_buffer *insert_buffer, + struct iio_buffer *remove_buffer) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); struct iio_device_config new_config; int ret; ret = iio_verify_update(indio_dev, insert_buffer, remove_buffer, - &new_config); + &new_config); if (ret) return ret; @@ -1258,7 +1258,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, return 0; if (insert_buffer && - (insert_buffer->direction == IIO_BUFFER_DIRECTION_OUT)) + insert_buffer->direction == IIO_BUFFER_DIRECTION_OUT) return -EINVAL; mutex_lock(&iio_dev_opaque->info_exist_lock); @@ -1275,7 +1275,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, goto out_unlock; } - if (indio_dev->info == NULL) { + if (!indio_dev->info) { ret = -ENODEV; goto out_unlock; } @@ -1615,7 +1615,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, buffer_attrcount = 0; if (buffer->attrs) { - while (buffer->attrs[buffer_attrcount] != NULL) + while (buffer->attrs[buffer_attrcount]) buffer_attrcount++; } buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs); @@ -1643,7 +1643,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, } ret = iio_buffer_add_channel_sysfs(indio_dev, buffer, - &channels[i]); + &channels[i]); if (ret < 0) goto error_cleanup_dynamic; scan_el_attrcount += ret; @@ -1651,10 +1651,10 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, iio_dev_opaque->scan_index_timestamp = channels[i].scan_index; } - if (indio_dev->masklength && buffer->scan_mask == NULL) { + if (indio_dev->masklength && !buffer->scan_mask) { buffer->scan_mask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL); - if (buffer->scan_mask == NULL) { + if (!buffer->scan_mask) { ret = -ENOMEM; goto error_cleanup_dynamic; } @@ -1771,7 +1771,7 @@ int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev) goto error_unwind_sysfs_and_mask; } - sz = sizeof(*(iio_dev_opaque->buffer_ioctl_handler)); + sz = sizeof(*iio_dev_opaque->buffer_ioctl_handler); iio_dev_opaque->buffer_ioctl_handler = kzalloc(sz, GFP_KERNEL); if (!iio_dev_opaque->buffer_ioctl_handler) { ret = -ENOMEM; @@ -1820,14 +1820,14 @@ void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev) * a time. */ bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev, - const unsigned long *mask) + const unsigned long *mask) { return bitmap_weight(mask, indio_dev->masklength) == 1; } EXPORT_SYMBOL_GPL(iio_validate_scan_mask_onehot); static const void *iio_demux(struct iio_buffer *buffer, - const void *datain) + const void *datain) { struct iio_demux_table *t; diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 784dc1e00310..f207e36b12cc 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -322,7 +322,7 @@ int iio_trigger_attach_poll_func(struct iio_trigger *trig, * this is the case if the IIO device and the trigger device share the * same parent device. */ - if (pf->indio_dev->dev.parent == trig->dev.parent) + if (iio_validate_own_trigger(pf->indio_dev, trig)) trig->attached_own_device = true; return ret; @@ -729,6 +729,26 @@ bool iio_trigger_using_own(struct iio_dev *indio_dev) EXPORT_SYMBOL(iio_trigger_using_own); /** + * iio_validate_own_trigger - Check if a trigger and IIO device belong to + * the same device + * @idev: the IIO device to check + * @trig: the IIO trigger to check + * + * This function can be used as the validate_trigger callback for triggers that + * can only be attached to their own device. + * + * Return: 0 if both the trigger and the IIO device belong to the same + * device, -EINVAL otherwise. + */ +int iio_validate_own_trigger(struct iio_dev *idev, struct iio_trigger *trig) +{ + if (idev->dev.parent != trig->dev.parent) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL_GPL(iio_validate_own_trigger); + +/** * iio_trigger_validate_own_device - Check if a trigger and IIO device belong to * the same device * @trig: The IIO trigger to check 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, }; diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 45abdcce6bc0..c74d11943ec7 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -1046,7 +1046,7 @@ static struct i2c_driver ak8974_driver = { .pm = pm_ptr(&ak8974_dev_pm_ops), .of_match_table = ak8974_of_match, }, - .probe_new = ak8974_probe, + .probe = ak8974_probe, .remove = ak8974_remove, .id_table = ak8974_id, }; diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 924b481a3034..eb706d0bf70b 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -1110,7 +1110,7 @@ static struct i2c_driver ak8975_driver = { .of_match_table = ak8975_of_match, .acpi_match_table = ak_acpi_match, }, - .probe_new = ak8975_probe, + .probe = ak8975_probe, .remove = ak8975_remove, .id_table = ak8975_id, }; diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c index 44b8960eea17..281d1fa31c8e 100644 --- a/drivers/iio/magnetometer/bmc150_magn_i2c.c +++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c @@ -71,7 +71,7 @@ static struct i2c_driver bmc150_magn_driver = { .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match), .pm = &bmc150_magn_pm_ops, }, - .probe_new = bmc150_magn_i2c_probe, + .probe = bmc150_magn_i2c_probe, .remove = bmc150_magn_i2c_remove, .id_table = bmc150_magn_i2c_id, }; diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c index 7ef2b1d56289..bdd2784a9f86 100644 --- a/drivers/iio/magnetometer/hmc5843_i2c.c +++ b/drivers/iio/magnetometer/hmc5843_i2c.c @@ -95,7 +95,7 @@ static struct i2c_driver hmc5843_driver = { .of_match_table = hmc5843_of_match, }, .id_table = hmc5843_id, - .probe_new = hmc5843_i2c_probe, + .probe = hmc5843_i2c_probe, .remove = hmc5843_i2c_remove, }; module_i2c_driver(hmc5843_driver); diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index 661176a885ad..deffe3ca9004 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -641,7 +641,7 @@ static struct i2c_driver mag3110_driver = { .of_match_table = mag3110_of_match, .pm = pm_sleep_ptr(&mag3110_pm_ops), }, - .probe_new = mag3110_probe, + .probe = mag3110_probe, .remove = mag3110_remove, .id_table = mag3110_id, }; diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index 756dadbad106..b495b8a63928 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -575,7 +575,7 @@ static struct i2c_driver mmc35240_driver = { .pm = pm_sleep_ptr(&mmc35240_pm_ops), .acpi_match_table = ACPI_PTR(mmc35240_acpi_match), }, - .probe_new = mmc35240_probe, + .probe = mmc35240_probe, .id_table = mmc35240_id, }; diff --git a/drivers/iio/magnetometer/rm3100-i2c.c b/drivers/iio/magnetometer/rm3100-i2c.c index ba669ab7113d..ac7276b3798c 100644 --- a/drivers/iio/magnetometer/rm3100-i2c.c +++ b/drivers/iio/magnetometer/rm3100-i2c.c @@ -45,7 +45,7 @@ static struct i2c_driver rm3100_driver = { .name = "rm3100-i2c", .of_match_table = rm3100_dt_match, }, - .probe_new = rm3100_probe, + .probe = rm3100_probe, }; module_i2c_driver(rm3100_driver); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 8faa7409d9e1..6cc0dfd31821 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -427,6 +427,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM9DS0_IMU_DEV_NAME, + [1] = LSM303D_IMU_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_magn_4_16bit_channels, .odr = { diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index cc0e0e94b129..950826dd20bf 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -111,7 +111,7 @@ static struct i2c_driver st_magn_driver = { .name = "st-magn-i2c", .of_match_table = st_magn_of_match, }, - .probe_new = st_magn_i2c_probe, + .probe = st_magn_i2c_probe, .id_table = st_magn_id_table, }; module_i2c_driver(st_magn_driver); diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c index e155a75b3cd2..c5e5c4ad681e 100644 --- a/drivers/iio/magnetometer/tmag5273.c +++ b/drivers/iio/magnetometer/tmag5273.c @@ -734,7 +734,7 @@ static struct i2c_driver tmag5273_driver = { .of_match_table = tmag5273_of_match, .pm = pm_ptr(&tmag5273_pm_ops), }, - .probe_new = tmag5273_probe, + .probe = tmag5273_probe, .id_table = tmag5273_id, }; module_i2c_driver(tmag5273_driver); diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 753717158b07..c5e485bfc6fc 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -1605,7 +1605,7 @@ static struct i2c_driver yas5xx_driver = { .of_match_table = yas5xx_of_match, .pm = pm_ptr(&yas5xx_dev_pm_ops), }, - .probe_new = yas5xx_probe, + .probe = yas5xx_probe, .remove = yas5xx_remove, .id_table = yas5xx_id, }; diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig index 01dd3f858d99..e6a9a3c67845 100644 --- a/drivers/iio/potentiometer/Kconfig +++ b/drivers/iio/potentiometer/Kconfig @@ -136,4 +136,14 @@ config TPL0102 To compile this driver as a module, choose M here: the module will be called tpl0102. +config X9250 + tristate "Renesas X9250 quad controlled potentiometers" + depends on SPI + help + Enable support for the Renesas X9250 quad controlled + potentiometers. + + To compile this driver as a module, choose M here: the module + will be called x9250. + endmenu diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile index 5ebb8e3bbd76..d11fb739176c 100644 --- a/drivers/iio/potentiometer/Makefile +++ b/drivers/iio/potentiometer/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_MCP4131) += mcp4131.o obj-$(CONFIG_MCP4531) += mcp4531.o obj-$(CONFIG_MCP41010) += mcp41010.o obj-$(CONFIG_TPL0102) += tpl0102.o +obj-$(CONFIG_X9250) += x9250.o diff --git a/drivers/iio/potentiometer/ad5110.c b/drivers/iio/potentiometer/ad5110.c index 8fbcce482989..991e745c4f93 100644 --- a/drivers/iio/potentiometer/ad5110.c +++ b/drivers/iio/potentiometer/ad5110.c @@ -334,7 +334,7 @@ static struct i2c_driver ad5110_driver = { .name = "ad5110", .of_match_table = ad5110_of_match, }, - .probe_new = ad5110_probe, + .probe = ad5110_probe, .id_table = ad5110_id, }; module_i2c_driver(ad5110_driver); diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c index aa140d632101..b17941e4c2f7 100644 --- a/drivers/iio/potentiometer/ad5272.c +++ b/drivers/iio/potentiometer/ad5272.c @@ -218,7 +218,7 @@ static struct i2c_driver ad5272_driver = { .name = "ad5272", .of_match_table = ad5272_dt_ids, }, - .probe_new = ad5272_probe, + .probe = ad5272_probe, .id_table = ad5272_id, }; diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 0b5e475807cb..fc183e0790da 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -252,7 +252,7 @@ static struct i2c_driver ds1803_driver = { .name = "ds1803", .of_match_table = ds1803_dt_ids, }, - .probe_new = ds1803_probe, + .probe = ds1803_probe, .id_table = ds1803_id, }; diff --git a/drivers/iio/potentiometer/max5432.c b/drivers/iio/potentiometer/max5432.c index 94ef27ef3fb5..c8e2481dadb5 100644 --- a/drivers/iio/potentiometer/max5432.c +++ b/drivers/iio/potentiometer/max5432.c @@ -123,7 +123,7 @@ static struct i2c_driver max5432_driver = { .name = "max5432", .of_match_table = max5432_dt_ids, }, - .probe_new = max5432_probe, + .probe = max5432_probe, }; module_i2c_driver(max5432_driver); diff --git a/drivers/iio/potentiometer/mcp4018.c b/drivers/iio/potentiometer/mcp4018.c index c0e171fec062..89daecc90305 100644 --- a/drivers/iio/potentiometer/mcp4018.c +++ b/drivers/iio/potentiometer/mcp4018.c @@ -174,7 +174,7 @@ static struct i2c_driver mcp4018_driver = { .name = "mcp4018", .of_match_table = mcp4018_of_match, }, - .probe_new = mcp4018_probe, + .probe = mcp4018_probe, .id_table = mcp4018_id, }; diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c index c25f84b4a270..c513c00c8243 100644 --- a/drivers/iio/potentiometer/mcp4531.c +++ b/drivers/iio/potentiometer/mcp4531.c @@ -385,7 +385,7 @@ static struct i2c_driver mcp4531_driver = { .name = "mcp4531", .of_match_table = mcp4531_of_match, }, - .probe_new = mcp4531_probe, + .probe = mcp4531_probe, .id_table = mcp4531_id, }; diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c index a3465b413b0c..8923ccb0fc4f 100644 --- a/drivers/iio/potentiometer/tpl0102.c +++ b/drivers/iio/potentiometer/tpl0102.c @@ -161,7 +161,7 @@ static struct i2c_driver tpl0102_driver = { .driver = { .name = "tpl0102", }, - .probe_new = tpl0102_probe, + .probe = tpl0102_probe, .id_table = tpl0102_id, }; diff --git a/drivers/iio/potentiometer/x9250.c b/drivers/iio/potentiometer/x9250.c new file mode 100644 index 000000000000..735348492699 --- /dev/null +++ b/drivers/iio/potentiometer/x9250.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * + * x9250.c -- Renesas X9250 potentiometers IIO driver + * + * Copyright 2023 CS GROUP France + * + * Author: Herve Codina <herve.codina@bootlin.com> + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/iio/iio.h> +#include <linux/limits.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> + +struct x9250_cfg { + const char *name; + int kohms; +}; + +struct x9250 { + struct spi_device *spi; + const struct x9250_cfg *cfg; + struct gpio_desc *wp_gpio; +}; + +#define X9250_ID 0x50 +#define X9250_CMD_RD_WCR(_p) (0x90 | (_p)) +#define X9250_CMD_WR_WCR(_p) (0xa0 | (_p)) + +static int x9250_write8(struct x9250 *x9250, u8 cmd, u8 val) +{ + u8 txbuf[3]; + + txbuf[0] = X9250_ID; + txbuf[1] = cmd; + txbuf[2] = val; + + return spi_write_then_read(x9250->spi, txbuf, ARRAY_SIZE(txbuf), NULL, 0); +} + +static int x9250_read8(struct x9250 *x9250, u8 cmd, u8 *val) +{ + u8 txbuf[2]; + + txbuf[0] = X9250_ID; + txbuf[1] = cmd; + + return spi_write_then_read(x9250->spi, txbuf, ARRAY_SIZE(txbuf), val, 1); +} + +#define X9250_CHANNEL(ch) { \ + .type = IIO_RESISTANCE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (ch), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_RAW), \ +} + +static const struct iio_chan_spec x9250_channels[] = { + X9250_CHANNEL(0), + X9250_CHANNEL(1), + X9250_CHANNEL(2), + X9250_CHANNEL(3), +}; + +static int x9250_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct x9250 *x9250 = iio_priv(indio_dev); + int ch = chan->channel; + int ret; + u8 v; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = x9250_read8(x9250, X9250_CMD_RD_WCR(ch), &v); + if (ret) + return ret; + *val = v; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + *val = 1000 * x9250->cfg->kohms; + *val2 = U8_MAX; + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; +} + +static int x9250_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, long mask) +{ + static const int range[] = {0, 1, 255}; /* min, step, max */ + + switch (mask) { + case IIO_CHAN_INFO_RAW: + *length = ARRAY_SIZE(range); + *vals = range; + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; + } + + return -EINVAL; +} + +static int x9250_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct x9250 *x9250 = iio_priv(indio_dev); + int ch = chan->channel; + int ret; + + if (mask != IIO_CHAN_INFO_RAW) + return -EINVAL; + + if (val > U8_MAX || val < 0) + return -EINVAL; + + gpiod_set_value_cansleep(x9250->wp_gpio, 0); + ret = x9250_write8(x9250, X9250_CMD_WR_WCR(ch), val); + gpiod_set_value_cansleep(x9250->wp_gpio, 1); + + return ret; +} + +static const struct iio_info x9250_info = { + .read_raw = x9250_read_raw, + .read_avail = x9250_read_avail, + .write_raw = x9250_write_raw, +}; + +enum x9250_type { + X9250T, + X9250U, +}; + +static const struct x9250_cfg x9250_cfg[] = { + [X9250T] = { .name = "x9250t", .kohms = 100, }, + [X9250U] = { .name = "x9250u", .kohms = 50, }, +}; + +static const char *const x9250_regulator_names[] = { + "vcc", + "avp", + "avn", +}; + +static int x9250_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct x9250 *x9250; + int ret; + + ret = devm_regulator_bulk_get_enable(&spi->dev, ARRAY_SIZE(x9250_regulator_names), + x9250_regulator_names); + if (ret) + return dev_err_probe(&spi->dev, ret, "Failed to get regulators\n"); + + /* + * The x9250 needs a 5ms maximum delay after the power-supplies are set + * before performing the first write (1ms for the first read). + */ + usleep_range(5000, 6000); + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*x9250)); + if (!indio_dev) + return -ENOMEM; + + x9250 = iio_priv(indio_dev); + x9250->spi = spi; + x9250->cfg = spi_get_device_match_data(spi); + x9250->wp_gpio = devm_gpiod_get_optional(&spi->dev, "wp", GPIOD_OUT_LOW); + if (IS_ERR(x9250->wp_gpio)) + return dev_err_probe(&spi->dev, PTR_ERR(x9250->wp_gpio), + "failed to get wp gpio\n"); + + indio_dev->info = &x9250_info; + indio_dev->channels = x9250_channels; + indio_dev->num_channels = ARRAY_SIZE(x9250_channels); + indio_dev->name = x9250->cfg->name; + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id x9250_of_match[] = { + { .compatible = "renesas,x9250t", .data = &x9250_cfg[X9250T]}, + { .compatible = "renesas,x9250u", .data = &x9250_cfg[X9250U]}, + { } +}; +MODULE_DEVICE_TABLE(of, x9250_of_match); + +static const struct spi_device_id x9250_id_table[] = { + { "x9250t", (kernel_ulong_t)&x9250_cfg[X9250T] }, + { "x9250u", (kernel_ulong_t)&x9250_cfg[X9250U] }, + { } +}; +MODULE_DEVICE_TABLE(spi, x9250_id_table); + +static struct spi_driver x9250_spi_driver = { + .driver = { + .name = "x9250", + .of_match_table = x9250_of_match, + }, + .id_table = x9250_id_table, + .probe = x9250_probe, +}; + +module_spi_driver(x9250_spi_driver); + +MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); +MODULE_DESCRIPTION("X9250 ALSA SoC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index 0083e858c21e..bd0f2c3bf2f2 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -416,7 +416,7 @@ static struct i2c_driver lmp91000_driver = { .name = LMP91000_DRV_NAME, .of_match_table = lmp91000_of_match, }, - .probe_new = lmp91000_probe, + .probe = lmp91000_probe, .remove = lmp91000_remove, .id_table = lmp91000_id, }; diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 02b97e89de50..7b4c2af32852 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -148,6 +148,19 @@ config MPL3115 To compile this driver as a module, choose M here: the module will be called mpl3115. +config MPRLS0025PA + tristate "Honeywell MPRLS0025PA (MicroPressure sensors series)" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say Y here to build support for the Honeywell MicroPressure pressure + sensor series. There are many different types with different pressure + range. These ranges can be set up in the device tree. + + To compile this driver as a module, choose M here: the module will be + called mprls0025pa. + config MS5611 tristate "Measurement Specialties MS5611 pressure sensor driver" select IIO_BUFFER diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index 083ae87ff48f..c90f77210e94 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_MPL115) += mpl115.o obj-$(CONFIG_MPL115_I2C) += mpl115_i2c.o obj-$(CONFIG_MPL115_SPI) += mpl115_spi.o obj-$(CONFIG_MPL3115) += mpl3115.o +obj-$(CONFIG_MPRLS0025PA) += mprls0025pa.o obj-$(CONFIG_MS5611) += ms5611_core.o obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o diff --git a/drivers/iio/pressure/abp060mg.c b/drivers/iio/pressure/abp060mg.c index c0140779366a..752a63c06b44 100644 --- a/drivers/iio/pressure/abp060mg.c +++ b/drivers/iio/pressure/abp060mg.c @@ -255,7 +255,7 @@ static struct i2c_driver abp060mg_driver = { .driver = { .name = "abp060mg", }, - .probe_new = abp060mg_probe, + .probe = abp060mg_probe, .id_table = abp060mg_id_table, }; module_i2c_driver(abp060mg_driver); diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index 567b945e6427..dbe630ad05b5 100644 --- a/drivers/iio/pressure/bmp280-i2c.c +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -56,7 +56,7 @@ static struct i2c_driver bmp280_i2c_driver = { .of_match_table = bmp280_of_i2c_match, .pm = pm_ptr(&bmp280_dev_pm_ops), }, - .probe_new = bmp280_i2c_probe, + .probe = bmp280_i2c_probe, .id_table = bmp280_i2c_id, }; module_i2c_driver(bmp280_i2c_driver); diff --git a/drivers/iio/pressure/dlhl60d.c b/drivers/iio/pressure/dlhl60d.c index 43650b048d62..28c8269ba65d 100644 --- a/drivers/iio/pressure/dlhl60d.c +++ b/drivers/iio/pressure/dlhl60d.c @@ -362,7 +362,7 @@ static struct i2c_driver dlh_driver = { .name = "dlhl60d", .of_match_table = dlh_of_match, }, - .probe_new = dlh_probe, + .probe = dlh_probe, .id_table = dlh_id, }; module_i2c_driver(dlh_driver); diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index 2af275a24ff9..b10dbf5cf494 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -887,7 +887,7 @@ static struct i2c_driver dps310_driver = { .name = DPS310_DEV_NAME, .acpi_match_table = dps310_acpi_match, }, - .probe_new = dps310_probe, + .probe = dps310_probe, .id_table = dps310_id, }; module_i2c_driver(dps310_driver); diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c index bd1f71a99cfa..8bdb279129fa 100644 --- a/drivers/iio/pressure/hp03.c +++ b/drivers/iio/pressure/hp03.c @@ -282,7 +282,7 @@ static struct i2c_driver hp03_driver = { .name = "hp03", .of_match_table = hp03_of_match, }, - .probe_new = hp03_probe, + .probe = hp03_probe, .id_table = hp03_id, }; module_i2c_driver(hp03_driver); diff --git a/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c index b6d2ff464341..a072de6cb59c 100644 --- a/drivers/iio/pressure/hp206c.c +++ b/drivers/iio/pressure/hp206c.c @@ -409,7 +409,7 @@ MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match); #endif static struct i2c_driver hp206c_driver = { - .probe_new = hp206c_probe, + .probe = hp206c_probe, .id_table = hp206c_id, .driver = { .name = "hp206c", diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c index 407cf25ea0e3..2086f3ef338f 100644 --- a/drivers/iio/pressure/icp10100.c +++ b/drivers/iio/pressure/icp10100.c @@ -648,7 +648,7 @@ static struct i2c_driver icp10100_driver = { .pm = pm_ptr(&icp10100_pm), .of_match_table = icp10100_of_match, }, - .probe_new = icp10100_probe, + .probe = icp10100_probe, .id_table = icp10100_id, }; module_i2c_driver(icp10100_driver); diff --git a/drivers/iio/pressure/mpl115_i2c.c b/drivers/iio/pressure/mpl115_i2c.c index ade4dd854ddf..fcbdadf4a511 100644 --- a/drivers/iio/pressure/mpl115_i2c.c +++ b/drivers/iio/pressure/mpl115_i2c.c @@ -55,7 +55,7 @@ static struct i2c_driver mpl115_i2c_driver = { .name = "mpl115", .pm = pm_ptr(&mpl115_dev_pm_ops), }, - .probe_new = mpl115_i2c_probe, + .probe = mpl115_i2c_probe, .id_table = mpl115_i2c_id, }; module_i2c_driver(mpl115_i2c_driver); diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index 72e811a5c96e..7aa19584c340 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -335,7 +335,7 @@ static struct i2c_driver mpl3115_driver = { .of_match_table = mpl3115_of_match, .pm = pm_sleep_ptr(&mpl3115_pm_ops), }, - .probe_new = mpl3115_probe, + .probe = mpl3115_probe, .remove = mpl3115_remove, .id_table = mpl3115_id, }; diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c new file mode 100644 index 000000000000..30fb2de36821 --- /dev/null +++ b/drivers/iio/pressure/mprls0025pa.c @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MPRLS0025PA - Honeywell MicroPressure pressure sensor series driver + * + * Copyright (c) Andreas Klinger <ak@it-klinger.de> + * + * Data sheet: + * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/ + * products/sensors/pressure-sensors/board-mount-pressure-sensors/ + * micropressure-mpr-series/documents/ + * sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf + * + * 7-bit I2C default slave address: 0x18 + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/math64.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/units.h> + +#include <linux/gpio/consumer.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#include <linux/regulator/consumer.h> + +#include <asm/unaligned.h> + +/* bits in i2c status byte */ +#define MPR_I2C_POWER BIT(6) /* device is powered */ +#define MPR_I2C_BUSY BIT(5) /* device is busy */ +#define MPR_I2C_MEMORY BIT(2) /* integrity test passed */ +#define MPR_I2C_MATH BIT(0) /* internal math saturation */ + +/* + * support _RAW sysfs interface: + * + * Calculation formula from the datasheet: + * pressure = (press_cnt - outputmin) * scale + pmin + * with: + * * pressure - measured pressure in Pascal + * * press_cnt - raw value read from sensor + * * pmin - minimum pressure range value of sensor (data->pmin) + * * pmax - maximum pressure range value of sensor (data->pmax) + * * outputmin - minimum numerical range raw value delivered by sensor + * (mpr_func_spec.output_min) + * * outputmax - maximum numerical range raw value delivered by sensor + * (mpr_func_spec.output_max) + * * scale - (pmax - pmin) / (outputmax - outputmin) + * + * formula of the userspace: + * pressure = (raw + offset) * scale + * + * Values given to the userspace in sysfs interface: + * * raw - press_cnt + * * offset - (-1 * outputmin) - pmin / scale + * note: With all sensors from the datasheet pmin = 0 + * which reduces the offset to (-1 * outputmin) + */ + +/* + * transfer function A: 10% to 90% of 2^24 + * transfer function B: 2.5% to 22.5% of 2^24 + * transfer function C: 20% to 80% of 2^24 + */ +enum mpr_func_id { + MPR_FUNCTION_A, + MPR_FUNCTION_B, + MPR_FUNCTION_C, +}; + +struct mpr_func_spec { + u32 output_min; + u32 output_max; +}; + +static const struct mpr_func_spec mpr_func_spec[] = { + [MPR_FUNCTION_A] = {.output_min = 1677722, .output_max = 15099494}, + [MPR_FUNCTION_B] = {.output_min = 419430, .output_max = 3774874}, + [MPR_FUNCTION_C] = {.output_min = 3355443, .output_max = 13421773}, +}; + +struct mpr_chan { + s32 pres; /* pressure value */ + s64 ts; /* timestamp */ +}; + +struct mpr_data { + struct i2c_client *client; + struct mutex lock; /* + * access to device during read + */ + u32 pmin; /* minimal pressure in pascal */ + u32 pmax; /* maximal pressure in pascal */ + enum mpr_func_id function; /* transfer function */ + u32 outmin; /* + * minimal numerical range raw + * value from sensor + */ + u32 outmax; /* + * maximal numerical range raw + * value from sensor + */ + int scale; /* int part of scale */ + int scale2; /* nano part of scale */ + int offset; /* int part of offset */ + int offset2; /* nano part of offset */ + struct gpio_desc *gpiod_reset; /* reset */ + int irq; /* + * end of conversion irq; + * used to distinguish between + * irq mode and reading in a + * loop until data is ready + */ + struct completion completion; /* handshake from irq to read */ + struct mpr_chan chan; /* + * channel values for buffered + * mode + */ +}; + +static const struct iio_chan_spec mpr_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 32, + .storagebits = 32, + .endianness = IIO_CPU, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static void mpr_reset(struct mpr_data *data) +{ + if (data->gpiod_reset) { + gpiod_set_value(data->gpiod_reset, 0); + udelay(10); + gpiod_set_value(data->gpiod_reset, 1); + } +} + +/** + * mpr_read_pressure() - Read pressure value from sensor via I2C + * @data: Pointer to private data struct. + * @press: Output value read from sensor. + * + * Reading from the sensor by sending and receiving I2C telegrams. + * + * If there is an end of conversion (EOC) interrupt registered the function + * waits for a maximum of one second for the interrupt. + * + * Context: The function can sleep and data->lock should be held when calling it + * Return: + * * 0 - OK, the pressure value could be read + * * -ETIMEDOUT - Timeout while waiting for the EOC interrupt or busy flag is + * still set after nloops attempts of reading + */ +static int mpr_read_pressure(struct mpr_data *data, s32 *press) +{ + struct device *dev = &data->client->dev; + int ret, i; + u8 wdata[] = {0xAA, 0x00, 0x00}; + s32 status; + int nloops = 10; + u8 buf[4]; + + reinit_completion(&data->completion); + + ret = i2c_master_send(data->client, wdata, sizeof(wdata)); + if (ret < 0) { + dev_err(dev, "error while writing ret: %d\n", ret); + return ret; + } + if (ret != sizeof(wdata)) { + dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret, + (u32)sizeof(wdata)); + return -EIO; + } + + if (data->irq > 0) { + ret = wait_for_completion_timeout(&data->completion, HZ); + if (!ret) { + dev_err(dev, "timeout while waiting for eoc irq\n"); + return -ETIMEDOUT; + } + } else { + /* wait until status indicates data is ready */ + for (i = 0; i < nloops; i++) { + /* + * datasheet only says to wait at least 5 ms for the + * data but leave the maximum response time open + * --> let's try it nloops (10) times which seems to be + * quite long + */ + usleep_range(5000, 10000); + status = i2c_smbus_read_byte(data->client); + if (status < 0) { + dev_err(dev, + "error while reading, status: %d\n", + status); + return status; + } + if (!(status & MPR_I2C_BUSY)) + break; + } + if (i == nloops) { + dev_err(dev, "timeout while reading\n"); + return -ETIMEDOUT; + } + } + + ret = i2c_master_recv(data->client, buf, sizeof(buf)); + if (ret < 0) { + dev_err(dev, "error in i2c_master_recv ret: %d\n", ret); + return ret; + } + if (ret != sizeof(buf)) { + dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret, + (u32)sizeof(buf)); + return -EIO; + } + + if (buf[0] & MPR_I2C_BUSY) { + /* + * it should never be the case that status still indicates + * business + */ + dev_err(dev, "data still not ready: %08x\n", buf[0]); + return -ETIMEDOUT; + } + + *press = get_unaligned_be24(&buf[1]); + + dev_dbg(dev, "received: %*ph cnt: %d\n", ret, buf, *press); + + return 0; +} + +static irqreturn_t mpr_eoc_handler(int irq, void *p) +{ + struct mpr_data *data = p; + + complete(&data->completion); + + return IRQ_HANDLED; +} + +static irqreturn_t mpr_trigger_handler(int irq, void *p) +{ + int ret; + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct mpr_data *data = iio_priv(indio_dev); + + mutex_lock(&data->lock); + ret = mpr_read_pressure(data, &data->chan.pres); + if (ret < 0) + goto err; + + iio_push_to_buffers_with_timestamp(indio_dev, &data->chan, + iio_get_time_ns(indio_dev)); + +err: + mutex_unlock(&data->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int mpr_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long mask) +{ + int ret; + s32 pressure; + struct mpr_data *data = iio_priv(indio_dev); + + if (chan->type != IIO_PRESSURE) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&data->lock); + ret = mpr_read_pressure(data, &pressure); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + *val = pressure; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = data->scale; + *val2 = data->scale2; + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OFFSET: + *val = data->offset; + *val2 = data->offset2; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static const struct iio_info mpr_info = { + .read_raw = &mpr_read_raw, +}; + +static int mpr_probe(struct i2c_client *client) +{ + int ret; + struct mpr_data *data; + struct iio_dev *indio_dev; + struct device *dev = &client->dev; + s64 scale, offset; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE)) + return dev_err_probe(dev, -EOPNOTSUPP, + "I2C functionality not supported\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return dev_err_probe(dev, -ENOMEM, "couldn't get iio_dev\n"); + + data = iio_priv(indio_dev); + data->client = client; + data->irq = client->irq; + + mutex_init(&data->lock); + init_completion(&data->completion); + + indio_dev->name = "mprls0025pa"; + indio_dev->info = &mpr_info; + indio_dev->channels = mpr_channels; + indio_dev->num_channels = ARRAY_SIZE(mpr_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, + "can't get and enable vdd supply\n"); + + if (dev_fwnode(dev)) { + ret = device_property_read_u32(dev, "honeywell,pmin-pascal", + &data->pmin); + if (ret) + return dev_err_probe(dev, ret, + "honeywell,pmin-pascal could not be read\n"); + ret = device_property_read_u32(dev, "honeywell,pmax-pascal", + &data->pmax); + if (ret) + return dev_err_probe(dev, ret, + "honeywell,pmax-pascal could not be read\n"); + ret = device_property_read_u32(dev, + "honeywell,transfer-function", &data->function); + if (ret) + return dev_err_probe(dev, ret, + "honeywell,transfer-function could not be read\n"); + if (data->function > MPR_FUNCTION_C) + return dev_err_probe(dev, -EINVAL, + "honeywell,transfer-function %d invalid\n", + data->function); + } else { + /* when loaded as i2c device we need to use default values */ + dev_notice(dev, "firmware node not found; using defaults\n"); + data->pmin = 0; + data->pmax = 172369; /* 25 psi */ + data->function = MPR_FUNCTION_A; + } + + data->outmin = mpr_func_spec[data->function].output_min; + data->outmax = mpr_func_spec[data->function].output_max; + + /* use 64 bit calculation for preserving a reasonable precision */ + scale = div_s64(((s64)(data->pmax - data->pmin)) * NANO, + data->outmax - data->outmin); + data->scale = div_s64_rem(scale, NANO, &data->scale2); + /* + * multiply with NANO before dividing by scale and later divide by NANO + * again. + */ + offset = ((-1LL) * (s64)data->outmin) * NANO - + div_s64(div_s64((s64)data->pmin * NANO, scale), NANO); + data->offset = div_s64_rem(offset, NANO, &data->offset2); + + if (data->irq > 0) { + ret = devm_request_irq(dev, data->irq, mpr_eoc_handler, + IRQF_TRIGGER_RISING, client->name, data); + if (ret) + return dev_err_probe(dev, ret, + "request irq %d failed\n", data->irq); + } + + data->gpiod_reset = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(data->gpiod_reset)) + return dev_err_probe(dev, PTR_ERR(data->gpiod_reset), + "request reset-gpio failed\n"); + + mpr_reset(data); + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + mpr_trigger_handler, NULL); + if (ret) + return dev_err_probe(dev, ret, + "iio triggered buffer setup failed\n"); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, + "unable to register iio device\n"); + + return 0; +} + +static const struct of_device_id mpr_matches[] = { + { .compatible = "honeywell,mprls0025pa" }, + { } +}; +MODULE_DEVICE_TABLE(of, mpr_matches); + +static const struct i2c_device_id mpr_id[] = { + { "mprls0025pa" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mpr_id); + +static struct i2c_driver mpr_driver = { + .probe = mpr_probe, + .id_table = mpr_id, + .driver = { + .name = "mprls0025pa", + .of_match_table = mpr_matches, + }, +}; +module_i2c_driver(mpr_driver); + +MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); +MODULE_DESCRIPTION("Honeywell MPRLS0025PA I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c index e3c68a3ed76a..9a0f52321fcb 100644 --- a/drivers/iio/pressure/ms5611_i2c.c +++ b/drivers/iio/pressure/ms5611_i2c.c @@ -125,7 +125,7 @@ static struct i2c_driver ms5611_driver = { .of_match_table = ms5611_i2c_matches, }, .id_table = ms5611_id, - .probe_new = ms5611_i2c_probe, + .probe = ms5611_i2c_probe, }; module_i2c_driver(ms5611_driver); diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index c4981b29dccb..9b3abffb724b 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -238,7 +238,7 @@ static const struct of_device_id ms5637_of_match[] = { MODULE_DEVICE_TABLE(of, ms5637_of_match); static struct i2c_driver ms5637_driver = { - .probe_new = ms5637_probe, + .probe = ms5637_probe, .id_table = ms5637_id, .driver = { .name = "ms5637", diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index f2c3bb568d16..5101552e3f38 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -116,7 +116,7 @@ static struct i2c_driver st_press_driver = { .of_match_table = st_press_of_match, .acpi_match_table = ACPI_PTR(st_press_acpi_match), }, - .probe_new = st_press_i2c_probe, + .probe = st_press_i2c_probe, .id_table = st_press_id_table, }; module_i2c_driver(st_press_driver); diff --git a/drivers/iio/pressure/t5403.c b/drivers/iio/pressure/t5403.c index 2fbf14aff033..a6463c06975e 100644 --- a/drivers/iio/pressure/t5403.c +++ b/drivers/iio/pressure/t5403.c @@ -260,7 +260,7 @@ static struct i2c_driver t5403_driver = { .driver = { .name = "t5403", }, - .probe_new = t5403_probe, + .probe = t5403_probe, .id_table = t5403_id, }; module_i2c_driver(t5403_driver); diff --git a/drivers/iio/pressure/zpa2326_i2c.c b/drivers/iio/pressure/zpa2326_i2c.c index ade465014be1..c7fffbe7c788 100644 --- a/drivers/iio/pressure/zpa2326_i2c.c +++ b/drivers/iio/pressure/zpa2326_i2c.c @@ -76,7 +76,7 @@ static struct i2c_driver zpa2326_i2c_driver = { .of_match_table = zpa2326_i2c_matches, .pm = ZPA2326_PM_OPS, }, - .probe_new = zpa2326_probe_i2c, + .probe = zpa2326_probe_i2c, .remove = zpa2326_remove_i2c, .id_table = zpa2326_i2c_ids, }; diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c index 7b8f40b7ccf3..fe45ca35a124 100644 --- a/drivers/iio/proximity/isl29501.c +++ b/drivers/iio/proximity/isl29501.c @@ -1008,7 +1008,7 @@ static struct i2c_driver isl29501_driver = { .name = "isl29501", }, .id_table = isl29501_id, - .probe_new = isl29501_probe, + .probe = isl29501_probe, }; module_i2c_driver(isl29501_driver); diff --git a/drivers/iio/proximity/mb1232.c b/drivers/iio/proximity/mb1232.c index e70cac8240af..fb1073c8d9f7 100644 --- a/drivers/iio/proximity/mb1232.c +++ b/drivers/iio/proximity/mb1232.c @@ -264,7 +264,7 @@ static struct i2c_driver mb1232_driver = { .name = "maxbotix-mb1232", .of_match_table = of_mb1232_match, }, - .probe_new = mb1232_probe, + .probe = mb1232_probe, .id_table = mb1232_id, }; module_i2c_driver(mb1232_driver); diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index c9eead01a031..2913d5e0fe4f 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -365,7 +365,7 @@ static struct i2c_driver lidar_driver = { .of_match_table = lidar_dt_ids, .pm = pm_ptr(&lidar_pm_ops), }, - .probe_new = lidar_probe, + .probe = lidar_probe, .remove = lidar_remove, .id_table = lidar_id, }; diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c index 44f72b78bd50..f02e83e3f15f 100644 --- a/drivers/iio/proximity/rfd77402.c +++ b/drivers/iio/proximity/rfd77402.c @@ -318,7 +318,7 @@ static struct i2c_driver rfd77402_driver = { .name = RFD77402_DRV_NAME, .pm = pm_sleep_ptr(&rfd77402_pm_ops), }, - .probe_new = rfd77402_probe, + .probe = rfd77402_probe, .id_table = rfd77402_id, }; diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c index 61866d0440f7..a75ea5042876 100644 --- a/drivers/iio/proximity/srf08.c +++ b/drivers/iio/proximity/srf08.c @@ -549,7 +549,7 @@ static struct i2c_driver srf08_driver = { .name = "srf08", .of_match_table = of_srf08_match, }, - .probe_new = srf08_probe, + .probe = srf08_probe, .id_table = srf08_id, }; module_i2c_driver(srf08_driver); diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index 0e4747ccd3cf..d977aacb7491 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -1050,7 +1050,7 @@ static struct i2c_driver sx9310_driver = { */ .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe_new = sx9310_probe, + .probe = sx9310_probe, .id_table = sx9310_id, }; module_i2c_driver(sx9310_driver); diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index 9a40ca32bb1c..438f9c9aba6e 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -1152,7 +1152,7 @@ static struct i2c_driver sx9324_driver = { */ .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe_new = sx9324_probe, + .probe = sx9324_probe, .id_table = sx9324_id, }; module_i2c_driver(sx9324_driver); diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c index a50d9176411a..2c4e14a4fe9f 100644 --- a/drivers/iio/proximity/sx9360.c +++ b/drivers/iio/proximity/sx9360.c @@ -896,7 +896,7 @@ static struct i2c_driver sx9360_driver = { */ .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe_new = sx9360_probe, + .probe = sx9360_probe, .id_table = sx9360_id, }; module_i2c_driver(sx9360_driver); diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 9b2cfcade6a4..550e7d3cd5ee 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -1055,7 +1055,7 @@ static struct i2c_driver sx9500_driver = { .of_match_table = sx9500_of_match, .pm = pm_sleep_ptr(&sx9500_pm_ops), }, - .probe_new = sx9500_probe, + .probe = sx9500_probe, .remove = sx9500_remove, .id_table = sx9500_id, }; diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c index cbc8400c773c..d1ddf85f5383 100644 --- a/drivers/iio/proximity/vcnl3020.c +++ b/drivers/iio/proximity/vcnl3020.c @@ -662,7 +662,7 @@ static struct i2c_driver vcnl3020_driver = { .name = "vcnl3020", .of_match_table = vcnl3020_of_match, }, - .probe_new = vcnl3020_probe, + .probe = vcnl3020_probe, }; module_i2c_driver(vcnl3020_driver); diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index c7c4d33d340f..2cea64bea909 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -294,7 +294,7 @@ static struct i2c_driver vl53l0x_driver = { .name = "vl53l0x-i2c", .of_match_table = st_vl53l0x_dt_match, }, - .probe_new = vl53l0x_probe, + .probe = vl53l0x_probe, .id_table = vl53l0x_id, }; module_i2c_driver(vl53l0x_driver); diff --git a/drivers/iio/temperature/max30208.c b/drivers/iio/temperature/max30208.c index c85c21474711..48be03852cd8 100644 --- a/drivers/iio/temperature/max30208.c +++ b/drivers/iio/temperature/max30208.c @@ -242,7 +242,7 @@ static struct i2c_driver max30208_driver = { .of_match_table = max30208_of_match, .acpi_match_table = max30208_acpi_match, }, - .probe_new = max30208_probe, + .probe = max30208_probe, .id_table = max30208_id_table, }; module_i2c_driver(max30208_driver); diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index 909fadb62349..676dc8701924 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -1,12 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor + * mlx90614.c - Support for Melexis MLX90614/MLX90615 contactless IR temperature sensor * * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> * Copyright (c) 2015 Essensium NV * Copyright (c) 2015 Melexis * - * Driver for the Melexis MLX90614 I2C 16-bit IR thermopile sensor + * Driver for the Melexis MLX90614/MLX90615 I2C 16-bit IR thermopile sensor + * + * MLX90614 - 17-bit ADC + MLX90302 DSP + * MLX90615 - 16-bit ADC + MLX90325 DSP * * (7-bit I2C slave address 0x5a, 100KHz bus speed only!) * @@ -19,12 +22,13 @@ * the "wakeup" GPIO is not given, power management will be disabled. */ +#include <linux/delay.h> #include <linux/err.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> -#include <linux/module.h> -#include <linux/delay.h> #include <linux/jiffies.h> -#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of_device.h> #include <linux/pm_runtime.h> #include <linux/iio/iio.h> @@ -34,16 +38,9 @@ #define MLX90614_OP_EEPROM 0x20 #define MLX90614_OP_SLEEP 0xff -/* RAM offsets with 16-bit data, MSB first */ -#define MLX90614_RAW1 (MLX90614_OP_RAM | 0x04) /* raw data IR channel 1 */ -#define MLX90614_RAW2 (MLX90614_OP_RAM | 0x05) /* raw data IR channel 2 */ -#define MLX90614_TA (MLX90614_OP_RAM | 0x06) /* ambient temperature */ -#define MLX90614_TOBJ1 (MLX90614_OP_RAM | 0x07) /* object 1 temperature */ -#define MLX90614_TOBJ2 (MLX90614_OP_RAM | 0x08) /* object 2 temperature */ - -/* EEPROM offsets with 16-bit data, MSB first */ -#define MLX90614_EMISSIVITY (MLX90614_OP_EEPROM | 0x04) /* emissivity correction coefficient */ -#define MLX90614_CONFIG (MLX90614_OP_EEPROM | 0x05) /* configuration register */ +#define MLX90615_OP_EEPROM 0x10 +#define MLX90615_OP_RAM 0x20 +#define MLX90615_OP_SLEEP 0xc6 /* Control bits in configuration register */ #define MLX90614_CONFIG_IIR_SHIFT 0 /* IIR coefficient */ @@ -52,44 +49,61 @@ #define MLX90614_CONFIG_DUAL_MASK (1 << MLX90614_CONFIG_DUAL_SHIFT) #define MLX90614_CONFIG_FIR_SHIFT 8 /* FIR coefficient */ #define MLX90614_CONFIG_FIR_MASK (0x7 << MLX90614_CONFIG_FIR_SHIFT) -#define MLX90614_CONFIG_GAIN_SHIFT 11 /* gain */ -#define MLX90614_CONFIG_GAIN_MASK (0x7 << MLX90614_CONFIG_GAIN_SHIFT) + +#define MLX90615_CONFIG_IIR_SHIFT 12 /* IIR coefficient */ +#define MLX90615_CONFIG_IIR_MASK (0x7 << MLX90615_CONFIG_IIR_SHIFT) /* Timings (in ms) */ #define MLX90614_TIMING_EEPROM 20 /* time for EEPROM write/erase to complete */ #define MLX90614_TIMING_WAKEUP 34 /* time to hold SDA low for wake-up */ #define MLX90614_TIMING_STARTUP 250 /* time before first data after wake-up */ +#define MLX90615_TIMING_WAKEUP 22 /* time to hold SCL low for wake-up */ + #define MLX90614_AUTOSLEEP_DELAY 5000 /* default autosleep delay */ /* Magic constants */ #define MLX90614_CONST_OFFSET_DEC -13657 /* decimal part of the Kelvin offset */ #define MLX90614_CONST_OFFSET_REM 500000 /* remainder of offset (273.15*50) */ #define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */ -#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */ -#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */ #define MLX90614_CONST_FIR 0x7 /* Fixed value for FIR part of low pass filter */ +/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + +struct mlx_chip_info { + /* EEPROM offsets with 16-bit data, MSB first */ + /* emissivity correction coefficient */ + u8 op_eeprom_emissivity; + u8 op_eeprom_config1; + /* RAM offsets with 16-bit data, MSB first */ + /* ambient temperature */ + u8 op_ram_ta; + /* object 1 temperature */ + u8 op_ram_tobj1; + /* object 2 temperature */ + u8 op_ram_tobj2; + u8 op_sleep; + /* support for two input channels (MLX90614 only) */ + u8 dual_channel; + u8 wakeup_delay_ms; + u16 emissivity_max; + u16 fir_config_mask; + u16 iir_config_mask; + int iir_valid_offset; + u16 iir_values[8]; + int iir_freqs[8][2]; +}; + struct mlx90614_data { struct i2c_client *client; struct mutex lock; /* for EEPROM access only */ struct gpio_desc *wakeup_gpio; /* NULL to disable sleep/wake-up */ + const struct mlx_chip_info *chip_info; /* Chip hardware details */ unsigned long ready_timestamp; /* in jiffies */ }; -/* Bandwidth values for IIR filtering */ -static const int mlx90614_iir_values[] = {77, 31, 20, 15, 723, 153, 110, 86}; -static const int mlx90614_freqs[][2] = { - {0, 150000}, - {0, 200000}, - {0, 310000}, - {0, 770000}, - {0, 860000}, - {1, 100000}, - {1, 530000}, - {7, 230000} -}; - /* * Erase an address and write word. * The mutex must be locked before calling. @@ -129,21 +143,26 @@ static s32 mlx90614_write_word(const struct i2c_client *client, u8 command, } /* - * Find the IIR value inside mlx90614_iir_values array and return its position + * Find the IIR value inside iir_values array and return its position * which is equivalent to the bit value in sensor register */ static inline s32 mlx90614_iir_search(const struct i2c_client *client, int value) { + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct mlx90614_data *data = iio_priv(indio_dev); + const struct mlx_chip_info *chip_info = data->chip_info; int i; s32 ret; - for (i = 0; i < ARRAY_SIZE(mlx90614_iir_values); ++i) { - if (value == mlx90614_iir_values[i]) + for (i = chip_info->iir_valid_offset; + i < ARRAY_SIZE(chip_info->iir_values); + i++) { + if (value == chip_info->iir_values[i]) break; } - if (i == ARRAY_SIZE(mlx90614_iir_values)) + if (i == ARRAY_SIZE(chip_info->iir_values)) return -EINVAL; /* @@ -151,17 +170,21 @@ static inline s32 mlx90614_iir_search(const struct i2c_client *client, * we must read them before we actually write * changes */ - ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG); + ret = i2c_smbus_read_word_data(client, chip_info->op_eeprom_config1); if (ret < 0) return ret; - ret &= ~MLX90614_CONFIG_FIR_MASK; - ret |= MLX90614_CONST_FIR << MLX90614_CONFIG_FIR_SHIFT; - ret &= ~MLX90614_CONFIG_IIR_MASK; - ret |= i << MLX90614_CONFIG_IIR_SHIFT; + /* Modify FIR on parts which have configurable FIR filter */ + if (chip_info->fir_config_mask) { + ret &= ~chip_info->fir_config_mask; + ret |= field_prep(chip_info->fir_config_mask, MLX90614_CONST_FIR); + } + + ret &= ~chip_info->iir_config_mask; + ret |= field_prep(chip_info->iir_config_mask, i); /* Write changed values */ - ret = mlx90614_write_word(client, MLX90614_CONFIG, ret); + ret = mlx90614_write_word(client, chip_info->op_eeprom_config1, ret); return ret; } @@ -221,22 +244,26 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { struct mlx90614_data *data = iio_priv(indio_dev); - u8 cmd; + const struct mlx_chip_info *chip_info = data->chip_info; + u8 cmd, idx; s32 ret; switch (mask) { case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */ switch (channel->channel2) { case IIO_MOD_TEMP_AMBIENT: - cmd = MLX90614_TA; + cmd = chip_info->op_ram_ta; break; case IIO_MOD_TEMP_OBJECT: + if (chip_info->dual_channel && channel->channel) + return -EINVAL; + switch (channel->channel) { case 0: - cmd = MLX90614_TOBJ1; + cmd = chip_info->op_ram_tobj1; break; case 1: - cmd = MLX90614_TOBJ2; + cmd = chip_info->op_ram_tobj2; break; default: return -EINVAL; @@ -268,45 +295,48 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: *val = MLX90614_CONST_SCALE; return IIO_VAL_INT; - case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */ + case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/emissivity_max / LSB */ ret = mlx90614_power_get(data, false); if (ret < 0) return ret; mutex_lock(&data->lock); ret = i2c_smbus_read_word_data(data->client, - MLX90614_EMISSIVITY); + chip_info->op_eeprom_emissivity); mutex_unlock(&data->lock); mlx90614_power_put(data); if (ret < 0) return ret; - if (ret == MLX90614_CONST_RAW_EMISSIVITY_MAX) { + if (ret == chip_info->emissivity_max) { *val = 1; *val2 = 0; } else { *val = 0; - *val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION; + *val2 = ret * NSEC_PER_SEC / chip_info->emissivity_max; } return IIO_VAL_INT_PLUS_NANO; - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR setting with - FIR = 1024 */ + /* IIR setting with FIR=1024 (MLX90614) or FIR=65536 (MLX90615) */ + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: ret = mlx90614_power_get(data, false); if (ret < 0) return ret; mutex_lock(&data->lock); - ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG); + ret = i2c_smbus_read_word_data(data->client, + chip_info->op_eeprom_config1); mutex_unlock(&data->lock); mlx90614_power_put(data); if (ret < 0) return ret; - *val = mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] / 100; - *val2 = (mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] % 100) * - 10000; + idx = field_get(chip_info->iir_config_mask, ret) - + chip_info->iir_valid_offset; + + *val = chip_info->iir_values[idx] / 100; + *val2 = (chip_info->iir_values[idx] % 100) * 10000; return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; @@ -318,22 +348,23 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev, int val2, long mask) { struct mlx90614_data *data = iio_priv(indio_dev); + const struct mlx_chip_info *chip_info = data->chip_info; s32 ret; switch (mask) { - case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */ + case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/emissivity_max / LSB */ if (val < 0 || val2 < 0 || val > 1 || (val == 1 && val2 != 0)) return -EINVAL; - val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX + - val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION; + val = val * chip_info->emissivity_max + + val2 * chip_info->emissivity_max / NSEC_PER_SEC; ret = mlx90614_power_get(data, false); if (ret < 0) return ret; mutex_lock(&data->lock); - ret = mlx90614_write_word(data->client, MLX90614_EMISSIVITY, - val); + ret = mlx90614_write_word(data->client, + chip_info->op_eeprom_emissivity, val); mutex_unlock(&data->lock); mlx90614_power_put(data); @@ -377,11 +408,15 @@ static int mlx90614_read_avail(struct iio_dev *indio_dev, const int **vals, int *type, int *length, long mask) { + struct mlx90614_data *data = iio_priv(indio_dev); + const struct mlx_chip_info *chip_info = data->chip_info; + switch (mask) { case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - *vals = (int *)mlx90614_freqs; + *vals = (int *)chip_info->iir_freqs; *type = IIO_VAL_INT_PLUS_MICRO; - *length = 2 * ARRAY_SIZE(mlx90614_freqs); + *length = 2 * (ARRAY_SIZE(chip_info->iir_freqs) - + chip_info->iir_valid_offset); return IIO_AVAIL_LIST; default: return -EINVAL; @@ -435,6 +470,7 @@ static const struct iio_info mlx90614_info = { #ifdef CONFIG_PM static int mlx90614_sleep(struct mlx90614_data *data) { + const struct mlx_chip_info *chip_info = data->chip_info; s32 ret; if (!data->wakeup_gpio) { @@ -447,7 +483,7 @@ static int mlx90614_sleep(struct mlx90614_data *data) mutex_lock(&data->lock); ret = i2c_smbus_xfer(data->client->adapter, data->client->addr, data->client->flags | I2C_CLIENT_PEC, - I2C_SMBUS_WRITE, MLX90614_OP_SLEEP, + I2C_SMBUS_WRITE, chip_info->op_sleep, I2C_SMBUS_BYTE, NULL); mutex_unlock(&data->lock); @@ -456,6 +492,8 @@ static int mlx90614_sleep(struct mlx90614_data *data) static int mlx90614_wakeup(struct mlx90614_data *data) { + const struct mlx_chip_info *chip_info = data->chip_info; + if (!data->wakeup_gpio) { dev_dbg(&data->client->dev, "Wake-up disabled"); return -ENOSYS; @@ -465,7 +503,7 @@ static int mlx90614_wakeup(struct mlx90614_data *data) i2c_lock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER); gpiod_direction_output(data->wakeup_gpio, 0); - msleep(MLX90614_TIMING_WAKEUP); + msleep(chip_info->wakeup_delay_ms); gpiod_direction_input(data->wakeup_gpio); i2c_unlock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER); @@ -478,7 +516,7 @@ static int mlx90614_wakeup(struct mlx90614_data *data) * If the read fails, the controller will probably be reset so that * further reads will work. */ - i2c_smbus_read_word_data(data->client, MLX90614_CONFIG); + i2c_smbus_read_word_data(data->client, chip_info->op_eeprom_config1); return 0; } @@ -527,9 +565,15 @@ static inline struct gpio_desc *mlx90614_probe_wakeup(struct i2c_client *client) /* Return 0 for single sensor, 1 for dual sensor, <0 on error. */ static int mlx90614_probe_num_ir_sensors(struct i2c_client *client) { + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct mlx90614_data *data = iio_priv(indio_dev); + const struct mlx_chip_info *chip_info = data->chip_info; s32 ret; - ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG); + if (chip_info->dual_channel) + return 0; + + ret = i2c_smbus_read_word_data(client, chip_info->op_eeprom_config1); if (ret < 0) return ret; @@ -556,6 +600,7 @@ static int mlx90614_probe(struct i2c_client *client) data->client = client; mutex_init(&data->lock); data->wakeup_gpio = mlx90614_probe_wakeup(client); + data->chip_info = device_get_match_data(&client->dev); mlx90614_wakeup(data); @@ -605,14 +650,68 @@ static void mlx90614_remove(struct i2c_client *client) } } +static const struct mlx_chip_info mlx90614_chip_info = { + .op_eeprom_emissivity = MLX90614_OP_EEPROM | 0x04, + .op_eeprom_config1 = MLX90614_OP_EEPROM | 0x05, + .op_ram_ta = MLX90614_OP_RAM | 0x06, + .op_ram_tobj1 = MLX90614_OP_RAM | 0x07, + .op_ram_tobj2 = MLX90614_OP_RAM | 0x08, + .op_sleep = MLX90614_OP_SLEEP, + .dual_channel = true, + .wakeup_delay_ms = MLX90614_TIMING_WAKEUP, + .emissivity_max = 65535, + .fir_config_mask = MLX90614_CONFIG_FIR_MASK, + .iir_config_mask = MLX90614_CONFIG_IIR_MASK, + .iir_valid_offset = 0, + .iir_values = { 77, 31, 20, 15, 723, 153, 110, 86 }, + .iir_freqs = { + { 0, 150000 }, /* 13% ~= 0.15 Hz */ + { 0, 200000 }, /* 17% ~= 0.20 Hz */ + { 0, 310000 }, /* 25% ~= 0.31 Hz */ + { 0, 770000 }, /* 50% ~= 0.77 Hz */ + { 0, 860000 }, /* 57% ~= 0.86 Hz */ + { 1, 100000 }, /* 67% ~= 1.10 Hz */ + { 1, 530000 }, /* 80% ~= 1.53 Hz */ + { 7, 230000 } /* 100% ~= 7.23 Hz */ + }, +}; + +static const struct mlx_chip_info mlx90615_chip_info = { + .op_eeprom_emissivity = MLX90615_OP_EEPROM | 0x03, + .op_eeprom_config1 = MLX90615_OP_EEPROM | 0x02, + .op_ram_ta = MLX90615_OP_RAM | 0x06, + .op_ram_tobj1 = MLX90615_OP_RAM | 0x07, + .op_ram_tobj2 = MLX90615_OP_RAM | 0x08, + .op_sleep = MLX90615_OP_SLEEP, + .dual_channel = false, + .wakeup_delay_ms = MLX90615_TIMING_WAKEUP, + .emissivity_max = 16383, + .fir_config_mask = 0, /* MLX90615 FIR is fixed */ + .iir_config_mask = MLX90615_CONFIG_IIR_MASK, + /* IIR value 0 is FORBIDDEN COMBINATION on MLX90615 */ + .iir_valid_offset = 1, + .iir_values = { 500, 50, 30, 20, 15, 13, 10 }, + .iir_freqs = { + { 0, 100000 }, /* 14% ~= 0.10 Hz */ + { 0, 130000 }, /* 17% ~= 0.13 Hz */ + { 0, 150000 }, /* 20% ~= 0.15 Hz */ + { 0, 200000 }, /* 25% ~= 0.20 Hz */ + { 0, 300000 }, /* 33% ~= 0.30 Hz */ + { 0, 500000 }, /* 50% ~= 0.50 Hz */ + { 5, 000000 }, /* 100% ~= 5.00 Hz */ + }, +}; + static const struct i2c_device_id mlx90614_id[] = { - { "mlx90614", 0 }, + { "mlx90614", .driver_data = (kernel_ulong_t)&mlx90614_chip_info }, + { "mlx90615", .driver_data = (kernel_ulong_t)&mlx90615_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, mlx90614_id); static const struct of_device_id mlx90614_of_match[] = { - { .compatible = "melexis,mlx90614" }, + { .compatible = "melexis,mlx90614", .data = &mlx90614_chip_info }, + { .compatible = "melexis,mlx90615", .data = &mlx90615_chip_info }, { } }; MODULE_DEVICE_TABLE(of, mlx90614_of_match); @@ -675,7 +774,7 @@ static struct i2c_driver mlx90614_driver = { .of_match_table = mlx90614_of_match, .pm = pm_ptr(&mlx90614_pm_ops), }, - .probe_new = mlx90614_probe, + .probe = mlx90614_probe, .remove = mlx90614_remove, .id_table = mlx90614_id, }; diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index 753b7a4ccfdd..8a57be108620 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -1337,7 +1337,7 @@ static struct i2c_driver mlx90632_driver = { .of_match_table = mlx90632_of_match, .pm = pm_ptr(&mlx90632_pm_ops), }, - .probe_new = mlx90632_probe, + .probe = mlx90632_probe, .id_table = mlx90632_id, }; module_i2c_driver(mlx90632_driver); diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index cdf08477e63f..3a3904fe138c 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -15,6 +15,7 @@ #include <linux/i2c.h> #include <linux/delay.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/pm.h> #include <linux/bitops.h> @@ -272,6 +273,12 @@ static int tmp006_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume); +static const struct of_device_id tmp006_of_match[] = { + { .compatible = "ti,tmp006" }, + { } +}; +MODULE_DEVICE_TABLE(of, tmp006_of_match); + static const struct i2c_device_id tmp006_id[] = { { "tmp006", 0 }, { } @@ -281,9 +288,10 @@ MODULE_DEVICE_TABLE(i2c, tmp006_id); static struct i2c_driver tmp006_driver = { .driver = { .name = "tmp006", + .of_match_table = tmp006_of_match, .pm = pm_sleep_ptr(&tmp006_pm_ops), }, - .probe_new = tmp006_probe, + .probe = tmp006_probe, .id_table = tmp006_id, }; module_i2c_driver(tmp006_driver); diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c index 8d27aa3bdd6d..decef6896362 100644 --- a/drivers/iio/temperature/tmp007.c +++ b/drivers/iio/temperature/tmp007.c @@ -574,7 +574,7 @@ static struct i2c_driver tmp007_driver = { .of_match_table = tmp007_of_match, .pm = pm_sleep_ptr(&tmp007_pm_ops), }, - .probe_new = tmp007_probe, + .probe = tmp007_probe, .id_table = tmp007_id, }; module_i2c_driver(tmp007_driver); diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c index 638e3a5bd6b8..fc02f491688b 100644 --- a/drivers/iio/temperature/tmp117.c +++ b/drivers/iio/temperature/tmp117.c @@ -217,7 +217,7 @@ static struct i2c_driver tmp117_driver = { .name = "tmp117", .of_match_table = tmp117_of_match, }, - .probe_new = tmp117_probe, + .probe = tmp117_probe, .id_table = tmp117_id, }; module_i2c_driver(tmp117_driver); diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c index 30b268ba82cc..53ef56fbfe1d 100644 --- a/drivers/iio/temperature/tsys01.c +++ b/drivers/iio/temperature/tsys01.c @@ -218,7 +218,7 @@ static const struct of_device_id tsys01_of_match[] = { MODULE_DEVICE_TABLE(of, tsys01_of_match); static struct i2c_driver tsys01_driver = { - .probe_new = tsys01_i2c_probe, + .probe = tsys01_i2c_probe, .id_table = tsys01_id, .driver = { .name = "tsys01", diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c index cdefe046ab17..6191db92ef9a 100644 --- a/drivers/iio/temperature/tsys02d.c +++ b/drivers/iio/temperature/tsys02d.c @@ -174,7 +174,7 @@ static const struct i2c_device_id tsys02d_id[] = { MODULE_DEVICE_TABLE(i2c, tsys02d_id); static struct i2c_driver tsys02d_driver = { - .probe_new = tsys02d_probe, + .probe = tsys02d_probe, .id_table = tsys02d_id, .driver = { .name = "tsys02d", |