summaryrefslogtreecommitdiff
path: root/drivers/iio
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-12-16 14:49:24 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2022-12-16 14:49:24 +0300
commitba54ff1fb662215de683777f815b9e96276d55cf (patch)
treed9ad29a17d91fafd76c0b16b41dd30445e50215c /drivers/iio
parentdd6f9b17cd7af68b6a5090deedf1f5e84f66f4e6 (diff)
parentf361c96c75184d0272572087c7d9874e0f64b870 (diff)
downloadlinux-ba54ff1fb662215de683777f815b9e96276d55cf.tar.xz
Merge tag 'char-misc-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH: "Here is the large set of char/misc and other driver subsystem changes for 6.2-rc1. Nothing earth-shattering in here at all, just a lot of new driver development and minor fixes. Highlights include: - fastrpc driver updates - iio new drivers and updates - habanalabs driver updates for new hardware and features - slimbus driver updates - speakup module parameters added to aid in boot time configuration - i2c probe_new conversions for lots of different drivers - other small driver fixes and additions One semi-interesting change in here is the increase of the number of misc dynamic minors available to 1048448 to handle new huge-cpu systems. All of these have been in linux-next for a while with no reported problems" * tag 'char-misc-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (521 commits) extcon: usbc-tusb320: Convert to i2c's .probe_new() extcon: rt8973: Convert to i2c's .probe_new() extcon: fsa9480: Convert to i2c's .probe_new() extcon: max77843: Replace irqchip mask_invert with unmask_base chardev: fix error handling in cdev_device_add() mcb: mcb-parse: fix error handing in chameleon_parse_gdd() drivers: mcb: fix resource leak in mcb_probe() coresight: etm4x: fix repeated words in comments coresight: cti: Fix null pointer error on CTI init before ETM coresight: trbe: remove cpuhp instance node before remove cpuhp state counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update misc: fastrpc: Add dma_mask to fastrpc_channel_ctx misc: fastrpc: Add mmap request assigning for static PD pool misc: fastrpc: Safekeep mmaps on interrupted invoke misc: fastrpc: Add support for audiopd misc: fastrpc: Rework fastrpc_req_munmap misc: fastrpc: Use fastrpc_map_put in fastrpc_map_create on fail misc: fastrpc: Add fastrpc_remote_heap_alloc misc: fastrpc: Add reserved mem support misc: fastrpc: Rename audio protection domain to root ...
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/TODO3
-rw-r--r--drivers/iio/accel/Kconfig21
-rw-r--r--drivers/iio/accel/Makefile3
-rw-r--r--drivers/iio/accel/adis16201.c2
-rw-r--r--drivers/iio/accel/adis16209.c2
-rw-r--r--drivers/iio/accel/adxl355.h20
-rw-r--r--drivers/iio/accel/adxl355_core.c93
-rw-r--r--drivers/iio/accel/adxl355_i2c.c22
-rw-r--r--drivers/iio/accel/adxl355_spi.c19
-rw-r--r--drivers/iio/accel/adxl367.c57
-rw-r--r--drivers/iio/accel/adxl367_i2c.c5
-rw-r--r--drivers/iio/accel/adxl372.c29
-rw-r--r--drivers/iio/accel/adxl372_i2c.c6
-rw-r--r--drivers/iio/accel/bma180.c6
-rw-r--r--drivers/iio/accel/bma400_core.c10
-rw-r--r--drivers/iio/accel/bma400_i2c.c6
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c31
-rw-r--r--drivers/iio/accel/bmc150-accel-i2c.c6
-rw-r--r--drivers/iio/accel/da280.c6
-rw-r--r--drivers/iio/accel/da311.c5
-rw-r--r--drivers/iio/accel/dmard06.c5
-rw-r--r--drivers/iio/accel/dmard09.c5
-rw-r--r--drivers/iio/accel/dmard10.c5
-rw-r--r--drivers/iio/accel/fxls8962af-core.c40
-rw-r--r--drivers/iio/accel/fxls8962af-i2c.c2
-rw-r--r--drivers/iio/accel/fxls8962af-spi.c2
-rw-r--r--drivers/iio/accel/kionix-kx022a-i2c.c51
-rw-r--r--drivers/iio/accel/kionix-kx022a-spi.c58
-rw-r--r--drivers/iio/accel/kionix-kx022a.c1142
-rw-r--r--drivers/iio/accel/kionix-kx022a.h82
-rw-r--r--drivers/iio/accel/kxcjk-1013.c31
-rw-r--r--drivers/iio/accel/kxsd9-i2c.c5
-rw-r--r--drivers/iio/accel/mc3230.c5
-rw-r--r--drivers/iio/accel/mma7455_i2c.c6
-rw-r--r--drivers/iio/accel/mma7660.c5
-rw-r--r--drivers/iio/accel/mma8452.c6
-rw-r--r--drivers/iio/accel/mma9551.c6
-rw-r--r--drivers/iio/accel/mma9553.c6
-rw-r--r--drivers/iio/accel/msa311.c21
-rw-r--r--drivers/iio/accel/mxc4005.c5
-rw-r--r--drivers/iio/accel/mxc6255.c5
-rw-r--r--drivers/iio/accel/sca3300.c12
-rw-r--r--drivers/iio/accel/stk8312.c5
-rw-r--r--drivers/iio/accel/stk8ba50.c5
-rw-r--r--drivers/iio/adc/Kconfig40
-rw-r--r--drivers/iio/adc/Makefile3
-rw-r--r--drivers/iio/adc/ad4130.c2100
-rw-r--r--drivers/iio/adc/ad7091r5.c6
-rw-r--r--drivers/iio/adc/ad7124.c10
-rw-r--r--drivers/iio/adc/ad7192.c27
-rw-r--r--drivers/iio/adc/ad7291.c6
-rw-r--r--drivers/iio/adc/ad7476.c11
-rw-r--r--drivers/iio/adc/ad7606.c22
-rw-r--r--drivers/iio/adc/ad7606.h2
-rw-r--r--drivers/iio/adc/ad7606_par.c3
-rw-r--r--drivers/iio/adc/ad799x.c26
-rw-r--r--drivers/iio/adc/ad9467.c11
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c8
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c33
-rw-r--r--drivers/iio/adc/axp288_adc.c9
-rw-r--r--drivers/iio/adc/cc10001_adc.c89
-rw-r--r--drivers/iio/adc/imx7d_adc.c14
-rw-r--r--drivers/iio/adc/ina2xx-adc.c6
-rw-r--r--drivers/iio/adc/lpc32xx_adc.c11
-rw-r--r--drivers/iio/adc/ltc2471.c6
-rw-r--r--drivers/iio/adc/ltc2485.c6
-rw-r--r--drivers/iio/adc/ltc2497-core.c7
-rw-r--r--drivers/iio/adc/ltc2497.c6
-rw-r--r--drivers/iio/adc/ltc2497.h2
-rw-r--r--drivers/iio/adc/max11410.c1050
-rw-r--r--drivers/iio/adc/max1241.c28
-rw-r--r--drivers/iio/adc/max1363.c18
-rw-r--r--drivers/iio/adc/max9611.c5
-rw-r--r--drivers/iio/adc/mcp3422.c6
-rw-r--r--drivers/iio/adc/mcp3911.c104
-rw-r--r--drivers/iio/adc/meson_saradc.c11
-rw-r--r--drivers/iio/adc/mt6370-adc.c305
-rw-r--r--drivers/iio/adc/rockchip_saradc.c15
-rw-r--r--drivers/iio/adc/sc27xx_adc.c14
-rw-r--r--drivers/iio/adc/stm32-adc-core.c30
-rw-r--r--drivers/iio/adc/stm32-adc-core.h31
-rw-r--r--drivers/iio/adc/stm32-adc.c307
-rw-r--r--drivers/iio/adc/ti-adc081c.c6
-rw-r--r--drivers/iio/adc/ti-adc128s052.c14
-rw-r--r--drivers/iio/adc/ti-ads1015.c6
-rw-r--r--drivers/iio/adc/ti-ads131e08.c11
-rw-r--r--drivers/iio/adc/vf610_adc.c104
-rw-r--r--drivers/iio/addac/Kconfig14
-rw-r--r--drivers/iio/addac/Makefile1
-rw-r--r--drivers/iio/addac/ad74115.c1943
-rw-r--r--drivers/iio/addac/ad74413r.c32
-rw-r--r--drivers/iio/amplifiers/hmc425a.c17
-rw-r--r--drivers/iio/buffer/industrialio-buffer-dmaengine.c4
-rw-r--r--drivers/iio/buffer/industrialio-triggered-buffer.c4
-rw-r--r--drivers/iio/buffer/kfifo_buf.c2
-rw-r--r--drivers/iio/cdc/ad7150.c24
-rw-r--r--drivers/iio/cdc/ad7746.c6
-rw-r--r--drivers/iio/chemical/ams-iaq-core.c5
-rw-r--r--drivers/iio/chemical/atlas-ezo-sensor.c6
-rw-r--r--drivers/iio/chemical/atlas-sensor.c6
-rw-r--r--drivers/iio/chemical/bme680_i2c.c6
-rw-r--r--drivers/iio/chemical/ccs811.c6
-rw-r--r--drivers/iio/chemical/scd4x.c4
-rw-r--r--drivers/iio/chemical/sgp30.c6
-rw-r--r--drivers/iio/chemical/sgp40.c6
-rw-r--r--drivers/iio/chemical/vz89x.c6
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c6
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c8
-rw-r--r--drivers/iio/common/scmi_sensors/scmi_iio.c9
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c39
-rw-r--r--drivers/iio/dac/ad5064.c6
-rw-r--r--drivers/iio/dac/ad5380.c6
-rw-r--r--drivers/iio/dac/ad5446.c6
-rw-r--r--drivers/iio/dac/ad5593r.c6
-rw-r--r--drivers/iio/dac/ad5696-i2c.c6
-rw-r--r--drivers/iio/dac/ds4424.c6
-rw-r--r--drivers/iio/dac/ltc2688.c23
-rw-r--r--drivers/iio/dac/m62332.c5
-rw-r--r--drivers/iio/dac/max517.c6
-rw-r--r--drivers/iio/dac/max5821.c6
-rw-r--r--drivers/iio/dac/mcp4725.c6
-rw-r--r--drivers/iio/dac/ti-dac5571.c6
-rw-r--r--drivers/iio/filter/admv8818.c4
-rw-r--r--drivers/iio/frequency/Kconfig10
-rw-r--r--drivers/iio/frequency/Makefile1
-rw-r--r--drivers/iio/frequency/ad9523.c22
-rw-r--r--drivers/iio/frequency/adf4377.c994
-rw-r--r--drivers/iio/gyro/adis16136.c2
-rw-r--r--drivers/iio/gyro/adis16260.c2
-rw-r--r--drivers/iio/gyro/bmg160_core.c24
-rw-r--r--drivers/iio/gyro/bmg160_i2c.c6
-rw-r--r--drivers/iio/gyro/fxas21002c_core.c21
-rw-r--r--drivers/iio/gyro/fxas21002c_i2c.c3
-rw-r--r--drivers/iio/gyro/fxas21002c_spi.c3
-rw-r--r--drivers/iio/gyro/itg3200_core.c15
-rw-r--r--drivers/iio/gyro/mpu3050-i2c.c6
-rw-r--r--drivers/iio/gyro/st_gyro_i2c.c5
-rw-r--r--drivers/iio/health/afe4404.c5
-rw-r--r--drivers/iio/health/max30100.c20
-rw-r--r--drivers/iio/health/max30102.c25
-rw-r--r--drivers/iio/humidity/am2315.c5
-rw-r--r--drivers/iio/humidity/hdc100x.c5
-rw-r--r--drivers/iio/humidity/hdc2010.c5
-rw-r--r--drivers/iio/humidity/hts221.h2
-rw-r--r--drivers/iio/humidity/hts221_core.c27
-rw-r--r--drivers/iio/humidity/hts221_i2c.c5
-rw-r--r--drivers/iio/humidity/htu21.c6
-rw-r--r--drivers/iio/humidity/si7005.c5
-rw-r--r--drivers/iio/humidity/si7020.c5
-rw-r--r--drivers/iio/imu/adis.c28
-rw-r--r--drivers/iio/imu/adis16400.c2
-rw-r--r--drivers/iio/imu/bmi160/bmi160_i2c.c6
-rw-r--r--drivers/iio/imu/fxos8700_i2c.c6
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600.h2
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_core.c26
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c6
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c6
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c17
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c10
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c3
-rw-r--r--drivers/iio/imu/kmx61.c6
-rw-r--r--drivers/iio/imu/st_lsm6dsx/Kconfig3
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h24
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c16
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c465
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c26
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c4
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c20
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c65
-rw-r--r--drivers/iio/industrialio-buffer.c40
-rw-r--r--drivers/iio/industrialio-core.c58
-rw-r--r--drivers/iio/industrialio-event.c8
-rw-r--r--drivers/iio/industrialio-trigger.c12
-rw-r--r--drivers/iio/light/adjd_s311.c5
-rw-r--r--drivers/iio/light/adux1020.c5
-rw-r--r--drivers/iio/light/al3010.c5
-rw-r--r--drivers/iio/light/al3320a.c5
-rw-r--r--drivers/iio/light/apds9300.c5
-rw-r--r--drivers/iio/light/apds9960.c25
-rw-r--r--drivers/iio/light/bh1750.c6
-rw-r--r--drivers/iio/light/bh1780.c5
-rw-r--r--drivers/iio/light/cm3232.c6
-rw-r--r--drivers/iio/light/cm3323.c5
-rw-r--r--drivers/iio/light/cm36651.c6
-rw-r--r--drivers/iio/light/gp2ap002.c5
-rw-r--r--drivers/iio/light/gp2ap020a00f.c6
-rw-r--r--drivers/iio/light/isl29018.c6
-rw-r--r--drivers/iio/light/isl29028.c6
-rw-r--r--drivers/iio/light/isl29125.c5
-rw-r--r--drivers/iio/light/jsa1212.c5
-rw-r--r--drivers/iio/light/ltr501.c33
-rw-r--r--drivers/iio/light/lv0104cs.c5
-rw-r--r--drivers/iio/light/max44000.c5
-rw-r--r--drivers/iio/light/noa1305.c31
-rw-r--r--drivers/iio/light/opt3001.c5
-rw-r--r--drivers/iio/light/pa12203001.c5
-rw-r--r--drivers/iio/light/rpr0521.c5
-rw-r--r--drivers/iio/light/si1133.c6
-rw-r--r--drivers/iio/light/si1145.c6
-rw-r--r--drivers/iio/light/st_uvis25_i2c.c5
-rw-r--r--drivers/iio/light/stk3310.c5
-rw-r--r--drivers/iio/light/tcs3414.c5
-rw-r--r--drivers/iio/light/tcs3472.c5
-rw-r--r--drivers/iio/light/tsl2563.c5
-rw-r--r--drivers/iio/light/tsl2583.c5
-rw-r--r--drivers/iio/light/tsl2772.c6
-rw-r--r--drivers/iio/light/tsl4531.c5
-rw-r--r--drivers/iio/light/us5182d.c5
-rw-r--r--drivers/iio/light/vcnl4000.c191
-rw-r--r--drivers/iio/light/vcnl4035.c5
-rw-r--r--drivers/iio/light/veml6030.c5
-rw-r--r--drivers/iio/light/veml6070.c5
-rw-r--r--drivers/iio/light/vl6180.c5
-rw-r--r--drivers/iio/light/zopt2201.c5
-rw-r--r--drivers/iio/magnetometer/ak8974.c5
-rw-r--r--drivers/iio/magnetometer/ak8975.c6
-rw-r--r--drivers/iio/magnetometer/bmc150_magn_i2c.c6
-rw-r--r--drivers/iio/magnetometer/hmc5843_i2c.c6
-rw-r--r--drivers/iio/magnetometer/mag3110.c6
-rw-r--r--drivers/iio/magnetometer/mmc35240.c5
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c5
-rw-r--r--drivers/iio/magnetometer/yamaha-yas530.c6
-rw-r--r--drivers/iio/multiplexer/iio-mux.c8
-rw-r--r--drivers/iio/potentiometer/ad5272.c6
-rw-r--r--drivers/iio/potentiometer/ds1803.c5
-rw-r--r--drivers/iio/potentiometer/max5432.c5
-rw-r--r--drivers/iio/potentiometer/tpl0102.c6
-rw-r--r--drivers/iio/potentiostat/lmp91000.c5
-rw-r--r--drivers/iio/pressure/abp060mg.c6
-rw-r--r--drivers/iio/pressure/bmp280-i2c.c6
-rw-r--r--drivers/iio/pressure/dlhl60d.c6
-rw-r--r--drivers/iio/pressure/dps310.c6
-rw-r--r--drivers/iio/pressure/hp03.c6
-rw-r--r--drivers/iio/pressure/hp206c.c6
-rw-r--r--drivers/iio/pressure/icp10100.c5
-rw-r--r--drivers/iio/pressure/mpl115.c62
-rw-r--r--drivers/iio/pressure/mpl115.h5
-rw-r--r--drivers/iio/pressure/mpl115_i2c.c7
-rw-r--r--drivers/iio/pressure/mpl115_spi.c1
-rw-r--r--drivers/iio/pressure/mpl3115.c6
-rw-r--r--drivers/iio/pressure/ms5611_i2c.c6
-rw-r--r--drivers/iio/pressure/ms5637.c6
-rw-r--r--drivers/iio/pressure/st_pressure_i2c.c5
-rw-r--r--drivers/iio/pressure/t5403.c6
-rw-r--r--drivers/iio/pressure/zpa2326_i2c.c6
-rw-r--r--drivers/iio/proximity/isl29501.c5
-rw-r--r--drivers/iio/proximity/mb1232.c6
-rw-r--r--drivers/iio/proximity/pulsedlight-lidar-lite-v2.c5
-rw-r--r--drivers/iio/proximity/rfd77402.c5
-rw-r--r--drivers/iio/proximity/srf08.c6
-rw-r--r--drivers/iio/proximity/sx9360.c1
-rw-r--r--drivers/iio/proximity/sx9500.c5
-rw-r--r--drivers/iio/proximity/sx_common.c23
-rw-r--r--drivers/iio/proximity/sx_common.h2
-rw-r--r--drivers/iio/temperature/Kconfig10
-rw-r--r--drivers/iio/temperature/Makefile1
-rw-r--r--drivers/iio/temperature/ltc2983.c193
-rw-r--r--drivers/iio/temperature/max30208.c252
-rw-r--r--drivers/iio/temperature/mlx90614.c6
-rw-r--r--drivers/iio/temperature/mlx90632.c480
-rw-r--r--drivers/iio/temperature/tmp006.c5
-rw-r--r--drivers/iio/temperature/tmp007.c6
-rw-r--r--drivers/iio/temperature/tsys01.c5
-rw-r--r--drivers/iio/temperature/tsys02d.c6
-rw-r--r--drivers/iio/trigger/iio-trig-sysfs.c14
265 files changed, 10903 insertions, 1574 deletions
diff --git a/drivers/iio/TODO b/drivers/iio/TODO
index 7d7326b7085a..2ace27d1ac62 100644
--- a/drivers/iio/TODO
+++ b/drivers/iio/TODO
@@ -7,9 +7,6 @@ tree
- ABI Documentation
- Audit driviers/iio/staging/Documentation
-- Replace iio_dev->mlock by either a local lock or use
-iio_claim_direct.(Requires analysis of the purpose of the lock.)
-
- Converting drivers from device tree centric to more generic
property handlers.
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index ffac66db7ac9..03ac410c162e 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -409,6 +409,27 @@ config IIO_ST_ACCEL_SPI_3AXIS
To compile this driver as a module, choose M here. The module
will be called st_accel_spi.
+config IIO_KX022A
+ tristate
+
+config IIO_KX022A_SPI
+ tristate "Kionix KX022A tri-axis digital accelerometer SPI interface"
+ depends on SPI
+ select IIO_KX022A
+ select REGMAP_SPI
+ help
+ Enable support for the Kionix KX022A digital tri-axis
+ accelerometer connected to I2C interface.
+
+config IIO_KX022A_I2C
+ tristate "Kionix KX022A tri-axis digital accelerometer I2C interface"
+ depends on I2C
+ select IIO_KX022A
+ select REGMAP_I2C
+ help
+ Enable support for the Kionix KX022A digital tri-axis
+ accelerometer connected to I2C interface.
+
config KXSD9
tristate "Kionix KXSD9 Accelerometer Driver"
select IIO_BUFFER
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 5e45b5fa5ab5..311ead9c3ef1 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -40,6 +40,9 @@ obj-$(CONFIG_FXLS8962AF) += fxls8962af-core.o
obj-$(CONFIG_FXLS8962AF_I2C) += fxls8962af-i2c.o
obj-$(CONFIG_FXLS8962AF_SPI) += fxls8962af-spi.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
+obj-$(CONFIG_IIO_KX022A) += kionix-kx022a.o
+obj-$(CONFIG_IIO_KX022A_I2C) += kionix-kx022a-i2c.o
+obj-$(CONFIG_IIO_KX022A_SPI) += kionix-kx022a-spi.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
obj-$(CONFIG_KXSD9_SPI) += kxsd9-spi.o
diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c
index dfb8e2e5bdf5..d054721859b3 100644
--- a/drivers/iio/accel/adis16201.c
+++ b/drivers/iio/accel/adis16201.c
@@ -281,7 +281,7 @@ static int adis16201_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = adis_initial_startup(st);
+ ret = __adis_initial_startup(st);
if (ret)
return ret;
diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c
index 5a9c6e2296f1..0035e4f4db63 100644
--- a/drivers/iio/accel/adis16209.c
+++ b/drivers/iio/accel/adis16209.c
@@ -291,7 +291,7 @@ static int adis16209_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = adis_initial_startup(st);
+ ret = __adis_initial_startup(st);
if (ret)
return ret;
diff --git a/drivers/iio/accel/adxl355.h b/drivers/iio/accel/adxl355.h
index 6dd49b13e4fd..061e66dc7057 100644
--- a/drivers/iio/accel/adxl355.h
+++ b/drivers/iio/accel/adxl355.h
@@ -10,12 +10,30 @@
#include <linux/regmap.h>
+enum adxl355_device_type {
+ ADXL355,
+ ADXL359,
+};
+
+struct adxl355_fractional_type {
+ int integer;
+ int decimal;
+};
+
struct device;
+struct adxl355_chip_info {
+ const char *name;
+ u8 part_id;
+ struct adxl355_fractional_type accel_scale;
+ struct adxl355_fractional_type temp_offset;
+};
+
extern const struct regmap_access_table adxl355_readable_regs_tbl;
extern const struct regmap_access_table adxl355_writeable_regs_tbl;
+extern const struct adxl355_chip_info adxl35x_chip_info[];
int adxl355_core_probe(struct device *dev, struct regmap *regmap,
- const char *name);
+ const struct adxl355_chip_info *chip_info);
#endif /* _ADXL355_H_ */
diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c
index 4bc648eac8b2..0c9225d18fb2 100644
--- a/drivers/iio/accel/adxl355_core.c
+++ b/drivers/iio/accel/adxl355_core.c
@@ -60,6 +60,7 @@
#define ADXL355_DEVID_AD_VAL 0xAD
#define ADXL355_DEVID_MST_VAL 0x1D
#define ADXL355_PARTID_VAL 0xED
+#define ADXL359_PARTID_VAL 0xE9
#define ADXL355_RESET_CODE 0x52
static const struct regmap_range adxl355_read_reg_range[] = {
@@ -83,6 +84,60 @@ const struct regmap_access_table adxl355_writeable_regs_tbl = {
};
EXPORT_SYMBOL_NS_GPL(adxl355_writeable_regs_tbl, IIO_ADXL355);
+const struct adxl355_chip_info adxl35x_chip_info[] = {
+ [ADXL355] = {
+ .name = "adxl355",
+ .part_id = ADXL355_PARTID_VAL,
+ /*
+ * At +/- 2g with 20-bit resolution, scale is given in datasheet
+ * as 3.9ug/LSB = 0.0000039 * 9.80665 = 0.00003824593 m/s^2.
+ */
+ .accel_scale = {
+ .integer = 0,
+ .decimal = 38245,
+ },
+ /*
+ * The datasheet defines an intercept of 1885 LSB at 25 degC
+ * and a slope of -9.05 LSB/C. The following formula can be used
+ * to find the temperature:
+ * Temp = ((RAW - 1885)/(-9.05)) + 25 but this doesn't follow
+ * the format of the IIO which is Temp = (RAW + OFFSET) * SCALE.
+ * Hence using some rearranging we get the scale as -110.497238
+ * and offset as -2111.25.
+ */
+ .temp_offset = {
+ .integer = -2111,
+ .decimal = 250000,
+ },
+ },
+ [ADXL359] = {
+ .name = "adxl359",
+ .part_id = ADXL359_PARTID_VAL,
+ /*
+ * At +/- 10g with 20-bit resolution, scale is given in datasheet
+ * as 19.5ug/LSB = 0.0000195 * 9.80665 = 0.0.00019122967 m/s^2.
+ */
+ .accel_scale = {
+ .integer = 0,
+ .decimal = 191229,
+ },
+ /*
+ * The datasheet defines an intercept of 1852 LSB at 25 degC
+ * and a slope of -9.05 LSB/C. The following formula can be used
+ * to find the temperature:
+ * Temp = ((RAW - 1852)/(-9.05)) + 25 but this doesn't follow
+ * the format of the IIO which is Temp = (RAW + OFFSET) * SCALE.
+ * Hence using some rearranging we get the scale as -110.497238
+ * and offset as -2079.25.
+ */
+ .temp_offset = {
+ .integer = -2079,
+ .decimal = 250000,
+ },
+ },
+};
+EXPORT_SYMBOL_NS_GPL(adxl35x_chip_info, IIO_ADXL355);
+
enum adxl355_op_mode {
ADXL355_MEASUREMENT,
ADXL355_STANDBY,
@@ -162,6 +217,7 @@ static const struct adxl355_chan_info adxl355_chans[] = {
};
struct adxl355_data {
+ const struct adxl355_chip_info *chip_info;
struct regmap *regmap;
struct device *dev;
struct mutex lock; /* lock to protect op_mode */
@@ -262,10 +318,8 @@ static int adxl355_setup(struct adxl355_data *data)
if (ret)
return ret;
- if (regval != ADXL355_PARTID_VAL) {
- dev_err(data->dev, "Invalid DEV ID 0x%02x\n", regval);
- return -ENODEV;
- }
+ if (regval != ADXL355_PARTID_VAL)
+ dev_warn(data->dev, "Invalid DEV ID 0x%02x\n", regval);
/*
* Perform a software reset to make sure the device is in a consistent
@@ -458,33 +512,25 @@ static int adxl355_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
- /*
- * The datasheet defines an intercept of 1885 LSB at 25 degC
- * and a slope of -9.05 LSB/C. The following formula can be used
- * to find the temperature:
- * Temp = ((RAW - 1885)/(-9.05)) + 25 but this doesn't follow
- * the format of the IIO which is Temp = (RAW + OFFSET) * SCALE.
- * Hence using some rearranging we get the scale as -110.497238
- * and offset as -2111.25.
- */
case IIO_TEMP:
+ /*
+ * Temperature scale is -110.497238.
+ * See the detailed explanation in adxl35x_chip_info
+ * definition above.
+ */
*val = -110;
*val2 = 497238;
return IIO_VAL_INT_PLUS_MICRO;
- /*
- * At +/- 2g with 20-bit resolution, scale is given in datasheet
- * as 3.9ug/LSB = 0.0000039 * 9.80665 = 0.00003824593 m/s^2.
- */
case IIO_ACCEL:
- *val = 0;
- *val2 = 38245;
+ *val = data->chip_info->accel_scale.integer;
+ *val2 = data->chip_info->accel_scale.decimal;
return IIO_VAL_INT_PLUS_NANO;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
- *val = -2111;
- *val2 = 250000;
+ *val = data->chip_info->temp_offset.integer;
+ *val2 = data->chip_info->temp_offset.decimal;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_CALIBBIAS:
*val = sign_extend32(data->calibbias[chan->address], 15);
@@ -707,7 +753,7 @@ static int adxl355_probe_trigger(struct iio_dev *indio_dev, int irq)
}
int adxl355_core_probe(struct device *dev, struct regmap *regmap,
- const char *name)
+ const struct adxl355_chip_info *chip_info)
{
struct adxl355_data *data;
struct iio_dev *indio_dev;
@@ -722,9 +768,10 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap,
data->regmap = regmap;
data->dev = dev;
data->op_mode = ADXL355_STANDBY;
+ data->chip_info = chip_info;
mutex_init(&data->lock);
- indio_dev->name = name;
+ indio_dev->name = chip_info->name;
indio_dev->info = &adxl355_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = adxl355_channels;
diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c
index f67d57921c81..6cde5ccac06b 100644
--- a/drivers/iio/accel/adxl355_i2c.c
+++ b/drivers/iio/accel/adxl355_i2c.c
@@ -23,6 +23,20 @@ static const struct regmap_config adxl355_i2c_regmap_config = {
static int adxl355_i2c_probe(struct i2c_client *client)
{
struct regmap *regmap;
+ const struct adxl355_chip_info *chip_data;
+ const struct i2c_device_id *adxl355;
+
+ chip_data = device_get_match_data(&client->dev);
+ if (!chip_data) {
+ adxl355 = to_i2c_driver(client->dev.driver)->id_table;
+ if (!adxl355)
+ return -EINVAL;
+
+ chip_data = (void *)i2c_match_id(adxl355, client)->driver_data;
+
+ if (!chip_data)
+ return -EINVAL;
+ }
regmap = devm_regmap_init_i2c(client, &adxl355_i2c_regmap_config);
if (IS_ERR(regmap)) {
@@ -32,17 +46,19 @@ static int adxl355_i2c_probe(struct i2c_client *client)
return PTR_ERR(regmap);
}
- return adxl355_core_probe(&client->dev, regmap, client->name);
+ return adxl355_core_probe(&client->dev, regmap, chip_data);
}
static const struct i2c_device_id adxl355_i2c_id[] = {
- { "adxl355", 0 },
+ { "adxl355", (kernel_ulong_t)&adxl35x_chip_info[ADXL355] },
+ { "adxl359", (kernel_ulong_t)&adxl35x_chip_info[ADXL359] },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl355_i2c_id);
static const struct of_device_id adxl355_of_match[] = {
- { .compatible = "adi,adxl355" },
+ { .compatible = "adi,adxl355", .data = &adxl35x_chip_info[ADXL355] },
+ { .compatible = "adi,adxl359", .data = &adxl35x_chip_info[ADXL359] },
{ }
};
MODULE_DEVICE_TABLE(of, adxl355_of_match);
diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c
index 5fe986ae03f6..fc99534d91ff 100644
--- a/drivers/iio/accel/adxl355_spi.c
+++ b/drivers/iio/accel/adxl355_spi.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
+#include <linux/property.h>
#include "adxl355.h"
@@ -24,9 +25,17 @@ static const struct regmap_config adxl355_spi_regmap_config = {
static int adxl355_spi_probe(struct spi_device *spi)
{
- const struct spi_device_id *id = spi_get_device_id(spi);
+ const struct adxl355_chip_info *chip_data;
struct regmap *regmap;
+ chip_data = device_get_match_data(&spi->dev);
+ if (!chip_data) {
+ chip_data = (void *)spi_get_device_id(spi)->driver_data;
+
+ if (!chip_data)
+ return -EINVAL;
+ }
+
regmap = devm_regmap_init_spi(spi, &adxl355_spi_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "Error initializing spi regmap: %ld\n",
@@ -35,17 +44,19 @@ static int adxl355_spi_probe(struct spi_device *spi)
return PTR_ERR(regmap);
}
- return adxl355_core_probe(&spi->dev, regmap, id->name);
+ return adxl355_core_probe(&spi->dev, regmap, chip_data);
}
static const struct spi_device_id adxl355_spi_id[] = {
- { "adxl355", 0 },
+ { "adxl355", (kernel_ulong_t)&adxl35x_chip_info[ADXL355] },
+ { "adxl359", (kernel_ulong_t)&adxl35x_chip_info[ADXL359] },
{ }
};
MODULE_DEVICE_TABLE(spi, adxl355_spi_id);
static const struct of_device_id adxl355_of_match[] = {
- { .compatible = "adi,adxl355" },
+ { .compatible = "adi,adxl355", .data = &adxl35x_chip_info[ADXL355] },
+ { .compatible = "adi,adxl359", .data = &adxl35x_chip_info[ADXL359] },
{ }
};
MODULE_DEVICE_TABLE(of, adxl355_of_match);
diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c
index 7c7d78040793..90b7ae6d42b7 100644
--- a/drivers/iio/accel/adxl367.c
+++ b/drivers/iio/accel/adxl367.c
@@ -160,8 +160,6 @@ struct adxl367_state {
struct device *dev;
struct regmap *regmap;
- struct regulator_bulk_data regulators[2];
-
/*
* Synchronize access to members of driver state, and ensure atomicity
* of consecutive regmap operations.
@@ -1185,32 +1183,19 @@ static ssize_t adxl367_get_fifo_watermark(struct device *dev,
return sysfs_emit(buf, "%d\n", fifo_watermark);
}
-static ssize_t hwfifo_watermark_min_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sysfs_emit(buf, "%s\n", "1");
-}
-
-static ssize_t hwfifo_watermark_max_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sysfs_emit(buf, "%s\n", __stringify(ADXL367_FIFO_MAX_WATERMARK));
-}
-
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1");
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max,
+ __stringify(ADXL367_FIFO_MAX_WATERMARK));
static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
adxl367_get_fifo_watermark, NULL, 0);
static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
adxl367_get_fifo_enabled, NULL, 0);
-static const struct attribute *adxl367_fifo_attributes[] = {
- &iio_dev_attr_hwfifo_watermark_min.dev_attr.attr,
- &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
- &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
- &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+static const struct iio_dev_attr *adxl367_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_watermark_min,
+ &iio_dev_attr_hwfifo_watermark_max,
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
NULL,
};
@@ -1487,16 +1472,10 @@ static int adxl367_setup(struct adxl367_state *st)
return adxl367_set_measure_en(st, true);
}
-static void adxl367_disable_regulators(void *data)
-{
- struct adxl367_state *st = data;
-
- regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators);
-}
-
int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
void *context, struct regmap *regmap, int irq)
{
+ static const char * const regulator_names[] = { "vdd", "vddio" };
struct iio_dev *indio_dev;
struct adxl367_state *st;
int ret;
@@ -1520,25 +1499,13 @@ int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
indio_dev->info = &adxl367_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- st->regulators[0].supply = "vdd";
- st->regulators[1].supply = "vddio";
-
- ret = devm_regulator_bulk_get(st->dev, ARRAY_SIZE(st->regulators),
- st->regulators);
+ ret = devm_regulator_bulk_get_enable(st->dev,
+ ARRAY_SIZE(regulator_names),
+ regulator_names);
if (ret)
return dev_err_probe(st->dev, ret,
"Failed to get regulators\n");
- ret = regulator_bulk_enable(ARRAY_SIZE(st->regulators), st->regulators);
- if (ret)
- return dev_err_probe(st->dev, ret,
- "Failed to enable regulators\n");
-
- ret = devm_add_action_or_reset(st->dev, adxl367_disable_regulators, st);
- if (ret)
- return dev_err_probe(st->dev, ret,
- "Failed to add regulators disable action\n");
-
ret = regmap_write(st->regmap, ADXL367_REG_RESET, ADXL367_RESET_CODE);
if (ret)
return ret;
diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c
index 3606efa25835..070aad724abd 100644
--- a/drivers/iio/accel/adxl367_i2c.c
+++ b/drivers/iio/accel/adxl367_i2c.c
@@ -41,8 +41,7 @@ static const struct adxl367_ops adxl367_i2c_ops = {
.read_fifo = adxl367_i2c_read_fifo,
};
-static int adxl367_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adxl367_i2c_probe(struct i2c_client *client)
{
struct adxl367_i2c_state *st;
struct regmap *regmap;
@@ -78,7 +77,7 @@ static struct i2c_driver adxl367_i2c_driver = {
.name = "adxl367_i2c",
.of_match_table = adxl367_of_match,
},
- .probe = adxl367_i2c_probe,
+ .probe_new = adxl367_i2c_probe,
.id_table = adxl367_i2c_id,
};
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
index bc53af809d5d..c4193286eb05 100644
--- a/drivers/iio/accel/adxl372.c
+++ b/drivers/iio/accel/adxl372.c
@@ -998,32 +998,19 @@ static ssize_t adxl372_get_fifo_watermark(struct device *dev,
return sprintf(buf, "%d\n", st->watermark);
}
-static ssize_t hwfifo_watermark_min_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sysfs_emit(buf, "%s\n", "1");
-}
-
-static ssize_t hwfifo_watermark_max_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sysfs_emit(buf, "%s\n", __stringify(ADXL372_FIFO_SIZE));
-}
-
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1");
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max,
+ __stringify(ADXL372_FIFO_SIZE));
static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
adxl372_get_fifo_watermark, NULL, 0);
static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
adxl372_get_fifo_enabled, NULL, 0);
-static const struct attribute *adxl372_fifo_attributes[] = {
- &iio_dev_attr_hwfifo_watermark_min.dev_attr.attr,
- &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
- &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
- &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+static const struct iio_dev_attr *adxl372_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_watermark_min,
+ &iio_dev_attr_hwfifo_watermark_max,
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
NULL,
};
diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c
index 4efb70a5fe40..e5f310ea65ff 100644
--- a/drivers/iio/accel/adxl372_i2c.c
+++ b/drivers/iio/accel/adxl372_i2c.c
@@ -18,9 +18,9 @@ static const struct regmap_config adxl372_regmap_config = {
.readable_noinc_reg = adxl372_readable_noinc_reg,
};
-static int adxl372_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adxl372_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct regmap *regmap;
unsigned int regval;
int ret;
@@ -58,7 +58,7 @@ static struct i2c_driver adxl372_i2c_driver = {
.name = "adxl372_i2c",
.of_match_table = adxl372_of_match,
},
- .probe = adxl372_i2c_probe,
+ .probe_new = adxl372_i2c_probe,
.id_table = adxl372_i2c_id,
};
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index d03fc3400f94..eb697eeb4301 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -921,9 +921,9 @@ static const struct iio_trigger_ops bma180_trigger_ops = {
.reenable = bma180_trig_reen,
};
-static int bma180_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bma180_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct bma180_data *data;
struct iio_dev *indio_dev;
@@ -1134,7 +1134,7 @@ static struct i2c_driver bma180_driver = {
.pm = pm_sleep_ptr(&bma180_pm_ops),
.of_match_table = bma180_of_match,
},
- .probe = bma180_probe,
+ .probe_new = 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 6e4d10a7cd32..b612d0146d4d 100644
--- a/drivers/iio/accel/bma400_core.c
+++ b/drivers/iio/accel/bma400_core.c
@@ -876,14 +876,10 @@ static int bma400_init(struct bma400_data *data)
ret = devm_regulator_bulk_get(data->dev,
ARRAY_SIZE(data->regulators),
data->regulators);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(data->dev,
- "Failed to get regulators: %d\n",
- ret);
+ if (ret)
+ return dev_err_probe(data->dev, ret, "Failed to get regulators: %d\n",
+ ret);
- return ret;
- }
ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
data->regulators);
if (ret) {
diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c
index 1ba2a982ea73..688b06dae669 100644
--- a/drivers/iio/accel/bma400_i2c.c
+++ b/drivers/iio/accel/bma400_i2c.c
@@ -13,9 +13,9 @@
#include "bma400.h"
-static int bma400_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bma400_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct regmap *regmap;
regmap = devm_regmap_init_i2c(client, &bma400_regmap_config);
@@ -44,7 +44,7 @@ static struct i2c_driver bma400_i2c_driver = {
.name = "bma400",
.of_match_table = bma400_of_i2c_match,
},
- .probe = bma400_i2c_probe,
+ .probe_new = bma400_i2c_probe,
.id_table = bma400_i2c_ids,
};
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 92f8b139acce..110591804b4c 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -925,32 +925,19 @@ static const struct iio_chan_spec_ext_info bmc150_accel_ext_info[] = {
{ }
};
-static ssize_t hwfifo_watermark_min_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sysfs_emit(buf, "%s\n", "1");
-}
-
-static ssize_t hwfifo_watermark_max_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sysfs_emit(buf, "%s\n", __stringify(BMC150_ACCEL_FIFO_LENGTH));
-}
-
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1");
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max,
+ __stringify(BMC150_ACCEL_FIFO_LENGTH));
static IIO_DEVICE_ATTR(hwfifo_enabled, S_IRUGO,
bmc150_accel_get_fifo_state, NULL, 0);
static IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO,
bmc150_accel_get_fifo_watermark, NULL, 0);
-static const struct attribute *bmc150_accel_fifo_attributes[] = {
- &iio_dev_attr_hwfifo_watermark_min.dev_attr.attr,
- &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
- &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
- &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+static const struct iio_dev_attr *bmc150_accel_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_watermark_min,
+ &iio_dev_attr_hwfifo_watermark_max,
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
NULL,
};
@@ -1678,7 +1665,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
enum bmc150_type type, const char *name,
bool block_supported)
{
- const struct attribute **fifo_attrs;
+ const struct iio_dev_attr **fifo_attrs;
struct bmc150_accel_data *data;
struct iio_dev *indio_dev;
int ret;
diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c
index be8cc598b88e..509cab2bd694 100644
--- a/drivers/iio/accel/bmc150-accel-i2c.c
+++ b/drivers/iio/accel/bmc150-accel-i2c.c
@@ -171,9 +171,9 @@ static void bmc150_acpi_dual_accel_probe(struct i2c_client *client) {}
static void bmc150_acpi_dual_accel_remove(struct i2c_client *client) {}
#endif
-static int bmc150_accel_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bmc150_accel_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct regmap *regmap;
const char *name = NULL;
enum bmc150_type type = BOSCH_UNKNOWN;
@@ -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 = bmc150_accel_probe,
+ .probe_new = 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 04e9c5678964..38a7d811610e 100644
--- a/drivers/iio/accel/da280.c
+++ b/drivers/iio/accel/da280.c
@@ -105,9 +105,9 @@ static void da280_disable(void *client)
da280_enable(client, false);
}
-static int da280_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int da280_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
struct iio_dev *indio_dev;
struct da280_data *data;
@@ -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 = da280_probe,
+ .probe_new = da280_probe,
.id_table = da280_i2c_id,
};
diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c
index ec4e29d260f7..080335fa2ad6 100644
--- a/drivers/iio/accel/da311.c
+++ b/drivers/iio/accel/da311.c
@@ -217,8 +217,7 @@ static void da311_disable(void *client)
da311_enable(client, false);
}
-static int da311_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int da311_probe(struct i2c_client *client)
{
int ret;
struct iio_dev *indio_dev;
@@ -279,7 +278,7 @@ static struct i2c_driver da311_driver = {
.name = "da311",
.pm = pm_sleep_ptr(&da311_pm_ops),
},
- .probe = da311_probe,
+ .probe_new = da311_probe,
.id_table = da311_i2c_id,
};
diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c
index 4b69c8530f5e..7390509aaac0 100644
--- a/drivers/iio/accel/dmard06.c
+++ b/drivers/iio/accel/dmard06.c
@@ -125,8 +125,7 @@ static const struct iio_info dmard06_info = {
.read_raw = dmard06_read_raw,
};
-static int dmard06_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int dmard06_probe(struct i2c_client *client)
{
int ret;
struct iio_dev *indio_dev;
@@ -218,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 = dmard06_probe,
+ .probe_new = 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 cb0246ca72f3..4b7a537f617d 100644
--- a/drivers/iio/accel/dmard09.c
+++ b/drivers/iio/accel/dmard09.c
@@ -88,8 +88,7 @@ static const struct iio_info dmard09_info = {
.read_raw = dmard09_read_raw,
};
-static int dmard09_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int dmard09_probe(struct i2c_client *client)
{
int ret;
struct iio_dev *indio_dev;
@@ -136,7 +135,7 @@ static struct i2c_driver dmard09_driver = {
.driver = {
.name = DMARD09_DRV_NAME
},
- .probe = dmard09_probe,
+ .probe_new = dmard09_probe,
.id_table = dmard09_id,
};
diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c
index 8ac62ec0a04a..07e68aed8a13 100644
--- a/drivers/iio/accel/dmard10.c
+++ b/drivers/iio/accel/dmard10.c
@@ -175,8 +175,7 @@ static void dmard10_shutdown_cleanup(void *client)
dmard10_shutdown(client);
}
-static int dmard10_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int dmard10_probe(struct i2c_client *client)
{
int ret;
struct iio_dev *indio_dev;
@@ -242,7 +241,7 @@ static struct i2c_driver dmard10_driver = {
.name = "dmard10",
.pm = pm_sleep_ptr(&dmard10_pm_ops),
},
- .probe = dmard10_probe,
+ .probe_new = dmard10_probe,
.id_table = dmard10_i2c_id,
};
diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c
index 8874d6d61725..0d672b1469e8 100644
--- a/drivers/iio/accel/fxls8962af-core.c
+++ b/drivers/iio/accel/fxls8962af-core.c
@@ -159,7 +159,6 @@ struct fxls8962af_chip_info {
struct fxls8962af_data {
struct regmap *regmap;
const struct fxls8962af_chip_info *chip_info;
- struct regulator *vdd_reg;
struct {
__le16 channels[3];
s64 ts __aligned(8);
@@ -1051,13 +1050,6 @@ static irqreturn_t fxls8962af_interrupt(int irq, void *p)
return IRQ_NONE;
}
-static void fxls8962af_regulator_disable(void *data_ptr)
-{
- struct fxls8962af_data *data = data_ptr;
-
- regulator_disable(data->vdd_reg);
-}
-
static void fxls8962af_pm_disable(void *dev_ptr)
{
struct device *dev = dev_ptr;
@@ -1171,20 +1163,10 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
if (ret)
return ret;
- data->vdd_reg = devm_regulator_get(dev, "vdd");
- if (IS_ERR(data->vdd_reg))
- return dev_err_probe(dev, PTR_ERR(data->vdd_reg),
- "Failed to get vdd regulator\n");
-
- ret = regulator_enable(data->vdd_reg);
- if (ret) {
- dev_err(dev, "Failed to enable vdd regulator: %d\n", ret);
- return ret;
- }
-
- ret = devm_add_action_or_reset(dev, fxls8962af_regulator_disable, data);
+ ret = devm_regulator_get_enable(dev, "vdd");
if (ret)
- return ret;
+ return dev_err_probe(dev, ret,
+ "Failed to get vdd regulator\n");
ret = regmap_read(data->regmap, FXLS8962AF_WHO_AM_I, &reg);
if (ret)
@@ -1241,7 +1223,7 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
}
EXPORT_SYMBOL_NS_GPL(fxls8962af_core_probe, IIO_FXLS8962AF);
-static int __maybe_unused fxls8962af_runtime_suspend(struct device *dev)
+static int fxls8962af_runtime_suspend(struct device *dev)
{
struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev));
int ret;
@@ -1255,14 +1237,14 @@ static int __maybe_unused fxls8962af_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused fxls8962af_runtime_resume(struct device *dev)
+static int fxls8962af_runtime_resume(struct device *dev)
{
struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev));
return fxls8962af_active(data);
}
-static int __maybe_unused fxls8962af_suspend(struct device *dev)
+static int fxls8962af_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct fxls8962af_data *data = iio_priv(indio_dev);
@@ -1283,7 +1265,7 @@ static int __maybe_unused fxls8962af_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused fxls8962af_resume(struct device *dev)
+static int fxls8962af_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct fxls8962af_data *data = iio_priv(indio_dev);
@@ -1300,12 +1282,10 @@ static int __maybe_unused fxls8962af_resume(struct device *dev)
return 0;
}
-const struct dev_pm_ops fxls8962af_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(fxls8962af_suspend, fxls8962af_resume)
- SET_RUNTIME_PM_OPS(fxls8962af_runtime_suspend,
- fxls8962af_runtime_resume, NULL)
+EXPORT_NS_GPL_DEV_PM_OPS(fxls8962af_pm_ops, IIO_FXLS8962AF) = {
+ SYSTEM_SLEEP_PM_OPS(fxls8962af_suspend, fxls8962af_resume)
+ RUNTIME_PM_OPS(fxls8962af_runtime_suspend, fxls8962af_runtime_resume, NULL)
};
-EXPORT_SYMBOL_NS_GPL(fxls8962af_pm_ops, IIO_FXLS8962AF);
MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>");
MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer driver");
diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c
index 8fbadfea1620..22640eaebac7 100644
--- a/drivers/iio/accel/fxls8962af-i2c.c
+++ b/drivers/iio/accel/fxls8962af-i2c.c
@@ -45,7 +45,7 @@ static struct i2c_driver fxls8962af_driver = {
.driver = {
.name = "fxls8962af_i2c",
.of_match_table = fxls8962af_of_match,
- .pm = &fxls8962af_pm_ops,
+ .pm = pm_ptr(&fxls8962af_pm_ops),
},
.probe_new = fxls8962af_probe,
.id_table = fxls8962af_id,
diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c
index 885b3ab7fcb5..a0d192211839 100644
--- a/drivers/iio/accel/fxls8962af-spi.c
+++ b/drivers/iio/accel/fxls8962af-spi.c
@@ -44,7 +44,7 @@ MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table);
static struct spi_driver fxls8962af_driver = {
.driver = {
.name = "fxls8962af_spi",
- .pm = &fxls8962af_pm_ops,
+ .pm = pm_ptr(&fxls8962af_pm_ops),
.of_match_table = fxls8962af_spi_of_match,
},
.probe = fxls8962af_probe,
diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c
new file mode 100644
index 000000000000..e6fd02d931b6
--- /dev/null
+++ b/drivers/iio/accel/kionix-kx022a-i2c.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 ROHM Semiconductors
+ *
+ * ROHM/KIONIX KX022A accelerometer driver
+ */
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "kionix-kx022a.h"
+
+static int kx022a_i2c_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct regmap *regmap;
+
+ if (!i2c->irq) {
+ dev_err(dev, "No IRQ configured\n");
+ return -EINVAL;
+ }
+
+ regmap = devm_regmap_init_i2c(i2c, &kx022a_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to initialize Regmap\n");
+
+ return kx022a_probe_internal(dev);
+}
+
+static const struct of_device_id kx022a_of_match[] = {
+ { .compatible = "kionix,kx022a", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, kx022a_of_match);
+
+static struct i2c_driver kx022a_i2c_driver = {
+ .driver = {
+ .name = "kx022a-i2c",
+ .of_match_table = kx022a_of_match,
+ },
+ .probe_new = kx022a_i2c_probe,
+};
+module_i2c_driver(kx022a_i2c_driver);
+
+MODULE_DESCRIPTION("ROHM/Kionix KX022A accelerometer driver");
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_KX022A);
diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c
new file mode 100644
index 000000000000..9cd047f7b346
--- /dev/null
+++ b/drivers/iio/accel/kionix-kx022a-spi.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 ROHM Semiconductors
+ *
+ * ROHM/KIONIX KX022A accelerometer driver
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "kionix-kx022a.h"
+
+static int kx022a_spi_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct regmap *regmap;
+
+ if (!spi->irq) {
+ dev_err(dev, "No IRQ configured\n");
+ return -EINVAL;
+ }
+
+ regmap = devm_regmap_init_spi(spi, &kx022a_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to initialize Regmap\n");
+
+ return kx022a_probe_internal(dev);
+}
+
+static const struct spi_device_id kx022a_id[] = {
+ { "kx022a" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, kx022a_id);
+
+static const struct of_device_id kx022a_of_match[] = {
+ { .compatible = "kionix,kx022a", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, kx022a_of_match);
+
+static struct spi_driver kx022a_spi_driver = {
+ .driver = {
+ .name = "kx022a-spi",
+ .of_match_table = kx022a_of_match,
+ },
+ .probe = kx022a_spi_probe,
+ .id_table = kx022a_id,
+};
+module_spi_driver(kx022a_spi_driver);
+
+MODULE_DESCRIPTION("ROHM/Kionix kx022A accelerometer driver");
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_KX022A);
diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c
new file mode 100644
index 000000000000..f866859855cd
--- /dev/null
+++ b/drivers/iio/accel/kionix-kx022a.c
@@ -0,0 +1,1142 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 ROHM Semiconductors
+ *
+ * ROHM/KIONIX KX022A accelerometer driver
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/string_helpers.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include "kionix-kx022a.h"
+
+/*
+ * The KX022A has FIFO which can store 43 samples of HiRes data from 2
+ * channels. This equals to 43 (samples) * 3 (channels) * 2 (bytes/sample) to
+ * 258 bytes of sample data. The quirk to know is that the amount of bytes in
+ * the FIFO is advertised via 8 bit register (max value 255). The thing to note
+ * is that full 258 bytes of data is indicated using the max value 255.
+ */
+#define KX022A_FIFO_LENGTH 43
+#define KX022A_FIFO_FULL_VALUE 255
+#define KX022A_SOFT_RESET_WAIT_TIME_US (5 * USEC_PER_MSEC)
+#define KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US (500 * USEC_PER_MSEC)
+
+/* 3 axis, 2 bytes of data for each of the axis */
+#define KX022A_FIFO_SAMPLES_SIZE_BYTES 6
+#define KX022A_FIFO_MAX_BYTES \
+ (KX022A_FIFO_LENGTH * KX022A_FIFO_SAMPLES_SIZE_BYTES)
+
+enum {
+ KX022A_STATE_SAMPLE,
+ KX022A_STATE_FIFO,
+};
+
+/* Regmap configs */
+static const struct regmap_range kx022a_volatile_ranges[] = {
+ {
+ .range_min = KX022A_REG_XHP_L,
+ .range_max = KX022A_REG_COTR,
+ }, {
+ .range_min = KX022A_REG_TSCP,
+ .range_max = KX022A_REG_INT_REL,
+ }, {
+ /* The reset bit will be cleared by sensor */
+ .range_min = KX022A_REG_CNTL2,
+ .range_max = KX022A_REG_CNTL2,
+ }, {
+ .range_min = KX022A_REG_BUF_STATUS_1,
+ .range_max = KX022A_REG_BUF_READ,
+ },
+};
+
+static const struct regmap_access_table kx022a_volatile_regs = {
+ .yes_ranges = &kx022a_volatile_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(kx022a_volatile_ranges),
+};
+
+static const struct regmap_range kx022a_precious_ranges[] = {
+ {
+ .range_min = KX022A_REG_INT_REL,
+ .range_max = KX022A_REG_INT_REL,
+ },
+};
+
+static const struct regmap_access_table kx022a_precious_regs = {
+ .yes_ranges = &kx022a_precious_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(kx022a_precious_ranges),
+};
+
+/*
+ * The HW does not set WHO_AM_I reg as read-only but we don't want to write it
+ * so we still include it in the read-only ranges.
+ */
+static const struct regmap_range kx022a_read_only_ranges[] = {
+ {
+ .range_min = KX022A_REG_XHP_L,
+ .range_max = KX022A_REG_INT_REL,
+ }, {
+ .range_min = KX022A_REG_BUF_STATUS_1,
+ .range_max = KX022A_REG_BUF_STATUS_2,
+ }, {
+ .range_min = KX022A_REG_BUF_READ,
+ .range_max = KX022A_REG_BUF_READ,
+ },
+};
+
+static const struct regmap_access_table kx022a_ro_regs = {
+ .no_ranges = &kx022a_read_only_ranges[0],
+ .n_no_ranges = ARRAY_SIZE(kx022a_read_only_ranges),
+};
+
+static const struct regmap_range kx022a_write_only_ranges[] = {
+ {
+ .range_min = KX022A_REG_BTS_WUF_TH,
+ .range_max = KX022A_REG_BTS_WUF_TH,
+ }, {
+ .range_min = KX022A_REG_MAN_WAKE,
+ .range_max = KX022A_REG_MAN_WAKE,
+ }, {
+ .range_min = KX022A_REG_SELF_TEST,
+ .range_max = KX022A_REG_SELF_TEST,
+ }, {
+ .range_min = KX022A_REG_BUF_CLEAR,
+ .range_max = KX022A_REG_BUF_CLEAR,
+ },
+};
+
+static const struct regmap_access_table kx022a_wo_regs = {
+ .no_ranges = &kx022a_write_only_ranges[0],
+ .n_no_ranges = ARRAY_SIZE(kx022a_write_only_ranges),
+};
+
+static const struct regmap_range kx022a_noinc_read_ranges[] = {
+ {
+ .range_min = KX022A_REG_BUF_READ,
+ .range_max = KX022A_REG_BUF_READ,
+ },
+};
+
+static const struct regmap_access_table kx022a_nir_regs = {
+ .yes_ranges = &kx022a_noinc_read_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(kx022a_noinc_read_ranges),
+};
+
+const struct regmap_config kx022a_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &kx022a_volatile_regs,
+ .rd_table = &kx022a_wo_regs,
+ .wr_table = &kx022a_ro_regs,
+ .rd_noinc_table = &kx022a_nir_regs,
+ .precious_table = &kx022a_precious_regs,
+ .max_register = KX022A_MAX_REGISTER,
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_NS_GPL(kx022a_regmap, IIO_KX022A);
+
+struct kx022a_data {
+ struct regmap *regmap;
+ struct iio_trigger *trig;
+ struct device *dev;
+ struct iio_mount_matrix orientation;
+ int64_t timestamp, old_timestamp;
+
+ int irq;
+ int inc_reg;
+ int ien_reg;
+
+ unsigned int g_range;
+ unsigned int state;
+ unsigned int odr_ns;
+
+ bool trigger_enabled;
+ /*
+ * Prevent toggling the sensor stby/active state (PC1 bit) in the
+ * middle of a configuration, or when the fifo is enabled. Also,
+ * protect the data stored/retrieved from this structure from
+ * concurrent accesses.
+ */
+ struct mutex mutex;
+ u8 watermark;
+
+ /* 3 x 16bit accel data + timestamp */
+ __le16 buffer[8] __aligned(IIO_DMA_MINALIGN);
+ struct {
+ __le16 channels[3];
+ s64 ts __aligned(8);
+ } scan;
+};
+
+static const struct iio_mount_matrix *
+kx022a_get_mount_matrix(const struct iio_dev *idev,
+ const struct iio_chan_spec *chan)
+{
+ struct kx022a_data *data = iio_priv(idev);
+
+ return &data->orientation;
+}
+
+enum {
+ AXIS_X,
+ AXIS_Y,
+ AXIS_Z,
+ AXIS_MAX
+};
+
+static const unsigned long kx022a_scan_masks[] = {
+ BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), 0
+};
+
+static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, kx022a_get_mount_matrix),
+ { }
+};
+
+#define KX022A_ACCEL_CHAN(axis, index) \
+{ \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .ext_info = kx022a_ext_info, \
+ .address = KX022A_REG_##axis##OUT_L, \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_LE, \
+ }, \
+}
+
+static const struct iio_chan_spec kx022a_channels[] = {
+ KX022A_ACCEL_CHAN(X, 0),
+ KX022A_ACCEL_CHAN(Y, 1),
+ KX022A_ACCEL_CHAN(Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+/*
+ * The sensor HW can support ODR up to 1600 Hz, which is beyond what most of the
+ * Linux CPUs can handle without dropping samples. Also, the low power mode is
+ * not available for higher sample rates. Thus, the driver only supports 200 Hz
+ * and slower ODRs. The slowest is 0.78 Hz.
+ */
+static const int kx022a_accel_samp_freq_table[][2] = {
+ { 0, 780000 },
+ { 1, 563000 },
+ { 3, 125000 },
+ { 6, 250000 },
+ { 12, 500000 },
+ { 25, 0 },
+ { 50, 0 },
+ { 100, 0 },
+ { 200, 0 },
+};
+
+static const unsigned int kx022a_odrs[] = {
+ 1282051282,
+ 639795266,
+ 320 * MEGA,
+ 160 * MEGA,
+ 80 * MEGA,
+ 40 * MEGA,
+ 20 * MEGA,
+ 10 * MEGA,
+ 5 * MEGA,
+};
+
+/*
+ * range is typically +-2G/4G/8G/16G, distributed over the amount of bits.
+ * The scale table can be calculated using
+ * (range / 2^bits) * g = (range / 2^bits) * 9.80665 m/s^2
+ * => KX022A uses 16 bit (HiRes mode - assume the low 8 bits are zeroed
+ * in low-power mode(?) )
+ * => +/-2G => 4 / 2^16 * 9,80665 * 10^6 (to scale to micro)
+ * => +/-2G - 598.550415
+ * +/-4G - 1197.10083
+ * +/-8G - 2394.20166
+ * +/-16G - 4788.40332
+ */
+static const int kx022a_scale_table[][2] = {
+ { 598, 550415 },
+ { 1197, 100830 },
+ { 2394, 201660 },
+ { 4788, 403320 },
+};
+
+static int kx022a_read_avail(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_SAMP_FREQ:
+ *vals = (const int *)kx022a_accel_samp_freq_table;
+ *length = ARRAY_SIZE(kx022a_accel_samp_freq_table) *
+ ARRAY_SIZE(kx022a_accel_samp_freq_table[0]);
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (const int *)kx022a_scale_table;
+ *length = ARRAY_SIZE(kx022a_scale_table) *
+ ARRAY_SIZE(kx022a_scale_table[0]);
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+#define KX022A_DEFAULT_PERIOD_NS (20 * NSEC_PER_MSEC)
+
+static void kx022a_reg2freq(unsigned int val, int *val1, int *val2)
+{
+ *val1 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][0];
+ *val2 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][1];
+}
+
+static void kx022a_reg2scale(unsigned int val, unsigned int *val1,
+ unsigned int *val2)
+{
+ val &= KX022A_MASK_GSEL;
+ val >>= KX022A_GSEL_SHIFT;
+
+ *val1 = kx022a_scale_table[val][0];
+ *val2 = kx022a_scale_table[val][1];
+}
+
+static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on)
+{
+ int ret;
+
+ if (on)
+ ret = regmap_set_bits(data->regmap, KX022A_REG_CNTL,
+ KX022A_MASK_PC1);
+ else
+ ret = regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
+ KX022A_MASK_PC1);
+ if (ret)
+ dev_err(data->dev, "Turn %s fail %d\n", str_on_off(on), ret);
+
+ return ret;
+
+}
+
+static int kx022a_turn_off_lock(struct kx022a_data *data)
+{
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = kx022a_turn_on_off_unlocked(data, false);
+ if (ret)
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int kx022a_turn_on_unlock(struct kx022a_data *data)
+{
+ int ret;
+
+ ret = kx022a_turn_on_off_unlocked(data, true);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int kx022a_write_raw(struct iio_dev *idev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct kx022a_data *data = iio_priv(idev);
+ int ret, n;
+
+ /*
+ * We should not allow changing scale or frequency when FIFO is running
+ * as it will mess the timestamp/scale for samples existing in the
+ * buffer. If this turns out to be an issue we can later change logic
+ * to internally flush the fifo before reconfiguring so the samples in
+ * fifo keep matching the freq/scale settings. (Such setup could cause
+ * issues if users trust the watermark to be reached within known
+ * time-limit).
+ */
+ ret = iio_device_claim_direct_mode(idev);
+ if (ret)
+ return ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ n = ARRAY_SIZE(kx022a_accel_samp_freq_table);
+
+ while (n--)
+ if (val == kx022a_accel_samp_freq_table[n][0] &&
+ val2 == kx022a_accel_samp_freq_table[n][1])
+ break;
+ if (n < 0) {
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+ ret = kx022a_turn_off_lock(data);
+ if (ret)
+ break;
+
+ ret = regmap_update_bits(data->regmap,
+ KX022A_REG_ODCNTL,
+ KX022A_MASK_ODR, n);
+ data->odr_ns = kx022a_odrs[n];
+ kx022a_turn_on_unlock(data);
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ n = ARRAY_SIZE(kx022a_scale_table);
+
+ while (n-- > 0)
+ if (val == kx022a_scale_table[n][0] &&
+ val2 == kx022a_scale_table[n][1])
+ break;
+ if (n < 0) {
+ ret = -EINVAL;
+ goto unlock_out;
+ }
+
+ ret = kx022a_turn_off_lock(data);
+ if (ret)
+ break;
+
+ ret = regmap_update_bits(data->regmap, KX022A_REG_CNTL,
+ KX022A_MASK_GSEL,
+ n << KX022A_GSEL_SHIFT);
+ kx022a_turn_on_unlock(data);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+unlock_out:
+ iio_device_release_direct_mode(idev);
+
+ return ret;
+}
+
+static int kx022a_fifo_set_wmi(struct kx022a_data *data)
+{
+ u8 threshold;
+
+ threshold = data->watermark;
+
+ return regmap_update_bits(data->regmap, KX022A_REG_BUF_CNTL1,
+ KX022A_MASK_WM_TH, threshold);
+}
+
+static int kx022a_get_axis(struct kx022a_data *data,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, chan->address, &data->buffer[0],
+ sizeof(__le16));
+ if (ret)
+ return ret;
+
+ *val = le16_to_cpu(data->buffer[0]);
+
+ return IIO_VAL_INT;
+}
+
+static int kx022a_read_raw(struct iio_dev *idev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct kx022a_data *data = iio_priv(idev);
+ unsigned int regval;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(idev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&data->mutex);
+ ret = kx022a_get_axis(data, chan, val);
+ mutex_unlock(&data->mutex);
+
+ iio_device_release_direct_mode(idev);
+
+ return ret;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = regmap_read(data->regmap, KX022A_REG_ODCNTL, &regval);
+ if (ret)
+ return ret;
+
+ if ((regval & KX022A_MASK_ODR) >
+ ARRAY_SIZE(kx022a_accel_samp_freq_table)) {
+ dev_err(data->dev, "Invalid ODR\n");
+ return -EINVAL;
+ }
+
+ kx022a_reg2freq(regval, val, val2);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = regmap_read(data->regmap, KX022A_REG_CNTL, &regval);
+ if (ret < 0)
+ return ret;
+
+ kx022a_reg2scale(regval, val, val2);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+
+ 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);
+
+ if (val > KX022A_FIFO_LENGTH)
+ val = KX022A_FIFO_LENGTH;
+
+ mutex_lock(&data->mutex);
+ data->watermark = val;
+ mutex_unlock(&data->mutex);
+
+ return 0;
+}
+
+static ssize_t hwfifo_enabled_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *idev = dev_to_iio_dev(dev);
+ struct kx022a_data *data = iio_priv(idev);
+ bool state;
+
+ mutex_lock(&data->mutex);
+ state = data->state;
+ mutex_unlock(&data->mutex);
+
+ return sysfs_emit(buf, "%d\n", state);
+}
+
+static ssize_t hwfifo_watermark_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *idev = dev_to_iio_dev(dev);
+ struct kx022a_data *data = iio_priv(idev);
+ int wm;
+
+ mutex_lock(&data->mutex);
+ wm = data->watermark;
+ mutex_unlock(&data->mutex);
+
+ return sysfs_emit(buf, "%d\n", wm);
+}
+
+static IIO_DEVICE_ATTR_RO(hwfifo_enabled, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0);
+
+static const struct iio_dev_attr *kx022a_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
+ NULL
+};
+
+static int kx022a_drop_fifo_contents(struct kx022a_data *data)
+{
+ /*
+ * We must clear the old time-stamp to avoid computing the timestamps
+ * based on samples acquired when buffer was last enabled.
+ *
+ * We don't need to protect the timestamp as long as we are only
+ * called from fifo-disable where we can guarantee the sensor is not
+ * triggering interrupts and where the mutex is locked to prevent the
+ * user-space access.
+ */
+ data->timestamp = 0;
+
+ return regmap_write(data->regmap, KX022A_REG_BUF_CLEAR, 0x0);
+}
+
+static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
+ bool irq)
+{
+ struct kx022a_data *data = iio_priv(idev);
+ struct device *dev = regmap_get_device(data->regmap);
+ __le16 buffer[KX022A_FIFO_LENGTH * 3];
+ uint64_t sample_period;
+ int count, fifo_bytes;
+ bool renable = false;
+ int64_t tstamp;
+ int ret, i;
+
+ ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes);
+ if (ret) {
+ dev_err(dev, "Error reading buffer status\n");
+ return ret;
+ }
+
+ /* Let's not overflow if we for some reason get bogus value from i2c */
+ if (fifo_bytes == KX022A_FIFO_FULL_VALUE)
+ fifo_bytes = KX022A_FIFO_MAX_BYTES;
+
+ if (fifo_bytes % KX022A_FIFO_SAMPLES_SIZE_BYTES)
+ dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n");
+
+ count = fifo_bytes / KX022A_FIFO_SAMPLES_SIZE_BYTES;
+ if (!count)
+ return 0;
+
+ /*
+ * If we are being called from IRQ handler we know the stored timestamp
+ * is fairly accurate for the last stored sample. Otherwise, if we are
+ * called as a result of a read operation from userspace and hence
+ * before the watermark interrupt was triggered, take a timestamp
+ * now. We can fall anywhere in between two samples so the error in this
+ * case is at most one sample period.
+ */
+ if (!irq) {
+ /*
+ * We need to have the IRQ disabled or we risk of messing-up
+ * the timestamps. If we are ran from IRQ, then the
+ * IRQF_ONESHOT has us covered - but if we are ran by the
+ * user-space read we need to disable the IRQ to be on a safe
+ * side. We do this usng synchronous disable so that if the
+ * IRQ thread is being ran on other CPU we wait for it to be
+ * finished.
+ */
+ disable_irq(data->irq);
+ renable = true;
+
+ data->old_timestamp = data->timestamp;
+ data->timestamp = iio_get_time_ns(idev);
+ }
+
+ /*
+ * Approximate timestamps for each of the sample based on the sampling
+ * frequency, timestamp for last sample and number of samples.
+ *
+ * We'd better not use the current bandwidth settings to compute the
+ * sample period. The real sample rate varies with the device and
+ * small variation adds when we store a large number of samples.
+ *
+ * To avoid this issue we compute the actual sample period ourselves
+ * based on the timestamp delta between the last two flush operations.
+ */
+ if (data->old_timestamp) {
+ sample_period = data->timestamp - data->old_timestamp;
+ do_div(sample_period, count);
+ } else {
+ sample_period = data->odr_ns;
+ }
+ tstamp = data->timestamp - (count - 1) * sample_period;
+
+ if (samples && count > samples) {
+ /*
+ * Here we leave some old samples to the buffer. We need to
+ * adjust the timestamp to match the first sample in the buffer
+ * or we will miscalculate the sample_period at next round.
+ */
+ data->timestamp -= (count - samples) * sample_period;
+ count = samples;
+ }
+
+ fifo_bytes = count * KX022A_FIFO_SAMPLES_SIZE_BYTES;
+ ret = regmap_noinc_read(data->regmap, KX022A_REG_BUF_READ,
+ &buffer[0], fifo_bytes);
+ if (ret)
+ goto renable_out;
+
+ for (i = 0; i < count; i++) {
+ __le16 *sam = &buffer[i * 3];
+ __le16 *chs;
+ int bit;
+
+ chs = &data->scan.channels[0];
+ for_each_set_bit(bit, idev->active_scan_mask, AXIS_MAX)
+ chs[bit] = sam[bit];
+
+ iio_push_to_buffers_with_timestamp(idev, &data->scan, tstamp);
+
+ tstamp += sample_period;
+ }
+
+ ret = count;
+
+renable_out:
+ if (renable)
+ enable_irq(data->irq);
+
+ return ret;
+}
+
+static int kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples)
+{
+ struct kx022a_data *data = iio_priv(idev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = __kx022a_fifo_flush(idev, samples, false);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static const struct iio_info kx022a_info = {
+ .read_raw = &kx022a_read_raw,
+ .write_raw = &kx022a_write_raw,
+ .read_avail = &kx022a_read_avail,
+
+ .validate_trigger = kx022a_validate_trigger,
+ .hwfifo_set_watermark = kx022a_set_watermark,
+ .hwfifo_flush_to_buffer = kx022a_fifo_flush,
+};
+
+static int kx022a_set_drdy_irq(struct kx022a_data *data, bool en)
+{
+ if (en)
+ return regmap_set_bits(data->regmap, KX022A_REG_CNTL,
+ KX022A_MASK_DRDY);
+
+ return regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
+ KX022A_MASK_DRDY);
+}
+
+static int kx022a_prepare_irq_pin(struct kx022a_data *data)
+{
+ /* Enable IRQ1 pin. Set polarity to active low */
+ int mask = KX022A_MASK_IEN | KX022A_MASK_IPOL |
+ KX022A_MASK_ITYP;
+ int val = KX022A_MASK_IEN | KX022A_IPOL_LOW |
+ KX022A_ITYP_LEVEL;
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, data->inc_reg, mask, val);
+ if (ret)
+ return ret;
+
+ /* We enable WMI to IRQ pin only at buffer_enable */
+ mask = KX022A_MASK_INS2_DRDY;
+
+ return regmap_set_bits(data->regmap, data->ien_reg, mask);
+}
+
+static int kx022a_fifo_disable(struct kx022a_data *data)
+{
+ int ret = 0;
+
+ ret = kx022a_turn_off_lock(data);
+ if (ret)
+ return ret;
+
+ ret = regmap_clear_bits(data->regmap, data->ien_reg, KX022A_MASK_WMI);
+ if (ret)
+ goto unlock_out;
+
+ ret = regmap_clear_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+ KX022A_MASK_BUF_EN);
+ if (ret)
+ goto unlock_out;
+
+ data->state &= ~KX022A_STATE_FIFO;
+
+ kx022a_drop_fifo_contents(data);
+
+ return kx022a_turn_on_unlock(data);
+
+unlock_out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int kx022a_buffer_predisable(struct iio_dev *idev)
+{
+ struct kx022a_data *data = iio_priv(idev);
+
+ if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED)
+ return 0;
+
+ return kx022a_fifo_disable(data);
+}
+
+static int kx022a_fifo_enable(struct kx022a_data *data)
+{
+ int ret;
+
+ ret = kx022a_turn_off_lock(data);
+ if (ret)
+ return ret;
+
+ /* Update watermark to HW */
+ ret = kx022a_fifo_set_wmi(data);
+ if (ret)
+ goto unlock_out;
+
+ /* Enable buffer */
+ ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+ KX022A_MASK_BUF_EN);
+ if (ret)
+ goto unlock_out;
+
+ data->state |= KX022A_STATE_FIFO;
+ ret = regmap_set_bits(data->regmap, data->ien_reg,
+ KX022A_MASK_WMI);
+ if (ret)
+ goto unlock_out;
+
+ return kx022a_turn_on_unlock(data);
+
+unlock_out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int kx022a_buffer_postenable(struct iio_dev *idev)
+{
+ struct kx022a_data *data = iio_priv(idev);
+
+ /*
+ * If we use data-ready trigger, then the IRQ masks should be handled by
+ * trigger enable and the hardware buffer is not used but we just update
+ * results to the IIO fifo when data-ready triggers.
+ */
+ if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED)
+ return 0;
+
+ return kx022a_fifo_enable(data);
+}
+
+static const struct iio_buffer_setup_ops kx022a_buffer_ops = {
+ .postenable = kx022a_buffer_postenable,
+ .predisable = kx022a_buffer_predisable,
+};
+
+static irqreturn_t kx022a_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *idev = pf->indio_dev;
+ struct kx022a_data *data = iio_priv(idev);
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, KX022A_REG_XOUT_L, data->buffer,
+ KX022A_FIFO_SAMPLES_SIZE_BYTES);
+ if (ret < 0)
+ goto err_read;
+
+ iio_push_to_buffers_with_timestamp(idev, data->buffer, pf->timestamp);
+err_read:
+ iio_trigger_notify_done(idev->trig);
+
+ return IRQ_HANDLED;
+}
+
+/* Get timestamps and wake the thread if we need to read data */
+static irqreturn_t kx022a_irq_handler(int irq, void *private)
+{
+ struct iio_dev *idev = private;
+ struct kx022a_data *data = iio_priv(idev);
+
+ data->old_timestamp = data->timestamp;
+ data->timestamp = iio_get_time_ns(idev);
+
+ if (data->state & KX022A_STATE_FIFO || data->trigger_enabled)
+ return IRQ_WAKE_THREAD;
+
+ return IRQ_NONE;
+}
+
+/*
+ * WMI and data-ready IRQs are acked when results are read. If we add
+ * TILT/WAKE or other IRQs - then we may need to implement the acking
+ * (which is racy).
+ */
+static irqreturn_t kx022a_irq_thread_handler(int irq, void *private)
+{
+ struct iio_dev *idev = private;
+ struct kx022a_data *data = iio_priv(idev);
+ irqreturn_t ret = IRQ_NONE;
+
+ mutex_lock(&data->mutex);
+
+ if (data->trigger_enabled) {
+ iio_trigger_poll_chained(data->trig);
+ ret = IRQ_HANDLED;
+ }
+
+ if (data->state & KX022A_STATE_FIFO) {
+ int ok;
+
+ ok = __kx022a_fifo_flush(idev, KX022A_FIFO_LENGTH, true);
+ if (ok > 0)
+ ret = IRQ_HANDLED;
+ }
+
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int kx022a_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct kx022a_data *data = iio_trigger_get_drvdata(trig);
+ int ret = 0;
+
+ mutex_lock(&data->mutex);
+
+ if (data->trigger_enabled == state)
+ goto unlock_out;
+
+ if (data->state & KX022A_STATE_FIFO) {
+ dev_warn(data->dev, "Can't set trigger when FIFO enabled\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ ret = kx022a_turn_on_off_unlocked(data, false);
+ if (ret)
+ goto unlock_out;
+
+ data->trigger_enabled = state;
+ ret = kx022a_set_drdy_irq(data, state);
+ if (ret)
+ goto unlock_out;
+
+ ret = kx022a_turn_on_off_unlocked(data, true);
+
+unlock_out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static const struct iio_trigger_ops kx022a_trigger_ops = {
+ .set_trigger_state = kx022a_trigger_set_state,
+};
+
+static int kx022a_chip_init(struct kx022a_data *data)
+{
+ int ret, val;
+
+ /* Reset the senor */
+ ret = regmap_write(data->regmap, KX022A_REG_CNTL2, KX022A_MASK_SRST);
+ if (ret)
+ return ret;
+
+ /*
+ * I've seen I2C read failures if we poll too fast after the sensor
+ * reset. Slight delay gives I2C block the time to recover.
+ */
+ msleep(1);
+
+ ret = regmap_read_poll_timeout(data->regmap, KX022A_REG_CNTL2, val,
+ !(val & KX022A_MASK_SRST),
+ KX022A_SOFT_RESET_WAIT_TIME_US,
+ KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US);
+ if (ret) {
+ dev_err(data->dev, "Sensor reset %s\n",
+ val & KX022A_MASK_SRST ? "timeout" : "fail#");
+ return ret;
+ }
+
+ ret = regmap_reinit_cache(data->regmap, &kx022a_regmap);
+ if (ret) {
+ dev_err(data->dev, "Failed to reinit reg cache\n");
+ return ret;
+ }
+
+ /* set data res 16bit */
+ ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+ KX022A_MASK_BRES16);
+ if (ret) {
+ dev_err(data->dev, "Failed to set data resolution\n");
+ return ret;
+ }
+
+ return kx022a_prepare_irq_pin(data);
+}
+
+int kx022a_probe_internal(struct device *dev)
+{
+ static const char * const regulator_names[] = {"io-vdd", "vdd"};
+ struct iio_trigger *indio_trig;
+ struct fwnode_handle *fwnode;
+ struct kx022a_data *data;
+ struct regmap *regmap;
+ unsigned int chip_id;
+ struct iio_dev *idev;
+ int ret, irq;
+ char *name;
+
+ regmap = dev_get_regmap(dev, NULL);
+ if (!regmap) {
+ dev_err(dev, "no regmap\n");
+ return -EINVAL;
+ }
+
+ fwnode = dev_fwnode(dev);
+ if (!fwnode)
+ return -ENODEV;
+
+ idev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!idev)
+ return -ENOMEM;
+
+ data = iio_priv(idev);
+
+ /*
+ * VDD is the analog and digital domain voltage supply and
+ * IO_VDD is the digital I/O voltage supply.
+ */
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
+ regulator_names);
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "failed to enable regulator\n");
+
+ ret = regmap_read(regmap, KX022A_REG_WHO, &chip_id);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to access sensor\n");
+
+ if (chip_id != KX022A_ID) {
+ dev_err(dev, "unsupported device 0x%x\n", chip_id);
+ return -EINVAL;
+ }
+
+ irq = fwnode_irq_get_byname(fwnode, "INT1");
+ if (irq > 0) {
+ data->inc_reg = KX022A_REG_INC1;
+ data->ien_reg = KX022A_REG_INC4;
+ } else {
+ irq = fwnode_irq_get_byname(fwnode, "INT2");
+ if (irq <= 0)
+ return dev_err_probe(dev, irq, "No suitable IRQ\n");
+
+ data->inc_reg = KX022A_REG_INC5;
+ data->ien_reg = KX022A_REG_INC6;
+ }
+
+ data->regmap = regmap;
+ data->dev = dev;
+ data->irq = irq;
+ data->odr_ns = KX022A_DEFAULT_PERIOD_NS;
+ mutex_init(&data->mutex);
+
+ idev->channels = kx022a_channels;
+ idev->num_channels = ARRAY_SIZE(kx022a_channels);
+ idev->name = "kx022-accel";
+ idev->info = &kx022a_info;
+ idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+ idev->available_scan_masks = kx022a_scan_masks;
+
+ /* Read the mounting matrix, if present */
+ ret = iio_read_mount_matrix(dev, &data->orientation);
+ if (ret)
+ return ret;
+
+ /* The sensor must be turned off for configuration */
+ ret = kx022a_turn_off_lock(data);
+ if (ret)
+ return ret;
+
+ ret = kx022a_chip_init(data);
+ if (ret) {
+ mutex_unlock(&data->mutex);
+ return ret;
+ }
+
+ ret = kx022a_turn_on_unlock(data);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup_ext(dev, idev,
+ &iio_pollfunc_store_time,
+ kx022a_trigger_handler,
+ IIO_BUFFER_DIRECTION_IN,
+ &kx022a_buffer_ops,
+ kx022a_fifo_attributes);
+
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "iio_triggered_buffer_setup_ext FAIL\n");
+ indio_trig = devm_iio_trigger_alloc(dev, "%sdata-rdy-dev%d", idev->name,
+ iio_device_id(idev));
+ if (!indio_trig)
+ return -ENOMEM;
+
+ data->trig = indio_trig;
+
+ indio_trig->ops = &kx022a_trigger_ops;
+ iio_trigger_set_drvdata(indio_trig, data);
+
+ /*
+ * No need to check for NULL. request_threaded_irq() defaults to
+ * dev_name() should the alloc fail.
+ */
+ name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-kx022a",
+ dev_name(data->dev));
+
+ ret = devm_request_threaded_irq(data->dev, irq, kx022a_irq_handler,
+ &kx022a_irq_thread_handler,
+ IRQF_ONESHOT, name, idev);
+ if (ret)
+ return dev_err_probe(data->dev, ret, "Could not request IRQ\n");
+
+
+ ret = devm_iio_trigger_register(dev, indio_trig);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "Trigger registration failed\n");
+
+ ret = devm_iio_device_register(data->dev, idev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Unable to register iio device\n");
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(kx022a_probe_internal, IIO_KX022A);
+
+MODULE_DESCRIPTION("ROHM/Kionix KX022A accelerometer driver");
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h
new file mode 100644
index 000000000000..12424649d438
--- /dev/null
+++ b/drivers/iio/accel/kionix-kx022a.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2022 ROHM Semiconductors
+ *
+ * ROHM/KIONIX KX022A accelerometer driver
+ */
+
+#ifndef _KX022A_H_
+#define _KX022A_H_
+
+#include <linux/bits.h>
+#include <linux/regmap.h>
+
+#define KX022A_REG_WHO 0x0f
+#define KX022A_ID 0xc8
+
+#define KX022A_REG_CNTL2 0x19
+#define KX022A_MASK_SRST BIT(7)
+#define KX022A_REG_CNTL 0x18
+#define KX022A_MASK_PC1 BIT(7)
+#define KX022A_MASK_RES BIT(6)
+#define KX022A_MASK_DRDY BIT(5)
+#define KX022A_MASK_GSEL GENMASK(4, 3)
+#define KX022A_GSEL_SHIFT 3
+#define KX022A_GSEL_2 0x0
+#define KX022A_GSEL_4 BIT(3)
+#define KX022A_GSEL_8 BIT(4)
+#define KX022A_GSEL_16 GENMASK(4, 3)
+
+#define KX022A_REG_INS2 0x13
+#define KX022A_MASK_INS2_DRDY BIT(4)
+#define KX122_MASK_INS2_WMI BIT(5)
+
+#define KX022A_REG_XHP_L 0x0
+#define KX022A_REG_XOUT_L 0x06
+#define KX022A_REG_YOUT_L 0x08
+#define KX022A_REG_ZOUT_L 0x0a
+#define KX022A_REG_COTR 0x0c
+#define KX022A_REG_TSCP 0x10
+#define KX022A_REG_INT_REL 0x17
+
+#define KX022A_REG_ODCNTL 0x1b
+
+#define KX022A_REG_BTS_WUF_TH 0x31
+#define KX022A_REG_MAN_WAKE 0x2c
+
+#define KX022A_REG_BUF_CNTL1 0x3a
+#define KX022A_MASK_WM_TH GENMASK(6, 0)
+#define KX022A_REG_BUF_CNTL2 0x3b
+#define KX022A_MASK_BUF_EN BIT(7)
+#define KX022A_MASK_BRES16 BIT(6)
+#define KX022A_REG_BUF_STATUS_1 0x3c
+#define KX022A_REG_BUF_STATUS_2 0x3d
+#define KX022A_REG_BUF_CLEAR 0x3e
+#define KX022A_REG_BUF_READ 0x3f
+#define KX022A_MASK_ODR GENMASK(3, 0)
+#define KX022A_ODR_SHIFT 3
+#define KX022A_FIFO_MAX_WMI_TH 41
+
+#define KX022A_REG_INC1 0x1c
+#define KX022A_REG_INC5 0x20
+#define KX022A_REG_INC6 0x21
+#define KX022A_MASK_IEN BIT(5)
+#define KX022A_MASK_IPOL BIT(4)
+#define KX022A_IPOL_LOW 0
+#define KX022A_IPOL_HIGH KX022A_MASK_IPOL1
+#define KX022A_MASK_ITYP BIT(3)
+#define KX022A_ITYP_PULSE KX022A_MASK_ITYP
+#define KX022A_ITYP_LEVEL 0
+
+#define KX022A_REG_INC4 0x1f
+#define KX022A_MASK_WMI BIT(5)
+
+#define KX022A_REG_SELF_TEST 0x60
+#define KX022A_MAX_REGISTER 0x60
+
+struct device;
+
+int kx022a_probe_internal(struct device *dev);
+extern const struct regmap_config kx022a_regmap;
+
+#endif
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index adc66b3615c0..98da4bda22df 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -241,7 +241,6 @@ enum kxcjk1013_axis {
};
struct kxcjk1013_data {
- struct regulator_bulk_data regulators[2];
struct i2c_client *client;
struct iio_trigger *dready_trig;
struct iio_trigger *motion_trig;
@@ -1425,16 +1424,10 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev,
return dev_name(dev);
}
-static void kxcjk1013_disable_regulators(void *d)
-{
- struct kxcjk1013_data *data = d;
-
- regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
-}
-
-static int kxcjk1013_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int kxcjk1013_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ static const char * const regulator_names[] = { "vdd", "vddio" };
struct kxcjk1013_data *data;
struct iio_dev *indio_dev;
struct kxcjk_1013_platform_data *pdata;
@@ -1461,22 +1454,12 @@ static int kxcjk1013_probe(struct i2c_client *client,
return ret;
}
- data->regulators[0].supply = "vdd";
- data->regulators[1].supply = "vddio";
- ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(data->regulators),
- data->regulators);
+ ret = devm_regulator_bulk_get_enable(&client->dev,
+ ARRAY_SIZE(regulator_names),
+ regulator_names);
if (ret)
return dev_err_probe(&client->dev, ret, "Failed to get regulators\n");
- ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
- data->regulators);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&client->dev, kxcjk1013_disable_regulators, data);
- if (ret)
- return ret;
-
/*
* A typical delay of 10ms is required for powering up
* according to the data sheets of supported chips.
@@ -1749,7 +1732,7 @@ static struct i2c_driver kxcjk1013_driver = {
.of_match_table = kxcjk1013_of_match,
.pm = &kxcjk1013_pm_ops,
},
- .probe = kxcjk1013_probe,
+ .probe_new = 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 61346ea8ef19..6b3683ddce36 100644
--- a/drivers/iio/accel/kxsd9-i2c.c
+++ b/drivers/iio/accel/kxsd9-i2c.c
@@ -10,8 +10,7 @@
#include "kxsd9.h"
-static int kxsd9_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int kxsd9_i2c_probe(struct i2c_client *i2c)
{
static const struct regmap_config config = {
.reg_bits = 8,
@@ -55,7 +54,7 @@ static struct i2c_driver kxsd9_i2c_driver = {
.of_match_table = kxsd9_of_match,
.pm = pm_ptr(&kxsd9_dev_pm_ops),
},
- .probe = kxsd9_i2c_probe,
+ .probe_new = 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 2462000e0519..efc21871de42 100644
--- a/drivers/iio/accel/mc3230.c
+++ b/drivers/iio/accel/mc3230.c
@@ -106,8 +106,7 @@ static const struct iio_info mc3230_info = {
.read_raw = mc3230_read_raw,
};
-static int mc3230_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mc3230_probe(struct i2c_client *client)
{
int ret;
struct iio_dev *indio_dev;
@@ -191,7 +190,7 @@ static struct i2c_driver mc3230_driver = {
.name = "mc3230",
.pm = pm_sleep_ptr(&mc3230_pm_ops),
},
- .probe = mc3230_probe,
+ .probe_new = 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 c63b321b01cd..a3864dbe2761 100644
--- a/drivers/iio/accel/mma7455_i2c.c
+++ b/drivers/iio/accel/mma7455_i2c.c
@@ -10,9 +10,9 @@
#include "mma7455.h"
-static int mma7455_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int mma7455_i2c_probe(struct i2c_client *i2c)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
struct regmap *regmap;
const char *name = NULL;
@@ -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 = mma7455_i2c_probe,
+ .probe_new = 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 85829990bbad..b279ca4dcdc0 100644
--- a/drivers/iio/accel/mma7660.c
+++ b/drivers/iio/accel/mma7660.c
@@ -169,8 +169,7 @@ static const struct iio_info mma7660_info = {
.attrs = &mma7660_attribute_group,
};
-static int mma7660_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mma7660_probe(struct i2c_client *client)
{
int ret;
struct iio_dev *indio_dev;
@@ -267,7 +266,7 @@ static struct i2c_driver mma7660_driver = {
.of_match_table = mma7660_of_match,
.acpi_match_table = mma7660_acpi_id,
},
- .probe = mma7660_probe,
+ .probe_new = 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 3ba28c2ff68a..f97fb68e3a71 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -1545,9 +1545,9 @@ static const struct of_device_id mma8452_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
-static int mma8452_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mma8452_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct mma8452_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -1846,7 +1846,7 @@ static struct i2c_driver mma8452_driver = {
.of_match_table = mma8452_dt_ids,
.pm = &mma8452_pm_ops,
},
- .probe = mma8452_probe,
+ .probe_new = mma8452_probe,
.remove = mma8452_remove,
.id_table = mma8452_id,
};
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index f7a793f4a8e3..aa4f5842859e 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -446,9 +446,9 @@ static const char *mma9551_match_acpi_device(struct device *dev)
return dev_name(dev);
}
-static int mma9551_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mma9551_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct mma9551_data *data;
struct iio_dev *indio_dev;
const char *name = NULL;
@@ -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 = mma9551_probe,
+ .probe_new = mma9551_probe,
.remove = mma9551_remove,
.id_table = mma9551_id,
};
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index 2da0e005b13e..0af578ef9d3d 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -1073,9 +1073,9 @@ static const char *mma9553_match_acpi_device(struct device *dev)
return dev_name(dev);
}
-static int mma9553_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mma9553_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct mma9553_data *data;
struct iio_dev *indio_dev;
const char *name = NULL;
@@ -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 = mma9553_probe,
+ .probe_new = mma9553_probe,
.remove = mma9553_remove,
.id_table = mma9553_id,
};
diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c
index 2fded3759171..af94d3adf6d8 100644
--- a/drivers/iio/accel/msa311.c
+++ b/drivers/iio/accel/msa311.c
@@ -351,7 +351,6 @@ static const struct regmap_config msa311_regmap_config = {
* @chip_name: Chip name in the format "msa311-%02x" % partid
* @new_data_trig: Optional NEW_DATA interrupt driven trigger used
* to notify external consumers a new sample is ready
- * @vdd: Optional external voltage regulator for the device power supply
*/
struct msa311_priv {
struct regmap *regs;
@@ -362,7 +361,6 @@ struct msa311_priv {
char *chip_name;
struct iio_trigger *new_data_trig;
- struct regulator *vdd;
};
enum msa311_si {
@@ -1146,11 +1144,6 @@ static void msa311_powerdown(void *msa311)
msa311_set_pwr_mode(msa311, MSA311_PWR_MODE_SUSPEND);
}
-static void msa311_vdd_disable(void *vdd)
-{
- regulator_disable(vdd);
-}
-
static int msa311_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
@@ -1173,19 +1166,9 @@ static int msa311_probe(struct i2c_client *i2c)
mutex_init(&msa311->lock);
- msa311->vdd = devm_regulator_get(dev, "vdd");
- if (IS_ERR(msa311->vdd))
- return dev_err_probe(dev, PTR_ERR(msa311->vdd),
- "can't get vdd supply\n");
-
- err = regulator_enable(msa311->vdd);
+ err = devm_regulator_get_enable(dev, "vdd");
if (err)
- return dev_err_probe(dev, err, "can't enable vdd supply\n");
-
- err = devm_add_action_or_reset(dev, msa311_vdd_disable, msa311->vdd);
- if (err)
- return dev_err_probe(dev, err,
- "can't add vdd disable action\n");
+ return dev_err_probe(dev, err, "can't get vdd supply\n");
err = msa311_check_partid(msa311);
if (err)
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index df600d2917c0..b146fc82738f 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -385,8 +385,7 @@ static int mxc4005_chip_init(struct mxc4005_data *data)
return 0;
}
-static int mxc4005_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mxc4005_probe(struct i2c_client *client)
{
struct mxc4005_data *data;
struct iio_dev *indio_dev;
@@ -489,7 +488,7 @@ static struct i2c_driver mxc4005_driver = {
.name = MXC4005_DRV_NAME,
.acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
},
- .probe = mxc4005_probe,
+ .probe_new = mxc4005_probe,
.id_table = mxc4005_id,
};
diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c
index 9aeeadc420d3..aa2e660545f8 100644
--- a/drivers/iio/accel/mxc6255.c
+++ b/drivers/iio/accel/mxc6255.c
@@ -113,8 +113,7 @@ static const struct regmap_config mxc6255_regmap_config = {
.readable_reg = mxc6255_is_readable_reg,
};
-static int mxc6255_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mxc6255_probe(struct i2c_client *client)
{
struct mxc6255_data *data;
struct iio_dev *indio_dev;
@@ -184,7 +183,7 @@ static struct i2c_driver mxc6255_driver = {
.name = MXC6255_DRV_NAME,
.acpi_match_table = ACPI_PTR(mxc6255_acpi_match),
},
- .probe = mxc6255_probe,
+ .probe_new = mxc6255_probe,
.id_table = mxc6255_id,
};
diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c
index eaa0c9cfda44..306482b70fad 100644
--- a/drivers/iio/accel/sca3300.c
+++ b/drivers/iio/accel/sca3300.c
@@ -679,12 +679,20 @@ static const struct of_device_id sca3300_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, sca3300_dt_ids);
+static const struct spi_device_id sca3300_ids[] = {
+ { "sca3300" },
+ { "scl3300" },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, sca3300_ids);
+
static struct spi_driver sca3300_driver = {
- .driver = {
+ .driver = {
.name = SCA3300_ALIAS,
.of_match_table = sca3300_dt_ids,
},
- .probe = sca3300_probe,
+ .probe = sca3300_probe,
+ .id_table = sca3300_ids,
};
module_spi_driver(sca3300_driver);
diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index 7b1d6fb692b3..68f680db7505 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -498,8 +498,7 @@ static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = {
.postdisable = stk8312_buffer_postdisable,
};
-static int stk8312_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int stk8312_probe(struct i2c_client *client)
{
int ret;
struct iio_dev *indio_dev;
@@ -645,7 +644,7 @@ static struct i2c_driver stk8312_driver = {
.name = STK8312_DRIVER_NAME,
.pm = pm_sleep_ptr(&stk8312_pm_ops),
},
- .probe = stk8312_probe,
+ .probe_new = 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 2f5e4ab2a6e7..44f6e0fbdfcc 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -379,8 +379,7 @@ static const struct iio_buffer_setup_ops stk8ba50_buffer_setup_ops = {
.postdisable = stk8ba50_buffer_postdisable,
};
-static int stk8ba50_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int stk8ba50_probe(struct i2c_client *client)
{
int ret;
struct iio_dev *indio_dev;
@@ -544,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 = stk8ba50_probe,
+ .probe_new = stk8ba50_probe,
.remove = stk8ba50_remove,
.id_table = stk8ba50_i2c_id,
};
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 791612ca6012..63f80d747cbd 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -21,6 +21,21 @@ config AD_SIGMA_DELTA
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
+config AD4130
+ tristate "Analog Device AD4130 ADC Driver"
+ depends on SPI
+ depends on GPIOLIB
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ select REGMAP_SPI
+ depends on COMMON_CLK
+ help
+ Say yes here to build support for Analog Devices AD4130-8 SPI analog
+ to digital converters (ADC).
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad4130.
+
config AD7091R5
tristate "Analog Devices AD7091R5 ADC Driver"
depends on I2C
@@ -667,6 +682,19 @@ config MAX11205
To compile this driver as a module, choose M here: the module will be
called max11205.
+config MAX11410
+ tristate "Analog Devices MAX11410 ADC driver"
+ depends on SPI
+ select REGMAP_SPI
+ select IIO_BUFFER
+ select IIO_TRIGGER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Analog Devices MAX11410 ADCs.
+
+ To compile this driver as a module, choose M here: the module will be
+ called max11410.
+
config MAX1241
tristate "Maxim max1241 ADC driver"
depends on SPI_MASTER
@@ -752,6 +780,18 @@ config MEDIATEK_MT6360_ADC
is used in smartphones and tablets and supports a 11 channel
general purpose ADC.
+config MEDIATEK_MT6370_ADC
+ tristate "MediaTek MT6370 ADC driver"
+ depends on MFD_MT6370
+ help
+ Say yes here to enable MediaTek MT6370 ADC support.
+
+ This ADC driver provides 9 channels for system monitoring (charger
+ current, voltage, and temperature).
+
+ This driver can also be built as a module. If so, the module
+ will be called "mt6370-adc".
+
config MEDIATEK_MT6577_AUXADC
tristate "MediaTek AUXADC driver"
depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 46caba7a010c..4ef41a7dfac6 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -6,6 +6,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
+obj-$(CONFIG_AD4130) += ad4130.o
obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o
obj-$(CONFIG_AD7124) += ad7124.o
obj-$(CONFIG_AD7192) += ad7192.o
@@ -62,6 +63,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX11100) += max11100.o
obj-$(CONFIG_MAX1118) += max1118.o
obj-$(CONFIG_MAX11205) += max11205.o
+obj-$(CONFIG_MAX11410) += max11410.o
obj-$(CONFIG_MAX1241) += max1241.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MAX9611) += max9611.o
@@ -69,6 +71,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MCP3911) += mcp3911.o
obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
+obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c
new file mode 100644
index 000000000000..38394341fd6e
--- /dev/null
+++ b/drivers/iio/adc/ad4130.c
@@ -0,0 +1,2100 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Analog Devices, Inc.
+ * Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+
+#include <asm/div64.h>
+#include <asm/unaligned.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
+
+#define AD4130_NAME "ad4130"
+
+#define AD4130_COMMS_READ_MASK BIT(6)
+
+#define AD4130_STATUS_REG 0x00
+
+#define AD4130_ADC_CONTROL_REG 0x01
+#define AD4130_ADC_CONTROL_BIPOLAR_MASK BIT(14)
+#define AD4130_ADC_CONTROL_INT_REF_VAL_MASK BIT(13)
+#define AD4130_INT_REF_2_5V 2500000
+#define AD4130_INT_REF_1_25V 1250000
+#define AD4130_ADC_CONTROL_CSB_EN_MASK BIT(9)
+#define AD4130_ADC_CONTROL_INT_REF_EN_MASK BIT(8)
+#define AD4130_ADC_CONTROL_MODE_MASK GENMASK(5, 2)
+#define AD4130_ADC_CONTROL_MCLK_SEL_MASK GENMASK(1, 0)
+#define AD4130_MCLK_FREQ_76_8KHZ 76800
+#define AD4130_MCLK_FREQ_153_6KHZ 153600
+
+#define AD4130_DATA_REG 0x02
+
+#define AD4130_IO_CONTROL_REG 0x03
+#define AD4130_IO_CONTROL_INT_PIN_SEL_MASK GENMASK(9, 8)
+#define AD4130_IO_CONTROL_GPIO_DATA_MASK GENMASK(7, 4)
+#define AD4130_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 0)
+
+#define AD4130_VBIAS_REG 0x04
+
+#define AD4130_ID_REG 0x05
+
+#define AD4130_ERROR_REG 0x06
+
+#define AD4130_ERROR_EN_REG 0x07
+
+#define AD4130_MCLK_COUNT_REG 0x08
+
+#define AD4130_CHANNEL_X_REG(x) (0x09 + (x))
+#define AD4130_CHANNEL_EN_MASK BIT(23)
+#define AD4130_CHANNEL_SETUP_MASK GENMASK(22, 20)
+#define AD4130_CHANNEL_AINP_MASK GENMASK(17, 13)
+#define AD4130_CHANNEL_AINM_MASK GENMASK(12, 8)
+#define AD4130_CHANNEL_IOUT1_MASK GENMASK(7, 4)
+#define AD4130_CHANNEL_IOUT2_MASK GENMASK(3, 0)
+
+#define AD4130_CONFIG_X_REG(x) (0x19 + (x))
+#define AD4130_CONFIG_IOUT1_VAL_MASK GENMASK(15, 13)
+#define AD4130_CONFIG_IOUT2_VAL_MASK GENMASK(12, 10)
+#define AD4130_CONFIG_BURNOUT_MASK GENMASK(9, 8)
+#define AD4130_CONFIG_REF_BUFP_MASK BIT(7)
+#define AD4130_CONFIG_REF_BUFM_MASK BIT(6)
+#define AD4130_CONFIG_REF_SEL_MASK GENMASK(5, 4)
+#define AD4130_CONFIG_PGA_MASK GENMASK(3, 1)
+
+#define AD4130_FILTER_X_REG(x) (0x21 + (x))
+#define AD4130_FILTER_MODE_MASK GENMASK(15, 12)
+#define AD4130_FILTER_SELECT_MASK GENMASK(10, 0)
+#define AD4130_FILTER_SELECT_MIN 1
+
+#define AD4130_OFFSET_X_REG(x) (0x29 + (x))
+
+#define AD4130_GAIN_X_REG(x) (0x31 + (x))
+
+#define AD4130_MISC_REG 0x39
+
+#define AD4130_FIFO_CONTROL_REG 0x3a
+#define AD4130_FIFO_CONTROL_HEADER_MASK BIT(18)
+#define AD4130_FIFO_CONTROL_MODE_MASK GENMASK(17, 16)
+#define AD4130_FIFO_CONTROL_WM_INT_EN_MASK BIT(9)
+#define AD4130_FIFO_CONTROL_WM_MASK GENMASK(7, 0)
+#define AD4130_WATERMARK_256 0
+
+#define AD4130_FIFO_STATUS_REG 0x3b
+
+#define AD4130_FIFO_THRESHOLD_REG 0x3c
+
+#define AD4130_FIFO_DATA_REG 0x3d
+#define AD4130_FIFO_SIZE 256
+#define AD4130_FIFO_MAX_SAMPLE_SIZE 3
+
+#define AD4130_MAX_ANALOG_PINS 16
+#define AD4130_MAX_CHANNELS 16
+#define AD4130_MAX_DIFF_INPUTS 30
+#define AD4130_MAX_GPIOS 4
+#define AD4130_MAX_ODR 2400
+#define AD4130_MAX_PGA 8
+#define AD4130_MAX_SETUPS 8
+
+#define AD4130_AIN2_P1 0x2
+#define AD4130_AIN3_P2 0x3
+
+#define AD4130_RESET_BUF_SIZE 8
+#define AD4130_RESET_SLEEP_US (160 * MICRO / AD4130_MCLK_FREQ_76_8KHZ)
+
+#define AD4130_INVALID_SLOT -1
+
+static const unsigned int ad4130_reg_size[] = {
+ [AD4130_STATUS_REG] = 1,
+ [AD4130_ADC_CONTROL_REG] = 2,
+ [AD4130_DATA_REG] = 3,
+ [AD4130_IO_CONTROL_REG] = 2,
+ [AD4130_VBIAS_REG] = 2,
+ [AD4130_ID_REG] = 1,
+ [AD4130_ERROR_REG] = 2,
+ [AD4130_ERROR_EN_REG] = 2,
+ [AD4130_MCLK_COUNT_REG] = 1,
+ [AD4130_CHANNEL_X_REG(0) ... AD4130_CHANNEL_X_REG(AD4130_MAX_CHANNELS - 1)] = 3,
+ [AD4130_CONFIG_X_REG(0) ... AD4130_CONFIG_X_REG(AD4130_MAX_SETUPS - 1)] = 2,
+ [AD4130_FILTER_X_REG(0) ... AD4130_FILTER_X_REG(AD4130_MAX_SETUPS - 1)] = 3,
+ [AD4130_OFFSET_X_REG(0) ... AD4130_OFFSET_X_REG(AD4130_MAX_SETUPS - 1)] = 3,
+ [AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 3,
+ [AD4130_MISC_REG] = 2,
+ [AD4130_FIFO_CONTROL_REG] = 3,
+ [AD4130_FIFO_STATUS_REG] = 1,
+ [AD4130_FIFO_THRESHOLD_REG] = 3,
+ [AD4130_FIFO_DATA_REG] = 3,
+};
+
+enum ad4130_int_ref_val {
+ AD4130_INT_REF_VAL_2_5V,
+ AD4130_INT_REF_VAL_1_25V,
+};
+
+enum ad4130_mclk_sel {
+ AD4130_MCLK_76_8KHZ,
+ AD4130_MCLK_76_8KHZ_OUT,
+ AD4130_MCLK_76_8KHZ_EXT,
+ AD4130_MCLK_153_6KHZ_EXT,
+};
+
+enum ad4130_int_pin_sel {
+ AD4130_INT_PIN_INT,
+ AD4130_INT_PIN_CLK,
+ AD4130_INT_PIN_P2,
+ AD4130_INT_PIN_DOUT,
+};
+
+enum ad4130_iout {
+ AD4130_IOUT_OFF,
+ AD4130_IOUT_10000NA,
+ AD4130_IOUT_20000NA,
+ AD4130_IOUT_50000NA,
+ AD4130_IOUT_100000NA,
+ AD4130_IOUT_150000NA,
+ AD4130_IOUT_200000NA,
+ AD4130_IOUT_100NA,
+ AD4130_IOUT_MAX
+};
+
+enum ad4130_burnout {
+ AD4130_BURNOUT_OFF,
+ AD4130_BURNOUT_500NA,
+ AD4130_BURNOUT_2000NA,
+ AD4130_BURNOUT_4000NA,
+ AD4130_BURNOUT_MAX
+};
+
+enum ad4130_ref_sel {
+ AD4130_REF_REFIN1,
+ AD4130_REF_REFIN2,
+ AD4130_REF_REFOUT_AVSS,
+ AD4130_REF_AVDD_AVSS,
+ AD4130_REF_SEL_MAX
+};
+
+enum ad4130_fifo_mode {
+ AD4130_FIFO_MODE_DISABLED = 0b00,
+ AD4130_FIFO_MODE_WM = 0b01,
+};
+
+enum ad4130_mode {
+ AD4130_MODE_CONTINUOUS = 0b0000,
+ AD4130_MODE_IDLE = 0b0100,
+};
+
+enum ad4130_filter_mode {
+ AD4130_FILTER_SINC4,
+ AD4130_FILTER_SINC4_SINC1,
+ AD4130_FILTER_SINC3,
+ AD4130_FILTER_SINC3_REJ60,
+ AD4130_FILTER_SINC3_SINC1,
+ AD4130_FILTER_SINC3_PF1,
+ AD4130_FILTER_SINC3_PF2,
+ AD4130_FILTER_SINC3_PF3,
+ AD4130_FILTER_SINC3_PF4,
+};
+
+enum ad4130_pin_function {
+ AD4130_PIN_FN_NONE,
+ AD4130_PIN_FN_SPECIAL = BIT(0),
+ AD4130_PIN_FN_DIFF = BIT(1),
+ AD4130_PIN_FN_EXCITATION = BIT(2),
+ AD4130_PIN_FN_VBIAS = BIT(3),
+};
+
+struct ad4130_setup_info {
+ unsigned int iout0_val;
+ unsigned int iout1_val;
+ unsigned int burnout;
+ unsigned int pga;
+ unsigned int fs;
+ u32 ref_sel;
+ enum ad4130_filter_mode filter_mode;
+ bool ref_bufp;
+ bool ref_bufm;
+};
+
+struct ad4130_slot_info {
+ struct ad4130_setup_info setup;
+ unsigned int enabled_channels;
+ unsigned int channels;
+};
+
+struct ad4130_chan_info {
+ struct ad4130_setup_info setup;
+ u32 iout0;
+ u32 iout1;
+ int slot;
+ bool enabled;
+ bool initialized;
+};
+
+struct ad4130_filter_config {
+ enum ad4130_filter_mode filter_mode;
+ unsigned int odr_div;
+ unsigned int fs_max;
+ enum iio_available_type samp_freq_avail_type;
+ int samp_freq_avail_len;
+ int samp_freq_avail[3][2];
+};
+
+struct ad4130_state {
+ struct regmap *regmap;
+ struct spi_device *spi;
+ struct clk *mclk;
+ struct regulator_bulk_data regulators[4];
+ u32 irq_trigger;
+ u32 inv_irq_trigger;
+
+ /*
+ * Synchronize access to members the of driver state, and ensure
+ * atomicity of consecutive regmap operations.
+ */
+ struct mutex lock;
+ struct completion completion;
+
+ struct iio_chan_spec chans[AD4130_MAX_CHANNELS];
+ struct ad4130_chan_info chans_info[AD4130_MAX_CHANNELS];
+ struct ad4130_slot_info slots_info[AD4130_MAX_SETUPS];
+ enum ad4130_pin_function pins_fn[AD4130_MAX_ANALOG_PINS];
+ u32 vbias_pins[AD4130_MAX_ANALOG_PINS];
+ u32 num_vbias_pins;
+ int scale_tbls[AD4130_REF_SEL_MAX][AD4130_MAX_PGA][2];
+ struct gpio_chip gc;
+ struct clk_hw int_clk_hw;
+
+ u32 int_pin_sel;
+ u32 int_ref_uv;
+ u32 mclk_sel;
+ bool int_ref_en;
+ bool bipolar;
+
+ unsigned int num_enabled_channels;
+ unsigned int effective_watermark;
+ unsigned int watermark;
+
+ struct spi_message fifo_msg;
+ struct spi_transfer fifo_xfer[2];
+
+ /*
+ * DMA (thus cache coherency maintenance) requires any transfer
+ * buffers to live in their own cache lines. As the use of these
+ * buffers is synchronous, all of the buffers used for DMA in this
+ * driver may share a cache line.
+ */
+ u8 reset_buf[AD4130_RESET_BUF_SIZE] __aligned(IIO_DMA_MINALIGN);
+ u8 reg_write_tx_buf[4];
+ u8 reg_read_tx_buf[1];
+ u8 reg_read_rx_buf[3];
+ u8 fifo_tx_buf[2];
+ u8 fifo_rx_buf[AD4130_FIFO_SIZE *
+ AD4130_FIFO_MAX_SAMPLE_SIZE];
+};
+
+static const char * const ad4130_int_pin_names[] = {
+ [AD4130_INT_PIN_INT] = "int",
+ [AD4130_INT_PIN_CLK] = "clk",
+ [AD4130_INT_PIN_P2] = "p2",
+ [AD4130_INT_PIN_DOUT] = "dout",
+};
+
+static const unsigned int ad4130_iout_current_na_tbl[AD4130_IOUT_MAX] = {
+ [AD4130_IOUT_OFF] = 0,
+ [AD4130_IOUT_100NA] = 100,
+ [AD4130_IOUT_10000NA] = 10000,
+ [AD4130_IOUT_20000NA] = 20000,
+ [AD4130_IOUT_50000NA] = 50000,
+ [AD4130_IOUT_100000NA] = 100000,
+ [AD4130_IOUT_150000NA] = 150000,
+ [AD4130_IOUT_200000NA] = 200000,
+};
+
+static const unsigned int ad4130_burnout_current_na_tbl[AD4130_BURNOUT_MAX] = {
+ [AD4130_BURNOUT_OFF] = 0,
+ [AD4130_BURNOUT_500NA] = 500,
+ [AD4130_BURNOUT_2000NA] = 2000,
+ [AD4130_BURNOUT_4000NA] = 4000,
+};
+
+#define AD4130_VARIABLE_ODR_CONFIG(_filter_mode, _odr_div, _fs_max) \
+{ \
+ .filter_mode = (_filter_mode), \
+ .odr_div = (_odr_div), \
+ .fs_max = (_fs_max), \
+ .samp_freq_avail_type = IIO_AVAIL_RANGE, \
+ .samp_freq_avail = { \
+ { AD4130_MAX_ODR, (_odr_div) * (_fs_max) }, \
+ { AD4130_MAX_ODR, (_odr_div) * (_fs_max) }, \
+ { AD4130_MAX_ODR, (_odr_div) }, \
+ }, \
+}
+
+#define AD4130_FIXED_ODR_CONFIG(_filter_mode, _odr_div) \
+{ \
+ .filter_mode = (_filter_mode), \
+ .odr_div = (_odr_div), \
+ .fs_max = AD4130_FILTER_SELECT_MIN, \
+ .samp_freq_avail_type = IIO_AVAIL_LIST, \
+ .samp_freq_avail_len = 1, \
+ .samp_freq_avail = { \
+ { AD4130_MAX_ODR, (_odr_div) }, \
+ }, \
+}
+
+static const struct ad4130_filter_config ad4130_filter_configs[] = {
+ AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC4, 1, 10),
+ AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC4_SINC1, 11, 10),
+ AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC3, 1, 2047),
+ AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC3_REJ60, 1, 2047),
+ AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC3_SINC1, 10, 2047),
+ AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF1, 92),
+ AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF2, 100),
+ AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF3, 124),
+ AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF4, 148),
+};
+
+static const char * const ad4130_filter_modes_str[] = {
+ [AD4130_FILTER_SINC4] = "sinc4",
+ [AD4130_FILTER_SINC4_SINC1] = "sinc4+sinc1",
+ [AD4130_FILTER_SINC3] = "sinc3",
+ [AD4130_FILTER_SINC3_REJ60] = "sinc3+rej60",
+ [AD4130_FILTER_SINC3_SINC1] = "sinc3+sinc1",
+ [AD4130_FILTER_SINC3_PF1] = "sinc3+pf1",
+ [AD4130_FILTER_SINC3_PF2] = "sinc3+pf2",
+ [AD4130_FILTER_SINC3_PF3] = "sinc3+pf3",
+ [AD4130_FILTER_SINC3_PF4] = "sinc3+pf4",
+};
+
+static int ad4130_get_reg_size(struct ad4130_state *st, unsigned int reg,
+ unsigned int *size)
+{
+ if (reg >= ARRAY_SIZE(ad4130_reg_size))
+ return -EINVAL;
+
+ *size = ad4130_reg_size[reg];
+
+ return 0;
+}
+
+static unsigned int ad4130_data_reg_size(struct ad4130_state *st)
+{
+ unsigned int data_reg_size;
+ int ret;
+
+ ret = ad4130_get_reg_size(st, AD4130_DATA_REG, &data_reg_size);
+ if (ret)
+ return 0;
+
+ return data_reg_size;
+}
+
+static unsigned int ad4130_resolution(struct ad4130_state *st)
+{
+ return ad4130_data_reg_size(st) * BITS_PER_BYTE;
+}
+
+static int ad4130_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct ad4130_state *st = context;
+ unsigned int size;
+ int ret;
+
+ ret = ad4130_get_reg_size(st, reg, &size);
+ if (ret)
+ return ret;
+
+ st->reg_write_tx_buf[0] = reg;
+
+ switch (size) {
+ case 3:
+ put_unaligned_be24(val, &st->reg_write_tx_buf[1]);
+ break;
+ case 2:
+ put_unaligned_be16(val, &st->reg_write_tx_buf[1]);
+ break;
+ case 1:
+ st->reg_write_tx_buf[1] = val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return spi_write(st->spi, st->reg_write_tx_buf, size + 1);
+}
+
+static int ad4130_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct ad4130_state *st = context;
+ struct spi_transfer t[] = {
+ {
+ .tx_buf = st->reg_read_tx_buf,
+ .len = sizeof(st->reg_read_tx_buf),
+ },
+ {
+ .rx_buf = st->reg_read_rx_buf,
+ },
+ };
+ unsigned int size;
+ int ret;
+
+ ret = ad4130_get_reg_size(st, reg, &size);
+ if (ret)
+ return ret;
+
+ st->reg_read_tx_buf[0] = AD4130_COMMS_READ_MASK | reg;
+ t[1].len = size;
+
+ ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
+ if (ret)
+ return ret;
+
+ switch (size) {
+ case 3:
+ *val = get_unaligned_be24(st->reg_read_rx_buf);
+ break;
+ case 2:
+ *val = get_unaligned_be16(st->reg_read_rx_buf);
+ break;
+ case 1:
+ *val = st->reg_read_rx_buf[0];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct regmap_config ad4130_regmap_config = {
+ .reg_read = ad4130_reg_read,
+ .reg_write = ad4130_reg_write,
+};
+
+static int ad4130_gpio_init_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask,
+ unsigned int ngpios)
+{
+ struct ad4130_state *st = gpiochip_get_data(gc);
+ unsigned int i;
+
+ /*
+ * Output-only GPIO functionality is available on pins AIN2 through
+ * AIN5. If these pins are used for anything else, do not expose them.
+ */
+ for (i = 0; i < ngpios; i++) {
+ unsigned int pin = i + AD4130_AIN2_P1;
+ bool valid = st->pins_fn[pin] == AD4130_PIN_FN_NONE;
+
+ __assign_bit(i, valid_mask, valid);
+ }
+
+ return 0;
+}
+
+static int ad4130_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static void ad4130_gpio_set(struct gpio_chip *gc, unsigned int offset,
+ int value)
+{
+ struct ad4130_state *st = gpiochip_get_data(gc);
+ unsigned int mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK,
+ BIT(offset));
+
+ regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask,
+ value ? mask : 0);
+}
+
+static int ad4130_set_mode(struct ad4130_state *st, enum ad4130_mode mode)
+{
+ return regmap_update_bits(st->regmap, AD4130_ADC_CONTROL_REG,
+ AD4130_ADC_CONTROL_MODE_MASK,
+ FIELD_PREP(AD4130_ADC_CONTROL_MODE_MASK, mode));
+}
+
+static int ad4130_set_watermark_interrupt_en(struct ad4130_state *st, bool en)
+{
+ return regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+ AD4130_FIFO_CONTROL_WM_INT_EN_MASK,
+ FIELD_PREP(AD4130_FIFO_CONTROL_WM_INT_EN_MASK, en));
+}
+
+static unsigned int ad4130_watermark_reg_val(unsigned int val)
+{
+ if (val == AD4130_FIFO_SIZE)
+ val = AD4130_WATERMARK_256;
+
+ return val;
+}
+
+static int ad4130_set_fifo_mode(struct ad4130_state *st,
+ enum ad4130_fifo_mode mode)
+{
+ return regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+ AD4130_FIFO_CONTROL_MODE_MASK,
+ FIELD_PREP(AD4130_FIFO_CONTROL_MODE_MASK, mode));
+}
+
+static void ad4130_push_fifo_data(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int data_reg_size = ad4130_data_reg_size(st);
+ unsigned int transfer_len = st->effective_watermark * data_reg_size;
+ unsigned int set_size = st->num_enabled_channels * data_reg_size;
+ unsigned int i;
+ int ret;
+
+ st->fifo_tx_buf[1] = ad4130_watermark_reg_val(st->effective_watermark);
+ st->fifo_xfer[1].len = transfer_len;
+
+ ret = spi_sync(st->spi, &st->fifo_msg);
+ if (ret)
+ return;
+
+ for (i = 0; i < transfer_len; i += set_size)
+ iio_push_to_buffers(indio_dev, &st->fifo_rx_buf[i]);
+}
+
+static irqreturn_t ad4130_irq_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct ad4130_state *st = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev))
+ ad4130_push_fifo_data(indio_dev);
+ else
+ complete(&st->completion);
+
+ return IRQ_HANDLED;
+}
+
+static int ad4130_find_slot(struct ad4130_state *st,
+ struct ad4130_setup_info *target_setup_info,
+ unsigned int *slot, bool *overwrite)
+{
+ unsigned int i;
+
+ *slot = AD4130_INVALID_SLOT;
+ *overwrite = false;
+
+ for (i = 0; i < AD4130_MAX_SETUPS; i++) {
+ struct ad4130_slot_info *slot_info = &st->slots_info[i];
+
+ /* Immediately accept a matching setup info. */
+ if (!memcmp(target_setup_info, &slot_info->setup,
+ sizeof(*target_setup_info))) {
+ *slot = i;
+ return 0;
+ }
+
+ /* Ignore all setups which are used by enabled channels. */
+ if (slot_info->enabled_channels)
+ continue;
+
+ /* Find the least used slot. */
+ if (*slot == AD4130_INVALID_SLOT ||
+ slot_info->channels < st->slots_info[*slot].channels)
+ *slot = i;
+ }
+
+ if (*slot == AD4130_INVALID_SLOT)
+ return -EINVAL;
+
+ *overwrite = true;
+
+ return 0;
+}
+
+static void ad4130_unlink_channel(struct ad4130_state *st, unsigned int channel)
+{
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_slot_info *slot_info = &st->slots_info[chan_info->slot];
+
+ chan_info->slot = AD4130_INVALID_SLOT;
+ slot_info->channels--;
+}
+
+static int ad4130_unlink_slot(struct ad4130_state *st, unsigned int slot)
+{
+ unsigned int i;
+
+ for (i = 0; i < AD4130_MAX_CHANNELS; i++) {
+ struct ad4130_chan_info *chan_info = &st->chans_info[i];
+
+ if (!chan_info->initialized || chan_info->slot != slot)
+ continue;
+
+ ad4130_unlink_channel(st, i);
+ }
+
+ return 0;
+}
+
+static int ad4130_link_channel_slot(struct ad4130_state *st,
+ unsigned int channel, unsigned int slot)
+{
+ struct ad4130_slot_info *slot_info = &st->slots_info[slot];
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ int ret;
+
+ ret = regmap_update_bits(st->regmap, AD4130_CHANNEL_X_REG(channel),
+ AD4130_CHANNEL_SETUP_MASK,
+ FIELD_PREP(AD4130_CHANNEL_SETUP_MASK, slot));
+ if (ret)
+ return ret;
+
+ chan_info->slot = slot;
+ slot_info->channels++;
+
+ return 0;
+}
+
+static int ad4130_write_slot_setup(struct ad4130_state *st,
+ unsigned int slot,
+ struct ad4130_setup_info *setup_info)
+{
+ unsigned int val;
+ int ret;
+
+ val = FIELD_PREP(AD4130_CONFIG_IOUT1_VAL_MASK, setup_info->iout0_val) |
+ FIELD_PREP(AD4130_CONFIG_IOUT1_VAL_MASK, setup_info->iout1_val) |
+ FIELD_PREP(AD4130_CONFIG_BURNOUT_MASK, setup_info->burnout) |
+ FIELD_PREP(AD4130_CONFIG_REF_BUFP_MASK, setup_info->ref_bufp) |
+ FIELD_PREP(AD4130_CONFIG_REF_BUFM_MASK, setup_info->ref_bufm) |
+ FIELD_PREP(AD4130_CONFIG_REF_SEL_MASK, setup_info->ref_sel) |
+ FIELD_PREP(AD4130_CONFIG_PGA_MASK, setup_info->pga);
+
+ ret = regmap_write(st->regmap, AD4130_CONFIG_X_REG(slot), val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(AD4130_FILTER_MODE_MASK, setup_info->filter_mode) |
+ FIELD_PREP(AD4130_FILTER_SELECT_MASK, setup_info->fs);
+
+ ret = regmap_write(st->regmap, AD4130_FILTER_X_REG(slot), val);
+ if (ret)
+ return ret;
+
+ memcpy(&st->slots_info[slot].setup, setup_info, sizeof(*setup_info));
+
+ return 0;
+}
+
+static int ad4130_write_channel_setup(struct ad4130_state *st,
+ unsigned int channel, bool on_enable)
+{
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_setup_info *setup_info = &chan_info->setup;
+ bool overwrite;
+ int slot;
+ int ret;
+
+ /*
+ * The following cases need to be handled.
+ *
+ * 1. Enabled and linked channel with setup changes:
+ * - Find a slot. If not possible, return error.
+ * - Unlink channel from current slot.
+ * - If the slot has channels linked to it, unlink all channels, and
+ * write the new setup to it.
+ * - Link channel to new slot.
+ *
+ * 2. Soon to be enabled and unlinked channel:
+ * - Find a slot. If not possible, return error.
+ * - If the slot has channels linked to it, unlink all channels, and
+ * write the new setup to it.
+ * - Link channel to the slot.
+ *
+ * 3. Disabled and linked channel with setup changes:
+ * - Unlink channel from current slot.
+ *
+ * 4. Soon to be enabled and linked channel:
+ * 5. Disabled and unlinked channel with setup changes:
+ * - Do nothing.
+ */
+
+ /* Case 4 */
+ if (on_enable && chan_info->slot != AD4130_INVALID_SLOT)
+ return 0;
+
+ if (!on_enable && !chan_info->enabled) {
+ if (chan_info->slot != AD4130_INVALID_SLOT)
+ /* Case 3 */
+ ad4130_unlink_channel(st, channel);
+
+ /* Cases 3 & 5 */
+ return 0;
+ }
+
+ /* Cases 1 & 2 */
+ ret = ad4130_find_slot(st, setup_info, &slot, &overwrite);
+ if (ret)
+ return ret;
+
+ if (chan_info->slot != AD4130_INVALID_SLOT)
+ /* Case 1 */
+ ad4130_unlink_channel(st, channel);
+
+ if (overwrite) {
+ ret = ad4130_unlink_slot(st, slot);
+ if (ret)
+ return ret;
+
+ ret = ad4130_write_slot_setup(st, slot, setup_info);
+ if (ret)
+ return ret;
+ }
+
+ return ad4130_link_channel_slot(st, channel, slot);
+}
+
+static int ad4130_set_channel_enable(struct ad4130_state *st,
+ unsigned int channel, bool status)
+{
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_slot_info *slot_info;
+ int ret;
+
+ if (chan_info->enabled == status)
+ return 0;
+
+ if (status) {
+ ret = ad4130_write_channel_setup(st, channel, true);
+ if (ret)
+ return ret;
+ }
+
+ slot_info = &st->slots_info[chan_info->slot];
+
+ ret = regmap_update_bits(st->regmap, AD4130_CHANNEL_X_REG(channel),
+ AD4130_CHANNEL_EN_MASK,
+ FIELD_PREP(AD4130_CHANNEL_EN_MASK, status));
+ if (ret)
+ return ret;
+
+ slot_info->enabled_channels += status ? 1 : -1;
+ chan_info->enabled = status;
+
+ return 0;
+}
+
+/*
+ * Table 58. FILTER_MODE_n bits and Filter Types of the datasheet describes
+ * the relation between filter mode, ODR and FS.
+ *
+ * Notice that the max ODR of each filter mode is not necessarily the
+ * absolute max ODR supported by the chip.
+ *
+ * The ODR divider is not explicitly specified, but it can be deduced based
+ * on the ODR range of each filter mode.
+ *
+ * For example, for Sinc4+Sinc1, max ODR is 218.18. That means that the
+ * absolute max ODR is divided by 11 to achieve the max ODR of this filter
+ * mode.
+ *
+ * The formulas for converting between ODR and FS for a specific filter
+ * mode can be deduced from the same table.
+ *
+ * Notice that FS = 1 actually means max ODR, and that ODR decreases by
+ * (maximum ODR / maximum FS) for each increment of FS.
+ *
+ * odr = MAX_ODR / odr_div * (1 - (fs - 1) / fs_max) <=>
+ * odr = MAX_ODR * (1 - (fs - 1) / fs_max) / odr_div <=>
+ * odr = MAX_ODR * (1 - (fs - 1) / fs_max) / odr_div <=>
+ * odr = MAX_ODR * (fs_max - fs + 1) / (fs_max * odr_div)
+ * (used in ad4130_fs_to_freq)
+ *
+ * For the opposite formula, FS can be extracted from the last one.
+ *
+ * MAX_ODR * (fs_max - fs + 1) = fs_max * odr_div * odr <=>
+ * fs_max - fs + 1 = fs_max * odr_div * odr / MAX_ODR <=>
+ * fs = 1 + fs_max - fs_max * odr_div * odr / MAX_ODR
+ * (used in ad4130_fs_to_freq)
+ */
+
+static void ad4130_freq_to_fs(enum ad4130_filter_mode filter_mode,
+ int val, int val2, unsigned int *fs)
+{
+ const struct ad4130_filter_config *filter_config =
+ &ad4130_filter_configs[filter_mode];
+ u64 dividend, divisor;
+ int temp;
+
+ dividend = filter_config->fs_max * filter_config->odr_div *
+ ((u64)val * NANO + val2);
+ divisor = (u64)AD4130_MAX_ODR * NANO;
+
+ temp = AD4130_FILTER_SELECT_MIN + filter_config->fs_max -
+ DIV64_U64_ROUND_CLOSEST(dividend, divisor);
+
+ if (temp < AD4130_FILTER_SELECT_MIN)
+ temp = AD4130_FILTER_SELECT_MIN;
+ else if (temp > filter_config->fs_max)
+ temp = filter_config->fs_max;
+
+ *fs = temp;
+}
+
+static void ad4130_fs_to_freq(enum ad4130_filter_mode filter_mode,
+ unsigned int fs, int *val, int *val2)
+{
+ const struct ad4130_filter_config *filter_config =
+ &ad4130_filter_configs[filter_mode];
+ unsigned int dividend, divisor;
+ u64 temp;
+
+ dividend = (filter_config->fs_max - fs + AD4130_FILTER_SELECT_MIN) *
+ AD4130_MAX_ODR;
+ divisor = filter_config->fs_max * filter_config->odr_div;
+
+ temp = div_u64((u64)dividend * NANO, divisor);
+ *val = div_u64_rem(temp, NANO, val2);
+}
+
+static int ad4130_set_filter_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int val)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel = chan->scan_index;
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_setup_info *setup_info = &chan_info->setup;
+ enum ad4130_filter_mode old_filter_mode;
+ int freq_val, freq_val2;
+ unsigned int old_fs;
+ int ret = 0;
+
+ mutex_lock(&st->lock);
+ if (setup_info->filter_mode == val)
+ goto out;
+
+ old_fs = setup_info->fs;
+ old_filter_mode = setup_info->filter_mode;
+
+ /*
+ * When switching between filter modes, try to match the ODR as
+ * close as possible. To do this, convert the current FS into ODR
+ * using the old filter mode, then convert it back into FS using
+ * the new filter mode.
+ */
+ ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs,
+ &freq_val, &freq_val2);
+
+ ad4130_freq_to_fs(val, freq_val, freq_val2, &setup_info->fs);
+
+ setup_info->filter_mode = val;
+
+ ret = ad4130_write_channel_setup(st, channel, false);
+ if (ret) {
+ setup_info->fs = old_fs;
+ setup_info->filter_mode = old_filter_mode;
+ }
+
+ out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int ad4130_get_filter_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel = chan->scan_index;
+ struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
+ enum ad4130_filter_mode filter_mode;
+
+ mutex_lock(&st->lock);
+ filter_mode = setup_info->filter_mode;
+ mutex_unlock(&st->lock);
+
+ return filter_mode;
+}
+
+static const struct iio_enum ad4130_filter_mode_enum = {
+ .items = ad4130_filter_modes_str,
+ .num_items = ARRAY_SIZE(ad4130_filter_modes_str),
+ .set = ad4130_set_filter_mode,
+ .get = ad4130_get_filter_mode,
+};
+
+static const struct iio_chan_spec_ext_info ad4130_filter_mode_ext_info[] = {
+ IIO_ENUM("filter_mode", IIO_SEPARATE, &ad4130_filter_mode_enum),
+ IIO_ENUM_AVAILABLE("filter_mode", IIO_SHARED_BY_TYPE,
+ &ad4130_filter_mode_enum),
+ { }
+};
+
+static const struct iio_chan_spec ad4130_channel_template = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .differential = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .ext_info = ad4130_filter_mode_ext_info,
+ .scan_type = {
+ .sign = 'u',
+ .endianness = IIO_BE,
+ },
+};
+
+static int ad4130_set_channel_pga(struct ad4130_state *st, unsigned int channel,
+ int val, int val2)
+{
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_setup_info *setup_info = &chan_info->setup;
+ unsigned int pga, old_pga;
+ int ret = 0;
+
+ for (pga = 0; pga < AD4130_MAX_PGA; pga++)
+ if (val == st->scale_tbls[setup_info->ref_sel][pga][0] &&
+ val2 == st->scale_tbls[setup_info->ref_sel][pga][1])
+ break;
+
+ if (pga == AD4130_MAX_PGA)
+ return -EINVAL;
+
+ mutex_lock(&st->lock);
+ if (pga == setup_info->pga)
+ goto out;
+
+ old_pga = setup_info->pga;
+ setup_info->pga = pga;
+
+ ret = ad4130_write_channel_setup(st, channel, false);
+ if (ret)
+ setup_info->pga = old_pga;
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int ad4130_set_channel_freq(struct ad4130_state *st,
+ unsigned int channel, int val, int val2)
+{
+ struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+ struct ad4130_setup_info *setup_info = &chan_info->setup;
+ unsigned int fs, old_fs;
+ int ret = 0;
+
+ mutex_lock(&st->lock);
+ old_fs = setup_info->fs;
+
+ ad4130_freq_to_fs(setup_info->filter_mode, val, val2, &fs);
+
+ if (fs == setup_info->fs)
+ goto out;
+
+ setup_info->fs = fs;
+
+ ret = ad4130_write_channel_setup(st, channel, false);
+ if (ret)
+ setup_info->fs = old_fs;
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
+ int *val)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = ad4130_set_channel_enable(st, channel, true);
+ if (ret)
+ return ret;
+
+ reinit_completion(&st->completion);
+
+ ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
+ if (ret)
+ return ret;
+
+ ret = wait_for_completion_timeout(&st->completion,
+ msecs_to_jiffies(1000));
+ if (!ret)
+ return -ETIMEDOUT;
+
+ ret = ad4130_set_mode(st, AD4130_MODE_IDLE);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(st->regmap, AD4130_DATA_REG, val);
+ if (ret)
+ return ret;
+
+ ret = ad4130_set_channel_enable(st, channel, false);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+}
+
+static int ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
+ int *val)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&st->lock);
+ ret = _ad4130_read_sample(indio_dev, channel, val);
+ mutex_unlock(&st->lock);
+
+ iio_device_release_direct_mode(indio_dev);
+
+ return ret;
+}
+
+static int ad4130_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel = chan->scan_index;
+ struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ return ad4130_read_sample(indio_dev, channel, val);
+ case IIO_CHAN_INFO_SCALE:
+ mutex_lock(&st->lock);
+ *val = st->scale_tbls[setup_info->ref_sel][setup_info->pga][0];
+ *val2 = st->scale_tbls[setup_info->ref_sel][setup_info->pga][1];
+ mutex_unlock(&st->lock);
+
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = st->bipolar ? -BIT(chan->scan_type.realbits - 1) : 0;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ mutex_lock(&st->lock);
+ ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs,
+ val, val2);
+ mutex_unlock(&st->lock);
+
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4130_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel = chan->scan_index;
+ struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
+ const struct ad4130_filter_config *filter_config;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (int *)st->scale_tbls[setup_info->ref_sel];
+ *length = ARRAY_SIZE(st->scale_tbls[setup_info->ref_sel]) * 2;
+
+ *type = IIO_VAL_INT_PLUS_NANO;
+
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ mutex_lock(&st->lock);
+ filter_config = &ad4130_filter_configs[setup_info->filter_mode];
+ mutex_unlock(&st->lock);
+
+ *vals = (int *)filter_config->samp_freq_avail;
+ *length = filter_config->samp_freq_avail_len * 2;
+ *type = IIO_VAL_FRACTIONAL;
+
+ return filter_config->samp_freq_avail_type;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4130_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4130_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel = chan->scan_index;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ return ad4130_set_channel_pga(st, channel, val, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ad4130_set_channel_freq(st, channel, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4130_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static int ad4130_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int channel;
+ unsigned int val = 0;
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ for_each_set_bit(channel, scan_mask, indio_dev->num_channels) {
+ ret = ad4130_set_channel_enable(st, channel, true);
+ if (ret)
+ goto out;
+
+ val++;
+ }
+
+ st->num_enabled_channels = val;
+
+out:
+ mutex_unlock(&st->lock);
+
+ return 0;
+}
+
+static int ad4130_set_fifo_watermark(struct iio_dev *indio_dev, unsigned int val)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int eff;
+ int ret;
+
+ if (val > AD4130_FIFO_SIZE)
+ return -EINVAL;
+
+ eff = val * st->num_enabled_channels;
+ if (eff > AD4130_FIFO_SIZE)
+ /*
+ * Always set watermark to a multiple of the number of
+ * enabled channels to avoid making the FIFO unaligned.
+ */
+ eff = rounddown(AD4130_FIFO_SIZE, st->num_enabled_channels);
+
+ mutex_lock(&st->lock);
+
+ ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+ AD4130_FIFO_CONTROL_WM_MASK,
+ FIELD_PREP(AD4130_FIFO_CONTROL_WM_MASK,
+ ad4130_watermark_reg_val(eff)));
+ if (ret)
+ goto out;
+
+ st->effective_watermark = eff;
+ st->watermark = val;
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static const struct iio_info ad4130_info = {
+ .read_raw = ad4130_read_raw,
+ .read_avail = ad4130_read_avail,
+ .write_raw_get_fmt = ad4130_write_raw_get_fmt,
+ .write_raw = ad4130_write_raw,
+ .update_scan_mode = ad4130_update_scan_mode,
+ .hwfifo_set_watermark = ad4130_set_fifo_watermark,
+ .debugfs_reg_access = ad4130_reg_access,
+};
+
+static int ad4130_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ ret = ad4130_set_watermark_interrupt_en(st, true);
+ if (ret)
+ goto out;
+
+ ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger);
+ if (ret)
+ goto out;
+
+ ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM);
+ if (ret)
+ goto out;
+
+ ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int ad4130_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int i;
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ ret = ad4130_set_mode(st, AD4130_MODE_IDLE);
+ if (ret)
+ goto out;
+
+ ret = irq_set_irq_type(st->spi->irq, st->irq_trigger);
+ if (ret)
+ goto out;
+
+ ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED);
+ if (ret)
+ goto out;
+
+ ret = ad4130_set_watermark_interrupt_en(st, false);
+ if (ret)
+ goto out;
+
+ /*
+ * update_scan_mode() is not called in the disable path, disable all
+ * channels here.
+ */
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ ret = ad4130_set_channel_enable(st, i, false);
+ if (ret)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static const struct iio_buffer_setup_ops ad4130_buffer_ops = {
+ .postenable = ad4130_buffer_postenable,
+ .predisable = ad4130_buffer_predisable,
+};
+
+static ssize_t hwfifo_watermark_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ad4130_state *st = iio_priv(dev_to_iio_dev(dev));
+ unsigned int val;
+
+ mutex_lock(&st->lock);
+ val = st->watermark;
+ mutex_unlock(&st->lock);
+
+ return sysfs_emit(buf, "%d\n", val);
+}
+
+static ssize_t hwfifo_enabled_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ad4130_state *st = iio_priv(dev_to_iio_dev(dev));
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->regmap, AD4130_FIFO_CONTROL_REG, &val);
+ if (ret)
+ return ret;
+
+ val = FIELD_GET(AD4130_FIFO_CONTROL_MODE_MASK, val);
+
+ return sysfs_emit(buf, "%d\n", val != AD4130_FIFO_MODE_DISABLED);
+}
+
+static ssize_t hwfifo_watermark_min_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n", "1");
+}
+
+static ssize_t hwfifo_watermark_max_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n", __stringify(AD4130_FIFO_SIZE));
+}
+
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_enabled, 0);
+
+static const struct iio_dev_attr *ad4130_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_watermark_min,
+ &iio_dev_attr_hwfifo_watermark_max,
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
+ NULL
+};
+
+static int _ad4130_find_table_index(const unsigned int *tbl, size_t len,
+ unsigned int val)
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ if (tbl[i] == val)
+ return i;
+
+ return -EINVAL;
+}
+
+#define ad4130_find_table_index(table, val) \
+ _ad4130_find_table_index(table, ARRAY_SIZE(table), val)
+
+static int ad4130_get_ref_voltage(struct ad4130_state *st,
+ enum ad4130_ref_sel ref_sel)
+{
+ switch (ref_sel) {
+ case AD4130_REF_REFIN1:
+ return regulator_get_voltage(st->regulators[2].consumer);
+ case AD4130_REF_REFIN2:
+ return regulator_get_voltage(st->regulators[3].consumer);
+ case AD4130_REF_AVDD_AVSS:
+ return regulator_get_voltage(st->regulators[0].consumer);
+ case AD4130_REF_REFOUT_AVSS:
+ return st->int_ref_uv;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4130_parse_fw_setup(struct ad4130_state *st,
+ struct fwnode_handle *child,
+ struct ad4130_setup_info *setup_info)
+{
+ struct device *dev = &st->spi->dev;
+ u32 tmp;
+ int ret;
+
+ tmp = 0;
+ fwnode_property_read_u32(child, "adi,excitation-current-0-nanoamp", &tmp);
+ ret = ad4130_find_table_index(ad4130_iout_current_na_tbl, tmp);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Invalid excitation current %unA\n", tmp);
+ setup_info->iout0_val = ret;
+
+ tmp = 0;
+ fwnode_property_read_u32(child, "adi,excitation-current-1-nanoamp", &tmp);
+ ret = ad4130_find_table_index(ad4130_iout_current_na_tbl, tmp);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Invalid excitation current %unA\n", tmp);
+ setup_info->iout1_val = ret;
+
+ tmp = 0;
+ fwnode_property_read_u32(child, "adi,burnout-current-nanoamp", &tmp);
+ ret = ad4130_find_table_index(ad4130_burnout_current_na_tbl, tmp);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Invalid burnout current %unA\n", tmp);
+ setup_info->burnout = ret;
+
+ setup_info->ref_bufp = fwnode_property_read_bool(child, "adi,buffered-positive");
+ setup_info->ref_bufm = fwnode_property_read_bool(child, "adi,buffered-negative");
+
+ setup_info->ref_sel = AD4130_REF_REFIN1;
+ fwnode_property_read_u32(child, "adi,reference-select",
+ &setup_info->ref_sel);
+ if (setup_info->ref_sel >= AD4130_REF_SEL_MAX)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid reference selected %u\n",
+ setup_info->ref_sel);
+
+ if (setup_info->ref_sel == AD4130_REF_REFOUT_AVSS)
+ st->int_ref_en = true;
+
+ ret = ad4130_get_ref_voltage(st, setup_info->ref_sel);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Cannot use reference %u\n",
+ setup_info->ref_sel);
+
+ return 0;
+}
+
+static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin)
+{
+ struct device *dev = &st->spi->dev;
+
+ if (pin >= AD4130_MAX_DIFF_INPUTS)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid differential channel %u\n", pin);
+
+ if (pin >= AD4130_MAX_ANALOG_PINS)
+ return 0;
+
+ if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL)
+ return dev_err_probe(dev, -EINVAL,
+ "Pin %u already used with fn %u\n", pin,
+ st->pins_fn[pin]);
+
+ st->pins_fn[pin] |= AD4130_PIN_FN_DIFF;
+
+ return 0;
+}
+
+static int ad4130_validate_diff_channels(struct ad4130_state *st,
+ u32 *pins, unsigned int len)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < len; i++) {
+ ret = ad4130_validate_diff_channel(st, pins[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad4130_validate_excitation_pin(struct ad4130_state *st, u32 pin)
+{
+ struct device *dev = &st->spi->dev;
+
+ if (pin >= AD4130_MAX_ANALOG_PINS)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid excitation pin %u\n", pin);
+
+ if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL)
+ return dev_err_probe(dev, -EINVAL,
+ "Pin %u already used with fn %u\n", pin,
+ st->pins_fn[pin]);
+
+ st->pins_fn[pin] |= AD4130_PIN_FN_EXCITATION;
+
+ return 0;
+}
+
+static int ad4130_validate_vbias_pin(struct ad4130_state *st, u32 pin)
+{
+ struct device *dev = &st->spi->dev;
+
+ if (pin >= AD4130_MAX_ANALOG_PINS)
+ return dev_err_probe(dev, -EINVAL, "Invalid vbias pin %u\n",
+ pin);
+
+ if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL)
+ return dev_err_probe(dev, -EINVAL,
+ "Pin %u already used with fn %u\n", pin,
+ st->pins_fn[pin]);
+
+ st->pins_fn[pin] |= AD4130_PIN_FN_VBIAS;
+
+ return 0;
+}
+
+static int ad4130_validate_vbias_pins(struct ad4130_state *st,
+ u32 *pins, unsigned int len)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < st->num_vbias_pins; i++) {
+ ret = ad4130_validate_vbias_pin(st, pins[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad4130_parse_fw_channel(struct iio_dev *indio_dev,
+ struct fwnode_handle *child)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int resolution = ad4130_resolution(st);
+ unsigned int index = indio_dev->num_channels++;
+ struct device *dev = &st->spi->dev;
+ struct ad4130_chan_info *chan_info;
+ struct iio_chan_spec *chan;
+ u32 pins[2];
+ int ret;
+
+ if (index >= AD4130_MAX_CHANNELS)
+ return dev_err_probe(dev, -EINVAL, "Too many channels\n");
+
+ chan = &st->chans[index];
+ chan_info = &st->chans_info[index];
+
+ *chan = ad4130_channel_template;
+ chan->scan_type.realbits = resolution;
+ chan->scan_type.storagebits = resolution;
+ chan->scan_index = index;
+
+ chan_info->slot = AD4130_INVALID_SLOT;
+ chan_info->setup.fs = AD4130_FILTER_SELECT_MIN;
+ chan_info->initialized = true;
+
+ ret = fwnode_property_read_u32_array(child, "diff-channels", pins,
+ ARRAY_SIZE(pins));
+ if (ret)
+ return ret;
+
+ ret = ad4130_validate_diff_channels(st, pins, ARRAY_SIZE(pins));
+ if (ret)
+ return ret;
+
+ chan->channel = pins[0];
+ chan->channel2 = pins[1];
+
+ ret = ad4130_parse_fw_setup(st, child, &chan_info->setup);
+ if (ret)
+ return ret;
+
+ fwnode_property_read_u32(child, "adi,excitation-pin-0",
+ &chan_info->iout0);
+ if (chan_info->setup.iout0_val != AD4130_IOUT_OFF) {
+ ret = ad4130_validate_excitation_pin(st, chan_info->iout0);
+ if (ret)
+ return ret;
+ }
+
+ fwnode_property_read_u32(child, "adi,excitation-pin-1",
+ &chan_info->iout1);
+ if (chan_info->setup.iout1_val != AD4130_IOUT_OFF) {
+ ret = ad4130_validate_excitation_pin(st, chan_info->iout1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad4130_parse_fw_children(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ struct fwnode_handle *child;
+ int ret;
+
+ indio_dev->channels = st->chans;
+
+ device_for_each_child_node(dev, child) {
+ ret = ad4130_parse_fw_channel(indio_dev, child);
+ if (ret) {
+ fwnode_handle_put(child);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ad4310_parse_fw(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ u32 ext_clk_freq = AD4130_MCLK_FREQ_76_8KHZ;
+ unsigned int i;
+ int avdd_uv;
+ int irq;
+ int ret;
+
+ st->mclk = devm_clk_get_optional(dev, "mclk");
+ if (IS_ERR(st->mclk))
+ return dev_err_probe(dev, PTR_ERR(st->mclk),
+ "Failed to get mclk\n");
+
+ st->int_pin_sel = AD4130_INT_PIN_INT;
+
+ for (i = 0; i < ARRAY_SIZE(ad4130_int_pin_names); i++) {
+ irq = fwnode_irq_get_byname(dev_fwnode(dev),
+ ad4130_int_pin_names[i]);
+ if (irq > 0) {
+ st->int_pin_sel = i;
+ break;
+ }
+ }
+
+ if (st->int_pin_sel == AD4130_INT_PIN_DOUT)
+ return dev_err_probe(dev, -EINVAL,
+ "Cannot use DOUT as interrupt pin\n");
+
+ if (st->int_pin_sel == AD4130_INT_PIN_P2)
+ st->pins_fn[AD4130_AIN3_P2] = AD4130_PIN_FN_SPECIAL;
+
+ device_property_read_u32(dev, "adi,ext-clk-freq-hz", &ext_clk_freq);
+ if (ext_clk_freq != AD4130_MCLK_FREQ_153_6KHZ &&
+ ext_clk_freq != AD4130_MCLK_FREQ_76_8KHZ)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid external clock frequency %u\n",
+ ext_clk_freq);
+
+ if (st->mclk && ext_clk_freq == AD4130_MCLK_FREQ_153_6KHZ)
+ st->mclk_sel = AD4130_MCLK_153_6KHZ_EXT;
+ else if (st->mclk)
+ st->mclk_sel = AD4130_MCLK_76_8KHZ_EXT;
+ else
+ st->mclk_sel = AD4130_MCLK_76_8KHZ;
+
+ if (st->int_pin_sel == AD4130_INT_PIN_CLK &&
+ st->mclk_sel != AD4130_MCLK_76_8KHZ)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid clock %u for interrupt pin %u\n",
+ st->mclk_sel, st->int_pin_sel);
+
+ st->int_ref_uv = AD4130_INT_REF_2_5V;
+
+ /*
+ * When the AVDD supply is set to below 2.5V the internal reference of
+ * 1.25V should be selected.
+ * See datasheet page 37, section ADC REFERENCE.
+ */
+ avdd_uv = regulator_get_voltage(st->regulators[0].consumer);
+ if (avdd_uv > 0 && avdd_uv < AD4130_INT_REF_2_5V)
+ st->int_ref_uv = AD4130_INT_REF_1_25V;
+
+ st->bipolar = device_property_read_bool(dev, "adi,bipolar");
+
+ ret = device_property_count_u32(dev, "adi,vbias-pins");
+ if (ret > 0) {
+ if (ret > AD4130_MAX_ANALOG_PINS)
+ return dev_err_probe(dev, -EINVAL,
+ "Too many vbias pins %u\n", ret);
+
+ st->num_vbias_pins = ret;
+
+ ret = device_property_read_u32_array(dev, "adi,vbias-pins",
+ st->vbias_pins,
+ st->num_vbias_pins);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to read vbias pins\n");
+
+ ret = ad4130_validate_vbias_pins(st, st->vbias_pins,
+ st->num_vbias_pins);
+ if (ret)
+ return ret;
+ }
+
+ ret = ad4130_parse_fw_children(indio_dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void ad4130_fill_scale_tbls(struct ad4130_state *st)
+{
+ unsigned int pow = ad4130_resolution(st) - st->bipolar;
+ unsigned int i, j;
+
+ for (i = 0; i < AD4130_REF_SEL_MAX; i++) {
+ int ret;
+ u64 nv;
+
+ ret = ad4130_get_ref_voltage(st, i);
+ if (ret < 0)
+ continue;
+
+ nv = (u64)ret * NANO;
+
+ for (j = 0; j < AD4130_MAX_PGA; j++)
+ st->scale_tbls[i][j][1] = div_u64(nv >> (pow + j), MILLI);
+ }
+}
+
+static void ad4130_clk_disable_unprepare(void *clk)
+{
+ clk_disable_unprepare(clk);
+}
+
+static int ad4130_set_mclk_sel(struct ad4130_state *st,
+ enum ad4130_mclk_sel mclk_sel)
+{
+ return regmap_update_bits(st->regmap, AD4130_ADC_CONTROL_REG,
+ AD4130_ADC_CONTROL_MCLK_SEL_MASK,
+ FIELD_PREP(AD4130_ADC_CONTROL_MCLK_SEL_MASK,
+ mclk_sel));
+}
+
+static unsigned long ad4130_int_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return AD4130_MCLK_FREQ_76_8KHZ;
+}
+
+static int ad4130_int_clk_is_enabled(struct clk_hw *hw)
+{
+ struct ad4130_state *st = container_of(hw, struct ad4130_state, int_clk_hw);
+
+ return st->mclk_sel == AD4130_MCLK_76_8KHZ_OUT;
+}
+
+static int ad4130_int_clk_prepare(struct clk_hw *hw)
+{
+ struct ad4130_state *st = container_of(hw, struct ad4130_state, int_clk_hw);
+ int ret;
+
+ ret = ad4130_set_mclk_sel(st, AD4130_MCLK_76_8KHZ_OUT);
+ if (ret)
+ return ret;
+
+ st->mclk_sel = AD4130_MCLK_76_8KHZ_OUT;
+
+ return 0;
+}
+
+static void ad4130_int_clk_unprepare(struct clk_hw *hw)
+{
+ struct ad4130_state *st = container_of(hw, struct ad4130_state, int_clk_hw);
+ int ret;
+
+ ret = ad4130_set_mclk_sel(st, AD4130_MCLK_76_8KHZ);
+ if (ret)
+ return;
+
+ st->mclk_sel = AD4130_MCLK_76_8KHZ;
+}
+
+static const struct clk_ops ad4130_int_clk_ops = {
+ .recalc_rate = ad4130_int_clk_recalc_rate,
+ .is_enabled = ad4130_int_clk_is_enabled,
+ .prepare = ad4130_int_clk_prepare,
+ .unprepare = ad4130_int_clk_unprepare,
+};
+
+static int ad4130_setup_int_clk(struct ad4130_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ struct device_node *of_node = dev_of_node(dev);
+ struct clk_init_data init;
+ const char *clk_name;
+ struct clk *clk;
+
+ if (st->int_pin_sel == AD4130_INT_PIN_CLK ||
+ st->mclk_sel != AD4130_MCLK_76_8KHZ)
+ return 0;
+
+ if (!of_node)
+ return 0;
+
+ clk_name = of_node->name;
+ of_property_read_string(of_node, "clock-output-names", &clk_name);
+
+ init.name = clk_name;
+ init.ops = &ad4130_int_clk_ops;
+
+ st->int_clk_hw.init = &init;
+ clk = devm_clk_register(dev, &st->int_clk_hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ return of_clk_add_provider(of_node, of_clk_src_simple_get, clk);
+}
+
+static int ad4130_setup(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ unsigned int int_ref_val;
+ unsigned long rate = AD4130_MCLK_FREQ_76_8KHZ;
+ unsigned int val;
+ unsigned int i;
+ int ret;
+
+ if (st->mclk_sel == AD4130_MCLK_153_6KHZ_EXT)
+ rate = AD4130_MCLK_FREQ_153_6KHZ;
+
+ ret = clk_set_rate(st->mclk, rate);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(st->mclk);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, ad4130_clk_disable_unprepare,
+ st->mclk);
+ if (ret)
+ return ret;
+
+ if (st->int_ref_uv == AD4130_INT_REF_2_5V)
+ int_ref_val = AD4130_INT_REF_VAL_2_5V;
+ else
+ int_ref_val = AD4130_INT_REF_VAL_1_25V;
+
+ /* Switch to SPI 4-wire mode. */
+ val = FIELD_PREP(AD4130_ADC_CONTROL_CSB_EN_MASK, 1);
+ val |= FIELD_PREP(AD4130_ADC_CONTROL_BIPOLAR_MASK, st->bipolar);
+ val |= FIELD_PREP(AD4130_ADC_CONTROL_INT_REF_EN_MASK, st->int_ref_en);
+ val |= FIELD_PREP(AD4130_ADC_CONTROL_MODE_MASK, AD4130_MODE_IDLE);
+ val |= FIELD_PREP(AD4130_ADC_CONTROL_MCLK_SEL_MASK, st->mclk_sel);
+ val |= FIELD_PREP(AD4130_ADC_CONTROL_INT_REF_VAL_MASK, int_ref_val);
+
+ ret = regmap_write(st->regmap, AD4130_ADC_CONTROL_REG, val);
+ if (ret)
+ return ret;
+
+ /*
+ * Configure all GPIOs for output. If configured, the interrupt function
+ * of P2 takes priority over the GPIO out function.
+ */
+ val = AD4130_IO_CONTROL_GPIO_CTRL_MASK;
+ val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel);
+
+ ret = regmap_write(st->regmap, AD4130_IO_CONTROL_REG, val);
+ if (ret)
+ return ret;
+
+ val = 0;
+ for (i = 0; i < st->num_vbias_pins; i++)
+ val |= BIT(st->vbias_pins[i]);
+
+ ret = regmap_write(st->regmap, AD4130_VBIAS_REG, val);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+ AD4130_FIFO_CONTROL_HEADER_MASK, 0);
+ if (ret)
+ return ret;
+
+ /* FIFO watermark interrupt starts out as enabled, disable it. */
+ ret = ad4130_set_watermark_interrupt_en(st, false);
+ if (ret)
+ return ret;
+
+ /* Setup channels. */
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ struct ad4130_chan_info *chan_info = &st->chans_info[i];
+ struct iio_chan_spec *chan = &st->chans[i];
+ unsigned int val;
+
+ val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK, chan->channel) |
+ FIELD_PREP(AD4130_CHANNEL_AINM_MASK, chan->channel2) |
+ FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK, chan_info->iout0) |
+ FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK, chan_info->iout1);
+
+ ret = regmap_write(st->regmap, AD4130_CHANNEL_X_REG(i), val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad4130_soft_reset(struct ad4130_state *st)
+{
+ int ret;
+
+ ret = spi_write(st->spi, st->reset_buf, sizeof(st->reset_buf));
+ if (ret)
+ return ret;
+
+ fsleep(AD4130_RESET_SLEEP_US);
+
+ return 0;
+}
+
+static void ad4130_disable_regulators(void *data)
+{
+ struct ad4130_state *st = data;
+
+ regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators);
+}
+
+static int ad4130_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct ad4130_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ memset(st->reset_buf, 0xff, sizeof(st->reset_buf));
+ init_completion(&st->completion);
+ mutex_init(&st->lock);
+ st->spi = spi;
+
+ /*
+ * Xfer: [ XFR1 ] [ XFR2 ]
+ * Master: 0x7D N ......................
+ * Slave: ...... DATA1 DATA2 ... DATAN
+ */
+ st->fifo_tx_buf[0] = AD4130_COMMS_READ_MASK | AD4130_FIFO_DATA_REG;
+ st->fifo_xfer[0].tx_buf = st->fifo_tx_buf;
+ st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf);
+ st->fifo_xfer[1].rx_buf = st->fifo_rx_buf;
+ spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer,
+ ARRAY_SIZE(st->fifo_xfer));
+
+ indio_dev->name = AD4130_NAME;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &ad4130_info;
+
+ st->regmap = devm_regmap_init(dev, NULL, st, &ad4130_regmap_config);
+ if (IS_ERR(st->regmap))
+ return PTR_ERR(st->regmap);
+
+ st->regulators[0].supply = "avdd";
+ st->regulators[1].supply = "iovdd";
+ st->regulators[2].supply = "refin1";
+ st->regulators[3].supply = "refin2";
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(st->regulators),
+ st->regulators);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(st->regulators), st->regulators);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable regulators\n");
+
+ ret = devm_add_action_or_reset(dev, ad4130_disable_regulators, st);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to add regulators disable action\n");
+
+ ret = ad4130_soft_reset(st);
+ if (ret)
+ return ret;
+
+ ret = ad4310_parse_fw(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ad4130_setup(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ad4130_setup_int_clk(st);
+ if (ret)
+ return ret;
+
+ ad4130_fill_scale_tbls(st);
+
+ st->gc.owner = THIS_MODULE;
+ st->gc.label = AD4130_NAME;
+ st->gc.base = -1;
+ st->gc.ngpio = AD4130_MAX_GPIOS;
+ st->gc.parent = dev;
+ st->gc.can_sleep = true;
+ st->gc.init_valid_mask = ad4130_gpio_init_valid_mask;
+ st->gc.get_direction = ad4130_gpio_get_direction;
+ st->gc.set = ad4130_gpio_set;
+
+ ret = devm_gpiochip_add_data(dev, &st->gc, st);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
+ &ad4130_buffer_ops,
+ ad4130_fifo_attributes);
+ if (ret)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, spi->irq, NULL,
+ ad4130_irq_handler, IRQF_ONESHOT,
+ indio_dev->name, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request irq\n");
+
+ /*
+ * When the chip enters FIFO mode, IRQ polarity is inverted.
+ * When the chip exits FIFO mode, IRQ polarity returns to normal.
+ * See datasheet pages: 65, FIFO Watermark Interrupt section,
+ * and 71, Bit Descriptions for STATUS Register, RDYB.
+ * Cache the normal and inverted IRQ triggers to set them when
+ * entering and exiting FIFO mode.
+ */
+ st->irq_trigger = irq_get_trigger_type(spi->irq);
+ if (st->irq_trigger & IRQF_TRIGGER_RISING)
+ st->inv_irq_trigger = IRQF_TRIGGER_FALLING;
+ else if (st->irq_trigger & IRQF_TRIGGER_FALLING)
+ st->inv_irq_trigger = IRQF_TRIGGER_RISING;
+ else
+ return dev_err_probe(dev, -EINVAL, "Invalid irq flags: %u\n",
+ st->irq_trigger);
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id ad4130_of_match[] = {
+ {
+ .compatible = "adi,ad4130",
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad4130_of_match);
+
+static struct spi_driver ad4130_driver = {
+ .driver = {
+ .name = AD4130_NAME,
+ .of_match_table = ad4130_of_match,
+ },
+ .probe = ad4130_probe,
+};
+module_spi_driver(ad4130_driver);
+
+MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD4130 SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c
index 47f5763023a4..7d6709da1005 100644
--- a/drivers/iio/adc/ad7091r5.c
+++ b/drivers/iio/adc/ad7091r5.c
@@ -69,9 +69,9 @@ static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = {
.vref_mV = 2500,
};
-static int ad7091r5_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int ad7091r5_i2c_probe(struct i2c_client *i2c)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
const struct ad7091r_chip_info *chip_info;
struct regmap *map = devm_regmap_init_i2c(i2c, &ad7091r_regmap_config);
@@ -103,7 +103,7 @@ static struct i2c_driver ad7091r5_driver = {
.name = "ad7091r5",
.of_match_table = ad7091r5_dt_ids,
},
- .probe = ad7091r5_i2c_probe,
+ .probe_new = ad7091r5_i2c_probe,
.id_table = ad7091r5_i2c_ids,
};
module_i2c_driver(ad7091r5_driver);
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index 4088786e1026..050a2fbf5c49 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -945,6 +945,8 @@ static int ad7124_probe(struct spi_device *spi)
info = of_device_get_match_data(&spi->dev);
if (!info)
+ info = (void *)spi_get_device_id(spi)->driver_data;
+ if (!info)
return -ENODEV;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -1021,12 +1023,20 @@ static const struct of_device_id ad7124_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ad7124_of_match);
+static const struct spi_device_id ad71124_ids[] = {
+ { "ad7124-4", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_4] },
+ { "ad7124-8", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_8] },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad71124_ids);
+
static struct spi_driver ad71124_driver = {
.driver = {
.name = "ad7124",
.of_match_table = ad7124_of_match,
},
.probe = ad7124_probe,
+ .id_table = ad71124_ids,
};
module_spi_driver(ad71124_driver);
diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c
index d71977be7d22..55a6ab591016 100644
--- a/drivers/iio/adc/ad7192.c
+++ b/drivers/iio/adc/ad7192.c
@@ -177,7 +177,6 @@ struct ad7192_chip_info {
struct ad7192_state {
const struct ad7192_chip_info *chip_info;
struct regulator *avdd;
- struct regulator *dvdd;
struct clk *mclk;
u16 int_vref_mv;
u32 fclk;
@@ -1015,19 +1014,9 @@ static int ad7192_probe(struct spi_device *spi)
if (ret)
return ret;
- st->dvdd = devm_regulator_get(&spi->dev, "dvdd");
- if (IS_ERR(st->dvdd))
- return PTR_ERR(st->dvdd);
-
- ret = regulator_enable(st->dvdd);
- if (ret) {
- dev_err(&spi->dev, "Failed to enable specified DVdd supply\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->dvdd);
+ ret = devm_regulator_get_enable(&spi->dev, "dvdd");
if (ret)
- return ret;
+ return dev_err_probe(&spi->dev, ret, "Failed to enable specified DVdd supply\n");
ret = regulator_get_voltage(st->avdd);
if (ret < 0) {
@@ -1037,6 +1026,8 @@ static int ad7192_probe(struct spi_device *spi)
st->int_vref_mv = ret / 1000;
st->chip_info = of_device_get_match_data(&spi->dev);
+ if (!st->chip_info)
+ st->chip_info = (void *)spi_get_device_id(spi)->driver_data;
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1098,12 +1089,22 @@ static const struct of_device_id ad7192_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ad7192_of_match);
+static const struct spi_device_id ad7192_ids[] = {
+ { "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] },
+ { "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] },
+ { "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] },
+ { "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad7192_ids);
+
static struct spi_driver ad7192_driver = {
.driver = {
.name = "ad7192",
.of_match_table = ad7192_of_match,
},
.probe = ad7192_probe,
+ .id_table = ad7192_ids,
};
module_spi_driver(ad7192_driver);
diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c
index e9129dac762f..3dd0105f63d7 100644
--- a/drivers/iio/adc/ad7291.c
+++ b/drivers/iio/adc/ad7291.c
@@ -465,9 +465,9 @@ static void ad7291_reg_disable(void *reg)
regulator_disable(reg);
}
-static int ad7291_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ad7291_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ad7291_chip_info *chip;
struct iio_dev *indio_dev;
int ret;
@@ -553,7 +553,7 @@ static struct i2c_driver ad7291_driver = {
.name = KBUILD_MODNAME,
.of_match_table = ad7291_of_match,
},
- .probe = ad7291_probe,
+ .probe_new = ad7291_probe,
.id_table = ad7291_id,
};
module_i2c_driver(ad7291_driver);
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 94776f696290..80aebed47d1f 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -368,16 +368,7 @@ static int ad7476_probe(struct spi_device *spi)
}
if (st->chip_info->has_vdrive) {
- reg = devm_regulator_get(&spi->dev, "vdrive");
- if (IS_ERR(reg))
- return PTR_ERR(reg);
-
- ret = regulator_enable(reg);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable,
- reg);
+ ret = devm_regulator_get_enable(&spi->dev, "vdrive");
if (ret)
return ret;
}
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index ba24f99523e0..dd6b603f65ea 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -557,13 +557,6 @@ static const struct iio_trigger_ops ad7606_trigger_ops = {
.validate_device = iio_trigger_validate_own_device,
};
-static void ad7606_regulator_disable(void *data)
-{
- struct ad7606_state *st = data;
-
- regulator_disable(st->reg);
-}
-
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
const char *name, unsigned int id,
const struct ad7606_bus_ops *bops)
@@ -589,19 +582,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
st->scale_avail = ad7606_scale_avail;
st->num_scales = ARRAY_SIZE(ad7606_scale_avail);
- st->reg = devm_regulator_get(dev, "avcc");
- if (IS_ERR(st->reg))
- return PTR_ERR(st->reg);
-
- ret = regulator_enable(st->reg);
- if (ret) {
- dev_err(dev, "Failed to enable specified AVcc supply\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(dev, ad7606_regulator_disable, st);
+ ret = devm_regulator_get_enable(dev, "avcc");
if (ret)
- return ret;
+ return dev_err_probe(dev, ret,
+ "Failed to enable specified AVcc supply\n");
st->chip_info = &ad7606_chip_info_tbl[id];
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index 2dc4f599f9df..0c6a88cc4695 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -62,7 +62,6 @@ struct ad7606_chip_info {
* struct ad7606_state - driver instance specific data
* @dev pointer to kernel device
* @chip_info entry in the table of chips that describes this device
- * @reg regulator info for the power supply of the device
* @bops bus operations (SPI or parallel)
* @range voltage range selection, selects which scale to apply
* @oversampling oversampling selection
@@ -92,7 +91,6 @@ struct ad7606_chip_info {
struct ad7606_state {
struct device *dev;
const struct ad7606_chip_info *chip_info;
- struct regulator *reg;
const struct ad7606_bus_ops *bops;
unsigned int range[16];
unsigned int oversampling;
diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c
index b912b4df9b56..d8408052262e 100644
--- a/drivers/iio/adc/ad7606_par.c
+++ b/drivers/iio/adc/ad7606_par.c
@@ -57,8 +57,7 @@ static int ad7606_par_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- addr = devm_ioremap_resource(&pdev->dev, res);
+ addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(addr))
return PTR_ERR(addr);
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 6dbe9d5e08a2..8f0a3a35e727 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -28,6 +28,7 @@
#include <linux/types.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
@@ -125,6 +126,8 @@ struct ad799x_state {
const struct ad799x_chip_config *chip_config;
struct regulator *reg;
struct regulator *vref;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
unsigned id;
u16 config;
@@ -290,7 +293,9 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
+ mutex_lock(&st->lock);
ret = ad799x_scan_direct(st, chan->scan_index);
+ mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
@@ -351,7 +356,8 @@ static ssize_t ad799x_write_frequency(struct device *dev,
if (ret)
return ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
+
ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
if (ret < 0)
goto error_ret_mutex;
@@ -373,7 +379,7 @@ static ssize_t ad799x_write_frequency(struct device *dev,
ret = len;
error_ret_mutex:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
}
@@ -407,6 +413,8 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
if (ret)
return ret;
+ mutex_lock(&st->lock);
+
if (state)
st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT;
else
@@ -418,6 +426,7 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
st->config &= ~AD7998_ALERT_EN;
ret = ad799x_write_config(st, st->config);
+ mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
return ret;
}
@@ -454,11 +463,9 @@ static int ad799x_write_event_value(struct iio_dev *indio_dev,
if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
return -EINVAL;
- mutex_lock(&indio_dev->mlock);
ret = i2c_smbus_write_word_swapped(st->client,
ad799x_threshold_reg(chan, dir, info),
val << chan->scan_type.shift);
- mutex_unlock(&indio_dev->mlock);
return ret;
}
@@ -473,10 +480,8 @@ static int ad799x_read_event_value(struct iio_dev *indio_dev,
int ret;
struct ad799x_state *st = iio_priv(indio_dev);
- mutex_lock(&indio_dev->mlock);
ret = i2c_smbus_read_word_swapped(st->client,
ad799x_threshold_reg(chan, dir, info));
- mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = (ret >> chan->scan_type.shift) &
@@ -770,9 +775,9 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
},
};
-static int ad799x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ad799x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
int extra_config = 0;
struct ad799x_state *st;
@@ -863,6 +868,9 @@ static int ad799x_probe(struct i2c_client *client,
if (ret)
goto error_cleanup_ring;
}
+
+ mutex_init(&st->lock);
+
ret = iio_device_register(indio_dev);
if (ret)
goto error_cleanup_ring;
@@ -960,7 +968,7 @@ static struct i2c_driver ad799x_driver = {
.name = "ad799x",
.pm = pm_sleep_ptr(&ad799x_pm_ops),
},
- .probe = ad799x_probe,
+ .probe_new = ad799x_probe,
.remove = ad799x_remove,
.id_table = ad799x_id,
};
diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c
index 7534572f7475..0621cf59d614 100644
--- a/drivers/iio/adc/ad9467.c
+++ b/drivers/iio/adc/ad9467.c
@@ -388,6 +388,8 @@ static int ad9467_probe(struct spi_device *spi)
info = of_device_get_match_data(&spi->dev);
if (!info)
+ info = (void *)spi_get_device_id(spi)->driver_data;
+ if (!info)
return -ENODEV;
conv = devm_adi_axi_adc_conv_register(&spi->dev, sizeof(*st));
@@ -447,12 +449,21 @@ static const struct of_device_id ad9467_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ad9467_of_match);
+static const struct spi_device_id ad9467_ids[] = {
+ { "ad9265", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9265] },
+ { "ad9434", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9434] },
+ { "ad9467", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9467] },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad9467_ids);
+
static struct spi_driver ad9467_driver = {
.driver = {
.name = "ad9467",
.of_match_table = ad9467_of_match,
},
.probe = ad9467_probe,
+ .id_table = ad9467_ids,
};
module_spi_driver(ad9467_driver);
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 261a9a6b45e1..d8570f620785 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -281,10 +281,10 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
unsigned int data_reg;
int ret = 0;
- if (iio_buffer_enabled(indio_dev))
- return -EBUSY;
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
- mutex_lock(&indio_dev->mlock);
ad_sigma_delta_set_channel(sigma_delta, chan->address);
spi_bus_lock(sigma_delta->spi->master);
@@ -323,7 +323,7 @@ out:
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master);
- mutex_unlock(&indio_dev->mlock);
+ iio_device_release_direct_mode(indio_dev);
if (ret)
return ret;
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index 870f4cb60923..ed4f8501bda8 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -2193,32 +2193,19 @@ static ssize_t at91_adc_get_watermark(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%d\n", st->dma_st.watermark);
}
-static ssize_t hwfifo_watermark_min_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sysfs_emit(buf, "%s\n", "2");
-}
-
-static ssize_t hwfifo_watermark_max_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sysfs_emit(buf, "%s\n", AT91_HWFIFO_MAX_SIZE_STR);
-}
-
static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
at91_adc_get_fifo_state, NULL, 0);
static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
at91_adc_get_watermark, NULL, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
-
-static const struct attribute *at91_adc_fifo_attributes[] = {
- &iio_dev_attr_hwfifo_watermark_min.dev_attr.attr,
- &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
- &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
- &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "2");
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max, AT91_HWFIFO_MAX_SIZE_STR);
+
+static const struct iio_dev_attr *at91_adc_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_watermark_min,
+ &iio_dev_attr_hwfifo_watermark_max,
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
NULL,
};
@@ -2235,7 +2222,7 @@ static int at91_adc_buffer_and_trigger_init(struct device *dev,
struct iio_dev *indio)
{
struct at91_adc_state *st = iio_priv(indio);
- const struct attribute **fifo_attrs;
+ const struct iio_dev_attr **fifo_attrs;
int ret;
if (st->selected_trig->hw_trig)
diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c
index 580361bd9849..49fff1cabd0d 100644
--- a/drivers/iio/adc/axp288_adc.c
+++ b/drivers/iio/adc/axp288_adc.c
@@ -9,6 +9,7 @@
#include <linux/dmi.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/regmap.h>
@@ -50,6 +51,8 @@ enum axp288_adc_id {
struct axp288_adc_info {
int irq;
struct regmap *regmap;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
bool ts_enabled;
};
@@ -161,7 +164,7 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev,
int ret;
struct axp288_adc_info *info = iio_priv(indio_dev);
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&info->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (axp288_adc_set_ts(info, AXP288_ADC_TS_CURRENT_ON_ONDEMAND,
@@ -178,7 +181,7 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev,
default:
ret = -EINVAL;
}
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return ret;
}
@@ -289,6 +292,8 @@ static int axp288_adc_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
+ mutex_init(&info->lock);
+
return devm_iio_device_register(&pdev->dev, indio_dev);
}
diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c
index e16ac935693b..2cde4b44fc6e 100644
--- a/drivers/iio/adc/cc10001_adc.c
+++ b/drivers/iio/adc/cc10001_adc.c
@@ -305,16 +305,27 @@ static int cc10001_adc_channel_init(struct iio_dev *indio_dev,
return 0;
}
+static void cc10001_reg_disable(void *priv)
+{
+ regulator_disable(priv);
+}
+
+static void cc10001_pd_cb(void *priv)
+{
+ cc10001_adc_power_down(priv);
+}
+
static int cc10001_adc_probe(struct platform_device *pdev)
{
- struct device_node *node = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
struct cc10001_adc_device *adc_dev;
unsigned long adc_clk_rate;
struct iio_dev *indio_dev;
unsigned long channel_map;
int ret;
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc_dev));
if (indio_dev == NULL)
return -ENOMEM;
@@ -326,7 +337,7 @@ static int cc10001_adc_probe(struct platform_device *pdev)
channel_map &= ~ret;
}
- adc_dev->reg = devm_regulator_get(&pdev->dev, "vref");
+ adc_dev->reg = devm_regulator_get(dev, "vref");
if (IS_ERR(adc_dev->reg))
return PTR_ERR(adc_dev->reg);
@@ -334,34 +345,28 @@ static int cc10001_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- indio_dev->name = dev_name(&pdev->dev);
+ ret = devm_add_action_or_reset(dev, cc10001_reg_disable, adc_dev->reg);
+ if (ret)
+ return ret;
+
+ indio_dev->name = dev_name(dev);
indio_dev->info = &cc10001_adc_info;
indio_dev->modes = INDIO_DIRECT_MODE;
adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(adc_dev->reg_base)) {
- ret = PTR_ERR(adc_dev->reg_base);
- goto err_disable_reg;
- }
+ if (IS_ERR(adc_dev->reg_base))
+ return PTR_ERR(adc_dev->reg_base);
- adc_dev->adc_clk = devm_clk_get(&pdev->dev, "adc");
+ adc_dev->adc_clk = devm_clk_get_enabled(dev, "adc");
if (IS_ERR(adc_dev->adc_clk)) {
- dev_err(&pdev->dev, "failed to get the clock\n");
- ret = PTR_ERR(adc_dev->adc_clk);
- goto err_disable_reg;
- }
-
- ret = clk_prepare_enable(adc_dev->adc_clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable the clock\n");
- goto err_disable_reg;
+ dev_err(dev, "failed to get/enable the clock\n");
+ return PTR_ERR(adc_dev->adc_clk);
}
adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
if (!adc_clk_rate) {
- ret = -EINVAL;
- dev_err(&pdev->dev, "null clock rate!\n");
- goto err_disable_clk;
+ dev_err(dev, "null clock rate!\n");
+ return -EINVAL;
}
adc_dev->eoc_delay_ns = NSEC_PER_SEC / adc_clk_rate;
@@ -375,47 +380,22 @@ static int cc10001_adc_probe(struct platform_device *pdev)
if (adc_dev->shared)
cc10001_adc_power_up(adc_dev);
+ ret = devm_add_action_or_reset(dev, cc10001_pd_cb, adc_dev);
+ if (ret)
+ return ret;
/* Setup the ADC channels available on the device */
ret = cc10001_adc_channel_init(indio_dev, channel_map);
if (ret < 0)
- goto err_disable_clk;
+ return ret;
mutex_init(&adc_dev->lock);
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
- &cc10001_adc_trigger_h, NULL);
- if (ret < 0)
- goto err_disable_clk;
-
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ &cc10001_adc_trigger_h, NULL);
if (ret < 0)
- goto err_cleanup_buffer;
-
- platform_set_drvdata(pdev, indio_dev);
-
- return 0;
-
-err_cleanup_buffer:
- iio_triggered_buffer_cleanup(indio_dev);
-err_disable_clk:
- clk_disable_unprepare(adc_dev->adc_clk);
-err_disable_reg:
- regulator_disable(adc_dev->reg);
- return ret;
-}
-
-static int cc10001_adc_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
-
- cc10001_adc_power_down(adc_dev);
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- clk_disable_unprepare(adc_dev->adc_clk);
- regulator_disable(adc_dev->reg);
+ return ret;
- return 0;
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id cc10001_adc_dt_ids[] = {
@@ -430,7 +410,6 @@ static struct platform_driver cc10001_adc_driver = {
.of_match_table = cc10001_adc_dt_ids,
},
.probe = cc10001_adc_probe,
- .remove = cc10001_adc_remove,
};
module_platform_driver(cc10001_adc_driver);
diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c
index 86caff1d006b..22da81bac97f 100644
--- a/drivers/iio/adc/imx7d_adc.c
+++ b/drivers/iio/adc/imx7d_adc.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -108,7 +109,8 @@ struct imx7d_adc {
struct device *dev;
void __iomem *regs;
struct clk *clk;
-
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
u32 vref_uv;
u32 value;
u32 channel;
@@ -293,7 +295,7 @@ static int imx7d_adc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&info->lock);
reinit_completion(&info->completion);
channel = chan->channel & 0x03;
@@ -303,16 +305,16 @@ static int imx7d_adc_read_raw(struct iio_dev *indio_dev,
ret = wait_for_completion_interruptible_timeout
(&info->completion, IMX7D_ADC_TIMEOUT);
if (ret == 0) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return -ETIMEDOUT;
}
if (ret < 0) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return ret;
}
*val = info->value;
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@@ -531,6 +533,8 @@ static int imx7d_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
+ mutex_init(&info->lock);
+
ret = devm_iio_device_register(dev, indio_dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register the device.\n");
diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c
index 910e7e965fc4..38d9d7b2313e 100644
--- a/drivers/iio/adc/ina2xx-adc.c
+++ b/drivers/iio/adc/ina2xx-adc.c
@@ -946,9 +946,9 @@ static int ina2xx_init(struct ina2xx_chip_info *chip, unsigned int config)
return ina2xx_set_calibration(chip);
}
-static int ina2xx_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ina2xx_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ina2xx_chip_info *chip;
struct iio_dev *indio_dev;
unsigned int val;
@@ -1090,7 +1090,7 @@ static struct i2c_driver ina2xx_driver = {
.name = KBUILD_MODNAME,
.of_match_table = ina2xx_of_match,
},
- .probe = ina2xx_probe,
+ .probe_new = ina2xx_probe,
.remove = ina2xx_remove,
.id_table = ina2xx_id,
};
diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c
index b56ce15255cf..732c924a976d 100644
--- a/drivers/iio/adc/lpc32xx_adc.c
+++ b/drivers/iio/adc/lpc32xx_adc.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -49,6 +50,8 @@ struct lpc32xx_adc_state {
struct clk *clk;
struct completion completion;
struct regulator *vref;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
u32 value;
};
@@ -64,10 +67,10 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
ret = clk_prepare_enable(st->clk);
if (ret) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
}
/* Measurement setup */
@@ -80,7 +83,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
wait_for_completion(&st->completion); /* set by ISR */
clk_disable_unprepare(st->clk);
*val = st->value;
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return IIO_VAL_INT;
@@ -201,6 +204,8 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
iodev->modes = INDIO_DIRECT_MODE;
iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels);
+ mutex_init(&st->lock);
+
retval = devm_iio_device_register(&pdev->dev, iodev);
if (retval)
return retval;
diff --git a/drivers/iio/adc/ltc2471.c b/drivers/iio/adc/ltc2471.c
index 0e0fe881a8e6..eeb2945829eb 100644
--- a/drivers/iio/adc/ltc2471.c
+++ b/drivers/iio/adc/ltc2471.c
@@ -99,9 +99,9 @@ static const struct iio_info ltc2471_info = {
.read_raw = ltc2471_read_raw,
};
-static int ltc2471_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ltc2471_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct ltc2471_data *data;
int ret;
@@ -146,7 +146,7 @@ static struct i2c_driver ltc2471_i2c_driver = {
.driver = {
.name = "ltc2471",
},
- .probe = ltc2471_i2c_probe,
+ .probe_new = ltc2471_i2c_probe,
.id_table = ltc2471_i2c_id,
};
diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c
index 37c762f8218c..6a23427344ec 100644
--- a/drivers/iio/adc/ltc2485.c
+++ b/drivers/iio/adc/ltc2485.c
@@ -89,9 +89,9 @@ static const struct iio_info ltc2485_info = {
.read_raw = ltc2485_read_raw,
};
-static int ltc2485_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ltc2485_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct ltc2485_data *data;
int ret;
@@ -133,7 +133,7 @@ static struct i2c_driver ltc2485_driver = {
.driver = {
.name = "ltc2485",
},
- .probe = ltc2485_probe,
+ .probe_new = ltc2485_probe,
.id_table = ltc2485_id,
};
module_i2c_driver(ltc2485_driver);
diff --git a/drivers/iio/adc/ltc2497-core.c b/drivers/iio/adc/ltc2497-core.c
index f52d37af4d1f..996f6cbbed3c 100644
--- a/drivers/iio/adc/ltc2497-core.c
+++ b/drivers/iio/adc/ltc2497-core.c
@@ -10,6 +10,7 @@
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
#include "ltc2497.h"
@@ -81,9 +82,9 @@ static int ltc2497core_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&ddata->lock);
ret = ltc2497core_read(ddata, chan->address, val);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&ddata->lock);
if (ret < 0)
return ret;
@@ -214,6 +215,8 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
ddata->addr_prev = LTC2497_CONFIG_DEFAULT;
ddata->time_prev = ktime_get();
+ mutex_init(&ddata->lock);
+
ret = iio_device_register(indio_dev);
if (ret < 0)
goto err_array_unregister;
diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index 556f10dfb502..17370c5eb6fe 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -94,9 +94,9 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
return ret;
}
-static int ltc2497_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ltc2497_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct ltc2497_chip_info *chip_info;
struct iio_dev *indio_dev;
struct ltc2497_driverdata *st;
@@ -165,7 +165,7 @@ static struct i2c_driver ltc2497_driver = {
.name = "ltc2497",
.of_match_table = ltc2497_of_match,
},
- .probe = ltc2497_probe,
+ .probe_new = ltc2497_probe,
.remove = ltc2497_remove,
.id_table = ltc2497_id,
};
diff --git a/drivers/iio/adc/ltc2497.h b/drivers/iio/adc/ltc2497.h
index e023de0d88c4..781519b52475 100644
--- a/drivers/iio/adc/ltc2497.h
+++ b/drivers/iio/adc/ltc2497.h
@@ -12,6 +12,8 @@ struct ltc2497_chip_info {
struct ltc2497core_driverdata {
struct regulator *ref;
ktime_t time_prev;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
const struct ltc2497_chip_info *chip_info;
u8 addr_prev;
int (*result_and_measure)(struct ltc2497core_driverdata *ddata,
diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c
new file mode 100644
index 000000000000..fdc9f03135b5
--- /dev/null
+++ b/drivers/iio/adc/max11410.c
@@ -0,0 +1,1050 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MAX11410 SPI ADC driver
+ *
+ * Copyright 2022 Analog Devices Inc.
+ */
+#include <asm-generic/unaligned.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define MAX11410_REG_CONV_START 0x01
+#define MAX11410_CONV_TYPE_SINGLE 0x00
+#define MAX11410_CONV_TYPE_CONTINUOUS 0x01
+#define MAX11410_REG_CAL_START 0x03
+#define MAX11410_CAL_START_SELF 0x00
+#define MAX11410_CAL_START_PGA 0x01
+#define MAX11410_REG_GPIO_CTRL(ch) ((ch) ? 0x05 : 0x04)
+#define MAX11410_GPIO_INTRB 0xC1
+#define MAX11410_REG_FILTER 0x08
+#define MAX11410_FILTER_RATE_MASK GENMASK(3, 0)
+#define MAX11410_FILTER_RATE_MAX 0x0F
+#define MAX11410_FILTER_LINEF_MASK GENMASK(5, 4)
+#define MAX11410_FILTER_50HZ BIT(5)
+#define MAX11410_FILTER_60HZ BIT(4)
+#define MAX11410_REG_CTRL 0x09
+#define MAX11410_CTRL_REFSEL_MASK GENMASK(2, 0)
+#define MAX11410_CTRL_VREFN_BUF_BIT BIT(3)
+#define MAX11410_CTRL_VREFP_BUF_BIT BIT(4)
+#define MAX11410_CTRL_FORMAT_BIT BIT(5)
+#define MAX11410_CTRL_UNIPOLAR_BIT BIT(6)
+#define MAX11410_REG_MUX_CTRL0 0x0B
+#define MAX11410_REG_PGA 0x0E
+#define MAX11410_PGA_GAIN_MASK GENMASK(2, 0)
+#define MAX11410_PGA_SIG_PATH_MASK GENMASK(5, 4)
+#define MAX11410_PGA_SIG_PATH_BUFFERED 0x00
+#define MAX11410_PGA_SIG_PATH_BYPASS 0x01
+#define MAX11410_PGA_SIG_PATH_PGA 0x02
+#define MAX11410_REG_DATA0 0x30
+#define MAX11410_REG_STATUS 0x38
+#define MAX11410_STATUS_CONV_READY_BIT BIT(0)
+#define MAX11410_STATUS_CAL_READY_BIT BIT(2)
+
+#define MAX11410_REFSEL_AVDD_AGND 0x03
+#define MAX11410_REFSEL_MAX 0x06
+#define MAX11410_SIG_PATH_MAX 0x02
+#define MAX11410_CHANNEL_INDEX_MAX 0x0A
+#define MAX11410_AINP_AVDD 0x0A
+#define MAX11410_AINN_GND 0x0A
+
+#define MAX11410_CONVERSION_TIMEOUT_MS 2000
+#define MAX11410_CALIB_TIMEOUT_MS 2000
+
+#define MAX11410_SCALE_AVAIL_SIZE 8
+
+enum max11410_filter {
+ MAX11410_FILTER_FIR5060,
+ MAX11410_FILTER_FIR50,
+ MAX11410_FILTER_FIR60,
+ MAX11410_FILTER_SINC4,
+};
+
+static const u8 max11410_sampling_len[] = {
+ [MAX11410_FILTER_FIR5060] = 5,
+ [MAX11410_FILTER_FIR50] = 6,
+ [MAX11410_FILTER_FIR60] = 6,
+ [MAX11410_FILTER_SINC4] = 10,
+};
+
+static const int max11410_sampling_rates[4][10][2] = {
+ [MAX11410_FILTER_FIR5060] = {
+ { 1, 100000 },
+ { 2, 100000 },
+ { 4, 200000 },
+ { 8, 400000 },
+ { 16, 800000 }
+ },
+ [MAX11410_FILTER_FIR50] = {
+ { 1, 300000 },
+ { 2, 700000 },
+ { 5, 300000 },
+ { 10, 700000 },
+ { 21, 300000 },
+ { 40 }
+ },
+ [MAX11410_FILTER_FIR60] = {
+ { 1, 300000 },
+ { 2, 700000 },
+ { 5, 300000 },
+ { 10, 700000 },
+ { 21, 300000 },
+ { 40 }
+ },
+ [MAX11410_FILTER_SINC4] = {
+ { 4 },
+ { 10 },
+ { 20 },
+ { 40 },
+ { 60 },
+ { 120 },
+ { 240 },
+ { 480 },
+ { 960 },
+ { 1920 }
+ }
+};
+
+struct max11410_channel_config {
+ u32 settling_time_us;
+ u32 *scale_avail;
+ u8 refsel;
+ u8 sig_path;
+ u8 gain;
+ bool bipolar;
+ bool buffered_vrefp;
+ bool buffered_vrefn;
+};
+
+struct max11410_state {
+ struct spi_device *spi_dev;
+ struct iio_trigger *trig;
+ struct completion completion;
+ struct mutex lock; /* Prevent changing channel config during sampling */
+ struct regmap *regmap;
+ struct regulator *avdd;
+ struct regulator *vrefp[3];
+ struct regulator *vrefn[3];
+ struct max11410_channel_config *channels;
+ int irq;
+ struct {
+ u32 data __aligned(IIO_DMA_MINALIGN);
+ s64 ts __aligned(8);
+ } scan;
+};
+
+static const struct iio_chan_spec chanspec_template = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ .endianness = IIO_LE,
+ },
+};
+
+static unsigned int max11410_reg_size(unsigned int reg)
+{
+ /* Registers from 0x00 to 0x10 are 1 byte, the rest are 3 bytes long. */
+ return reg <= 0x10 ? 1 : 3;
+}
+
+static int max11410_write_reg(struct max11410_state *st, unsigned int reg,
+ unsigned int val)
+{
+ /* This driver only needs to write 8-bit registers */
+ if (max11410_reg_size(reg) != 1)
+ return -EINVAL;
+
+ return regmap_write(st->regmap, reg, val);
+}
+
+static int max11410_read_reg(struct max11410_state *st, unsigned int reg,
+ int *val)
+{
+ int ret;
+
+ if (max11410_reg_size(reg) == 3) {
+ ret = regmap_bulk_read(st->regmap, reg, &st->scan.data, 3);
+ if (ret)
+ return ret;
+
+ *val = get_unaligned_be24(&st->scan.data);
+ return 0;
+ }
+
+ return regmap_read(st->regmap, reg, val);
+}
+
+static struct regulator *max11410_get_vrefp(struct max11410_state *st,
+ u8 refsel)
+{
+ refsel = refsel % 4;
+ if (refsel == 3)
+ return st->avdd;
+
+ return st->vrefp[refsel];
+}
+
+static struct regulator *max11410_get_vrefn(struct max11410_state *st,
+ u8 refsel)
+{
+ if (refsel > 2)
+ return NULL;
+
+ return st->vrefn[refsel];
+}
+
+static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x39,
+};
+
+static ssize_t max11410_notch_en_show(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct max11410_state *state = iio_priv(indio_dev);
+ struct iio_dev_attr *iio_attr = to_iio_dev_attr(devattr);
+ unsigned int val;
+ int ret;
+
+ ret = max11410_read_reg(state, MAX11410_REG_FILTER, &val);
+ if (ret)
+ return ret;
+
+ switch (iio_attr->address) {
+ case 0:
+ val = !FIELD_GET(MAX11410_FILTER_50HZ, val);
+ break;
+ case 1:
+ val = !FIELD_GET(MAX11410_FILTER_60HZ, val);
+ break;
+ case 2:
+ val = FIELD_GET(MAX11410_FILTER_LINEF_MASK, val) == 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return sysfs_emit(buf, "%d\n", val);
+}
+
+static ssize_t max11410_notch_en_store(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct iio_dev_attr *iio_attr = to_iio_dev_attr(devattr);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct max11410_state *state = iio_priv(indio_dev);
+ unsigned int filter_bits;
+ bool enable;
+ int ret;
+
+ ret = kstrtobool(buf, &enable);
+ if (ret)
+ return ret;
+
+ switch (iio_attr->address) {
+ case 0:
+ filter_bits = MAX11410_FILTER_50HZ;
+ break;
+ case 1:
+ filter_bits = MAX11410_FILTER_60HZ;
+ break;
+ case 2:
+ default:
+ filter_bits = MAX11410_FILTER_50HZ | MAX11410_FILTER_60HZ;
+ enable = !enable;
+ break;
+ }
+
+ if (enable)
+ ret = regmap_clear_bits(state->regmap, MAX11410_REG_FILTER,
+ filter_bits);
+ else
+ ret = regmap_set_bits(state->regmap, MAX11410_REG_FILTER,
+ filter_bits);
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t in_voltage_filter2_notch_center_show(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct max11410_state *state = iio_priv(indio_dev);
+ int ret, reg, rate, filter;
+
+ ret = regmap_read(state->regmap, MAX11410_REG_FILTER, &reg);
+ if (ret)
+ return ret;
+
+ rate = FIELD_GET(MAX11410_FILTER_RATE_MASK, reg);
+ rate = clamp_val(rate, 0,
+ max11410_sampling_len[MAX11410_FILTER_SINC4] - 1);
+ filter = max11410_sampling_rates[MAX11410_FILTER_SINC4][rate][0];
+
+ return sysfs_emit(buf, "%d\n", filter);
+}
+
+static IIO_CONST_ATTR(in_voltage_filter0_notch_center, "50");
+static IIO_CONST_ATTR(in_voltage_filter1_notch_center, "60");
+static IIO_DEVICE_ATTR_RO(in_voltage_filter2_notch_center, 2);
+
+static IIO_DEVICE_ATTR(in_voltage_filter0_notch_en, 0644,
+ max11410_notch_en_show, max11410_notch_en_store, 0);
+static IIO_DEVICE_ATTR(in_voltage_filter1_notch_en, 0644,
+ max11410_notch_en_show, max11410_notch_en_store, 1);
+static IIO_DEVICE_ATTR(in_voltage_filter2_notch_en, 0644,
+ max11410_notch_en_show, max11410_notch_en_store, 2);
+
+static struct attribute *max11410_attributes[] = {
+ &iio_const_attr_in_voltage_filter0_notch_center.dev_attr.attr,
+ &iio_const_attr_in_voltage_filter1_notch_center.dev_attr.attr,
+ &iio_dev_attr_in_voltage_filter2_notch_center.dev_attr.attr,
+ &iio_dev_attr_in_voltage_filter0_notch_en.dev_attr.attr,
+ &iio_dev_attr_in_voltage_filter1_notch_en.dev_attr.attr,
+ &iio_dev_attr_in_voltage_filter2_notch_en.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group max11410_attribute_group = {
+ .attrs = max11410_attributes,
+};
+
+static int max11410_set_input_mux(struct max11410_state *st, u8 ainp, u8 ainn)
+{
+ if (ainp > MAX11410_CHANNEL_INDEX_MAX ||
+ ainn > MAX11410_CHANNEL_INDEX_MAX)
+ return -EINVAL;
+
+ return max11410_write_reg(st, MAX11410_REG_MUX_CTRL0,
+ (ainp << 4) | ainn);
+}
+
+static int max11410_configure_channel(struct max11410_state *st,
+ struct iio_chan_spec const *chan)
+{
+ struct max11410_channel_config cfg = st->channels[chan->address];
+ unsigned int regval;
+ int ret;
+
+ if (chan->differential)
+ ret = max11410_set_input_mux(st, chan->channel, chan->channel2);
+ else
+ ret = max11410_set_input_mux(st, chan->channel,
+ MAX11410_AINN_GND);
+
+ if (ret)
+ return ret;
+
+ regval = FIELD_PREP(MAX11410_CTRL_VREFP_BUF_BIT, cfg.buffered_vrefp) |
+ FIELD_PREP(MAX11410_CTRL_VREFN_BUF_BIT, cfg.buffered_vrefn) |
+ FIELD_PREP(MAX11410_CTRL_REFSEL_MASK, cfg.refsel) |
+ FIELD_PREP(MAX11410_CTRL_UNIPOLAR_BIT, cfg.bipolar ? 0 : 1);
+ ret = regmap_update_bits(st->regmap, MAX11410_REG_CTRL,
+ MAX11410_CTRL_REFSEL_MASK |
+ MAX11410_CTRL_VREFP_BUF_BIT |
+ MAX11410_CTRL_VREFN_BUF_BIT |
+ MAX11410_CTRL_UNIPOLAR_BIT, regval);
+ if (ret)
+ return ret;
+
+ regval = FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK, cfg.sig_path) |
+ FIELD_PREP(MAX11410_PGA_GAIN_MASK, cfg.gain);
+ ret = regmap_write(st->regmap, MAX11410_REG_PGA, regval);
+ if (ret)
+ return ret;
+
+ if (cfg.settling_time_us)
+ fsleep(cfg.settling_time_us);
+
+ return 0;
+}
+
+static int max11410_sample(struct max11410_state *st, int *sample_raw,
+ struct iio_chan_spec const *chan)
+{
+ int val, ret;
+
+ ret = max11410_configure_channel(st, chan);
+ if (ret)
+ return ret;
+
+ if (st->irq > 0)
+ reinit_completion(&st->completion);
+
+ /* Start Conversion */
+ ret = max11410_write_reg(st, MAX11410_REG_CONV_START,
+ MAX11410_CONV_TYPE_SINGLE);
+ if (ret)
+ return ret;
+
+ if (st->irq > 0) {
+ /* Wait for an interrupt. */
+ ret = wait_for_completion_timeout(&st->completion,
+ msecs_to_jiffies(MAX11410_CONVERSION_TIMEOUT_MS));
+ if (!ret)
+ return -ETIMEDOUT;
+ } else {
+ /* Wait for status register Conversion Ready flag */
+ ret = read_poll_timeout(max11410_read_reg, ret,
+ ret || (val & MAX11410_STATUS_CONV_READY_BIT),
+ 5000, MAX11410_CONVERSION_TIMEOUT_MS * 1000,
+ true, st, MAX11410_REG_STATUS, &val);
+ if (ret)
+ return ret;
+ }
+
+ /* Read ADC Data */
+ return max11410_read_reg(st, MAX11410_REG_DATA0, sample_raw);
+}
+
+static int max11410_get_scale(struct max11410_state *state,
+ struct max11410_channel_config cfg)
+{
+ struct regulator *vrefp, *vrefn;
+ int scale;
+
+ vrefp = max11410_get_vrefp(state, cfg.refsel);
+
+ scale = regulator_get_voltage(vrefp) / 1000;
+ vrefn = max11410_get_vrefn(state, cfg.refsel);
+ if (vrefn)
+ scale -= regulator_get_voltage(vrefn) / 1000;
+
+ if (cfg.bipolar)
+ scale *= 2;
+
+ return scale >> cfg.gain;
+}
+
+static int max11410_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct max11410_state *state = iio_priv(indio_dev);
+ struct max11410_channel_config cfg = state->channels[chan->address];
+ int ret, reg_val, filter, rate;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ *val = max11410_get_scale(state, cfg);
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OFFSET:
+ if (cfg.bipolar)
+ *val = -BIT(chan->scan_type.realbits - 1);
+ else
+ *val = 0;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&state->lock);
+
+ ret = max11410_sample(state, &reg_val, chan);
+
+ mutex_unlock(&state->lock);
+
+ iio_device_release_direct_mode(indio_dev);
+
+ if (ret)
+ return ret;
+
+ *val = reg_val;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = regmap_read(state->regmap, MAX11410_REG_FILTER, &reg_val);
+ if (ret)
+ return ret;
+
+ filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+ rate = reg_val & MAX11410_FILTER_RATE_MASK;
+ if (rate >= max11410_sampling_len[filter])
+ rate = max11410_sampling_len[filter] - 1;
+
+ *val = max11410_sampling_rates[filter][rate][0];
+ *val2 = max11410_sampling_rates[filter][rate][1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+ return -EINVAL;
+}
+
+static int max11410_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct max11410_state *st = iio_priv(indio_dev);
+ int i, ret, reg_val, filter, gain;
+ u32 *scale_avail;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ scale_avail = st->channels[chan->address].scale_avail;
+ if (!scale_avail)
+ return -EOPNOTSUPP;
+
+ /* Accept values in range 0.000001 <= scale < 1.000000 */
+ if (val != 0 || val2 == 0)
+ return -EINVAL;
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ /* Convert from INT_PLUS_MICRO to FRACTIONAL_LOG2 */
+ val2 = val2 * DIV_ROUND_CLOSEST(BIT(24), 1000000);
+ val2 = DIV_ROUND_CLOSEST(scale_avail[0], val2);
+ gain = order_base_2(val2);
+
+ st->channels[chan->address].gain = clamp_val(gain, 0, 7);
+
+ iio_device_release_direct_mode(indio_dev);
+
+ return 0;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&st->lock);
+
+ ret = regmap_read(st->regmap, MAX11410_REG_FILTER, &reg_val);
+ if (ret)
+ goto out;
+
+ filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+
+ for (i = 0; i < max11410_sampling_len[filter]; ++i) {
+ if (val == max11410_sampling_rates[filter][i][0] &&
+ val2 == max11410_sampling_rates[filter][i][1])
+ break;
+ }
+ if (i == max11410_sampling_len[filter]) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+ MAX11410_FILTER_RATE_MASK, i);
+
+out:
+ mutex_unlock(&st->lock);
+ iio_device_release_direct_mode(indio_dev);
+
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int max11410_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
+{
+ struct max11410_state *st = iio_priv(indio_dev);
+ struct max11410_channel_config cfg;
+ int ret, reg_val, filter;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = regmap_read(st->regmap, MAX11410_REG_FILTER, &reg_val);
+ if (ret)
+ return ret;
+
+ filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+
+ *vals = (const int *)max11410_sampling_rates[filter];
+ *length = max11410_sampling_len[filter] * 2;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ cfg = st->channels[chan->address];
+
+ if (!cfg.scale_avail)
+ return -EINVAL;
+
+ *vals = cfg.scale_avail;
+ *length = MAX11410_SCALE_AVAIL_SIZE * 2;
+ *type = IIO_VAL_FRACTIONAL_LOG2;
+
+ return IIO_AVAIL_LIST;
+ }
+ return -EINVAL;
+}
+
+static const struct iio_info max11410_info = {
+ .read_raw = max11410_read_raw,
+ .write_raw = max11410_write_raw,
+ .read_avail = max11410_read_avail,
+ .attrs = &max11410_attribute_group,
+};
+
+static irqreturn_t max11410_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct max11410_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = max11410_read_reg(st, MAX11410_REG_DATA0, &st->scan.data);
+ if (ret) {
+ dev_err(&indio_dev->dev, "cannot read data\n");
+ goto out;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->scan,
+ iio_get_time_ns(indio_dev));
+
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int max11410_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct max11410_state *st = iio_priv(indio_dev);
+ int scan_ch, ret;
+
+ scan_ch = ffs(*indio_dev->active_scan_mask) - 1;
+
+ ret = max11410_configure_channel(st, &indio_dev->channels[scan_ch]);
+ if (ret)
+ return ret;
+
+ /* Start continuous conversion. */
+ return max11410_write_reg(st, MAX11410_REG_CONV_START,
+ MAX11410_CONV_TYPE_CONTINUOUS);
+}
+
+static int max11410_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct max11410_state *st = iio_priv(indio_dev);
+
+ /* Stop continuous conversion. */
+ return max11410_write_reg(st, MAX11410_REG_CONV_START,
+ MAX11410_CONV_TYPE_SINGLE);
+}
+
+static const struct iio_buffer_setup_ops max11410_buffer_ops = {
+ .postenable = &max11410_buffer_postenable,
+ .predisable = &max11410_buffer_predisable,
+ .validate_scan_mask = &iio_validate_scan_mask_onehot,
+};
+
+static const struct iio_trigger_ops max11410_trigger_ops = {
+ .validate_device = iio_trigger_validate_own_device,
+};
+
+static irqreturn_t max11410_interrupt(int irq, void *dev_id)
+{
+ struct iio_dev *indio_dev = dev_id;
+ struct max11410_state *st = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev))
+ iio_trigger_poll_chained(st->trig);
+ else
+ complete(&st->completion);
+
+ return IRQ_HANDLED;
+};
+
+static int max11410_parse_channels(struct max11410_state *st,
+ struct iio_dev *indio_dev)
+{
+ struct iio_chan_spec chanspec = chanspec_template;
+ struct device *dev = &st->spi_dev->dev;
+ struct max11410_channel_config *cfg;
+ struct iio_chan_spec *channels;
+ struct fwnode_handle *child;
+ u32 reference, sig_path;
+ const char *node_name;
+ u32 inputs[2], scale;
+ unsigned int num_ch;
+ int chan_idx = 0;
+ int ret, i;
+
+ num_ch = device_get_child_node_count(dev);
+ if (num_ch == 0)
+ return dev_err_probe(&indio_dev->dev, -ENODEV,
+ "FW has no channels defined\n");
+
+ /* Reserve space for soft timestamp channel */
+ num_ch++;
+ channels = devm_kcalloc(dev, num_ch, sizeof(*channels), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ st->channels = devm_kcalloc(dev, num_ch, sizeof(*st->channels),
+ GFP_KERNEL);
+ if (!st->channels)
+ return -ENOMEM;
+
+ device_for_each_child_node(dev, child) {
+ node_name = fwnode_get_name(child);
+ if (fwnode_property_present(child, "diff-channels")) {
+ ret = fwnode_property_read_u32_array(child,
+ "diff-channels",
+ inputs,
+ ARRAY_SIZE(inputs));
+
+ chanspec.differential = 1;
+ } else {
+ ret = fwnode_property_read_u32(child, "reg", &inputs[0]);
+
+ inputs[1] = 0;
+ chanspec.differential = 0;
+ }
+ if (ret) {
+ fwnode_handle_put(child);
+ return ret;
+ }
+
+ if (inputs[0] > MAX11410_CHANNEL_INDEX_MAX ||
+ inputs[1] > MAX11410_CHANNEL_INDEX_MAX) {
+ fwnode_handle_put(child);
+ return dev_err_probe(&indio_dev->dev, -EINVAL,
+ "Invalid channel index for %s, should be less than %d\n",
+ node_name,
+ MAX11410_CHANNEL_INDEX_MAX + 1);
+ }
+
+ cfg = &st->channels[chan_idx];
+
+ reference = MAX11410_REFSEL_AVDD_AGND;
+ fwnode_property_read_u32(child, "adi,reference", &reference);
+ if (reference > MAX11410_REFSEL_MAX) {
+ fwnode_handle_put(child);
+ return dev_err_probe(&indio_dev->dev, -EINVAL,
+ "Invalid adi,reference value for %s, should be less than %d.\n",
+ node_name, MAX11410_REFSEL_MAX + 1);
+ }
+
+ if (!max11410_get_vrefp(st, reference) ||
+ (!max11410_get_vrefn(st, reference) && reference <= 2)) {
+ fwnode_handle_put(child);
+ return dev_err_probe(&indio_dev->dev, -EINVAL,
+ "Invalid VREF configuration for %s, either specify corresponding VREF regulators or change adi,reference property.\n",
+ node_name);
+ }
+
+ sig_path = MAX11410_PGA_SIG_PATH_BUFFERED;
+ fwnode_property_read_u32(child, "adi,input-mode", &sig_path);
+ if (sig_path > MAX11410_SIG_PATH_MAX) {
+ fwnode_handle_put(child);
+ return dev_err_probe(&indio_dev->dev, -EINVAL,
+ "Invalid adi,input-mode value for %s, should be less than %d.\n",
+ node_name, MAX11410_SIG_PATH_MAX + 1);
+ }
+
+ fwnode_property_read_u32(child, "settling-time-us",
+ &cfg->settling_time_us);
+ cfg->bipolar = fwnode_property_read_bool(child, "bipolar");
+ cfg->buffered_vrefp = fwnode_property_read_bool(child, "adi,buffered-vrefp");
+ cfg->buffered_vrefn = fwnode_property_read_bool(child, "adi,buffered-vrefn");
+ cfg->refsel = reference;
+ cfg->sig_path = sig_path;
+ cfg->gain = 0;
+
+ /* Enable scale_available property if input mode is PGA */
+ if (sig_path == MAX11410_PGA_SIG_PATH_PGA) {
+ __set_bit(IIO_CHAN_INFO_SCALE,
+ &chanspec.info_mask_separate_available);
+ cfg->scale_avail = devm_kcalloc(dev, MAX11410_SCALE_AVAIL_SIZE * 2,
+ sizeof(*cfg->scale_avail),
+ GFP_KERNEL);
+ if (!cfg->scale_avail) {
+ fwnode_handle_put(child);
+ return -ENOMEM;
+ }
+
+ scale = max11410_get_scale(st, *cfg);
+ for (i = 0; i < MAX11410_SCALE_AVAIL_SIZE; i++) {
+ cfg->scale_avail[2 * i] = scale >> i;
+ cfg->scale_avail[2 * i + 1] = chanspec.scan_type.realbits;
+ }
+ } else {
+ __clear_bit(IIO_CHAN_INFO_SCALE,
+ &chanspec.info_mask_separate_available);
+ }
+
+ chanspec.address = chan_idx;
+ chanspec.scan_index = chan_idx;
+ chanspec.channel = inputs[0];
+ chanspec.channel2 = inputs[1];
+
+ channels[chan_idx] = chanspec;
+ chan_idx++;
+ }
+
+ channels[chan_idx] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(chan_idx);
+
+ indio_dev->num_channels = chan_idx + 1;
+ indio_dev->channels = channels;
+
+ return 0;
+}
+
+static void max11410_disable_reg(void *reg)
+{
+ regulator_disable(reg);
+}
+
+static int max11410_init_vref(struct device *dev,
+ struct regulator **vref,
+ const char *id)
+{
+ struct regulator *reg;
+ int ret;
+
+ reg = devm_regulator_get_optional(dev, id);
+ if (PTR_ERR(reg) == -ENODEV) {
+ *vref = NULL;
+ return 0;
+ } else if (IS_ERR(reg)) {
+ return PTR_ERR(reg);
+ }
+ ret = regulator_enable(reg);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable regulator %s\n", id);
+
+ *vref = reg;
+ return devm_add_action_or_reset(dev, max11410_disable_reg, reg);
+}
+
+static int max11410_calibrate(struct max11410_state *st, u32 cal_type)
+{
+ int ret, val;
+
+ ret = max11410_write_reg(st, MAX11410_REG_CAL_START, cal_type);
+ if (ret)
+ return ret;
+
+ /* Wait for status register Calibration Ready flag */
+ return read_poll_timeout(max11410_read_reg, ret,
+ ret || (val & MAX11410_STATUS_CAL_READY_BIT),
+ 50000, MAX11410_CALIB_TIMEOUT_MS * 1000, true,
+ st, MAX11410_REG_STATUS, &val);
+}
+
+static int max11410_self_calibrate(struct max11410_state *st)
+{
+ int ret, i;
+
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+ MAX11410_FILTER_RATE_MASK,
+ FIELD_PREP(MAX11410_FILTER_RATE_MASK,
+ MAX11410_FILTER_RATE_MAX));
+ if (ret)
+ return ret;
+
+ ret = max11410_calibrate(st, MAX11410_CAL_START_SELF);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+ MAX11410_PGA_SIG_PATH_MASK,
+ FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK,
+ MAX11410_PGA_SIG_PATH_PGA));
+ if (ret)
+ return ret;
+
+ /* PGA calibrations */
+ for (i = 1; i < 8; ++i) {
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+ MAX11410_PGA_GAIN_MASK, i);
+ if (ret)
+ return ret;
+
+ ret = max11410_calibrate(st, MAX11410_CAL_START_PGA);
+ if (ret)
+ return ret;
+ }
+
+ /* Cleanup */
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+ MAX11410_PGA_GAIN_MASK, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+ MAX11410_FILTER_RATE_MASK, 0);
+ if (ret)
+ return ret;
+
+ return regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+ MAX11410_PGA_SIG_PATH_MASK,
+ FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK,
+ MAX11410_PGA_SIG_PATH_BUFFERED));
+}
+
+static int max11410_probe(struct spi_device *spi)
+{
+ const char *vrefp_regs[] = { "vref0p", "vref1p", "vref2p" };
+ const char *vrefn_regs[] = { "vref0n", "vref1n", "vref2n" };
+ struct device *dev = &spi->dev;
+ struct max11410_state *st;
+ struct iio_dev *indio_dev;
+ int ret, irqs[2];
+ int i;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi_dev = spi;
+ init_completion(&st->completion);
+ mutex_init(&st->lock);
+
+ indio_dev->name = "max11410";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &max11410_info;
+
+ st->regmap = devm_regmap_init_spi(spi, &regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
+ "regmap initialization failed\n");
+
+ ret = max11410_init_vref(dev, &st->avdd, "avdd");
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(vrefp_regs); i++) {
+ ret = max11410_init_vref(dev, &st->vrefp[i], vrefp_regs[i]);
+ if (ret)
+ return ret;
+
+ ret = max11410_init_vref(dev, &st->vrefn[i], vrefn_regs[i]);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Regulators must be configured before parsing channels for
+ * validating "adi,reference" property of each channel.
+ */
+ ret = max11410_parse_channels(st, indio_dev);
+ if (ret)
+ return ret;
+
+ irqs[0] = fwnode_irq_get_byname(dev_fwnode(dev), "gpio0");
+ irqs[1] = fwnode_irq_get_byname(dev_fwnode(dev), "gpio1");
+
+ if (irqs[0] > 0) {
+ st->irq = irqs[0];
+ ret = regmap_write(st->regmap, MAX11410_REG_GPIO_CTRL(0),
+ MAX11410_GPIO_INTRB);
+ } else if (irqs[1] > 0) {
+ st->irq = irqs[1];
+ ret = regmap_write(st->regmap, MAX11410_REG_GPIO_CTRL(1),
+ MAX11410_GPIO_INTRB);
+ } else if (spi->irq > 0) {
+ return dev_err_probe(dev, -ENODEV,
+ "no interrupt name specified");
+ }
+
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(st->regmap, MAX11410_REG_CTRL,
+ MAX11410_CTRL_FORMAT_BIT);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ &max11410_trigger_handler,
+ &max11410_buffer_ops);
+ if (ret)
+ return ret;
+
+ if (st->irq > 0) {
+ st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!st->trig)
+ return -ENOMEM;
+
+ st->trig->ops = &max11410_trigger_ops;
+ ret = devm_iio_trigger_register(dev, st->trig);
+ if (ret)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, st->irq, NULL,
+ &max11410_interrupt,
+ IRQF_ONESHOT, "max11410",
+ indio_dev);
+ if (ret)
+ return ret;
+ }
+
+ ret = max11410_self_calibrate(st);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "cannot perform device self calibration\n");
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id max11410_spi_of_id[] = {
+ { .compatible = "adi,max11410" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max11410_spi_of_id);
+
+static const struct spi_device_id max11410_id[] = {
+ { "max11410" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, max11410_id);
+
+static struct spi_driver max11410_driver = {
+ .driver = {
+ .name = "max11410",
+ .of_match_table = max11410_spi_of_id,
+ },
+ .probe = max11410_probe,
+ .id_table = max11410_id,
+};
+module_spi_driver(max11410_driver);
+
+MODULE_AUTHOR("David Jung <David.Jung@analog.com>");
+MODULE_AUTHOR("Ibrahim Tilki <Ibrahim.Tilki@analog.com>");
+MODULE_DESCRIPTION("Analog Devices MAX11410 ADC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
index a815ad1f6913..500bb09ab19b 100644
--- a/drivers/iio/adc/max1241.c
+++ b/drivers/iio/adc/max1241.c
@@ -22,7 +22,6 @@ enum max1241_id {
struct max1241 {
struct spi_device *spi;
struct mutex lock;
- struct regulator *vdd;
struct regulator *vref;
struct gpio_desc *shutdown;
@@ -110,17 +109,6 @@ static const struct iio_info max1241_info = {
.read_raw = max1241_read_raw,
};
-static void max1241_disable_vdd_action(void *data)
-{
- struct max1241 *adc = data;
- struct device *dev = &adc->spi->dev;
- int err;
-
- err = regulator_disable(adc->vdd);
- if (err)
- dev_err(dev, "could not disable vdd regulator.\n");
-}
-
static void max1241_disable_vref_action(void *data)
{
struct max1241 *adc = data;
@@ -147,20 +135,10 @@ static int max1241_probe(struct spi_device *spi)
adc->spi = spi;
mutex_init(&adc->lock);
- adc->vdd = devm_regulator_get(dev, "vdd");
- if (IS_ERR(adc->vdd))
- return dev_err_probe(dev, PTR_ERR(adc->vdd),
- "failed to get vdd regulator\n");
-
- ret = regulator_enable(adc->vdd);
+ ret = devm_regulator_get_enable(dev, "vdd");
if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(dev, max1241_disable_vdd_action, adc);
- if (ret) {
- dev_err(dev, "could not set up vdd regulator cleanup action\n");
- return ret;
- }
+ return dev_err_probe(dev, ret,
+ "failed to get/enable vdd regulator\n");
adc->vref = devm_regulator_get(dev, "vref");
if (IS_ERR(adc->vref))
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index a28cf86cdce8..73b783b430d7 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -148,7 +148,6 @@ struct max1363_chip_info {
* @chip_info: chip model specific constants, available modes, etc.
* @current_mode: the scan mode of this chip
* @requestedmask: a valid requested set of channels
- * @reg: supply regulator
* @lock: lock to ensure state is consistent
* @monitor_on: whether monitor mode is enabled
* @monitor_speed: parameter corresponding to device monitor speed setting
@@ -168,7 +167,6 @@ struct max1363_state {
const struct max1363_chip_info *chip_info;
const struct max1363_mode *current_mode;
u32 requestedmask;
- struct regulator *reg;
struct mutex lock;
/* Using monitor modes and buffer at the same time is
@@ -1581,9 +1579,9 @@ static void max1363_reg_disable(void *reg)
regulator_disable(reg);
}
-static int max1363_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max1363_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
struct max1363_state *st;
struct iio_dev *indio_dev;
@@ -1597,15 +1595,7 @@ static int max1363_probe(struct i2c_client *client,
st = iio_priv(indio_dev);
mutex_init(&st->lock);
- st->reg = devm_regulator_get(&client->dev, "vcc");
- if (IS_ERR(st->reg))
- return PTR_ERR(st->reg);
-
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&client->dev, max1363_reg_disable, st->reg);
+ ret = devm_regulator_get_enable(&client->dev, "vcc");
if (ret)
return ret;
@@ -1728,7 +1718,7 @@ static struct i2c_driver max1363_driver = {
.name = "max1363",
.of_match_table = max1363_of_match,
},
- .probe = max1363_probe,
+ .probe_new = 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 f982f00303dc..cb7f4785423a 100644
--- a/drivers/iio/adc/max9611.c
+++ b/drivers/iio/adc/max9611.c
@@ -510,8 +510,7 @@ static const struct of_device_id max9611_of_table[] = {
};
MODULE_DEVICE_TABLE(of, max9611_of_table);
-static int max9611_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max9611_probe(struct i2c_client *client)
{
const char * const shunt_res_prop = "shunt-resistor-micro-ohms";
struct max9611_dev *max9611;
@@ -557,7 +556,7 @@ static struct i2c_driver max9611_driver = {
.name = DRIVER_NAME,
.of_match_table = max9611_of_table,
},
- .probe = max9611_probe,
+ .probe_new = max9611_probe,
};
module_i2c_driver(max9611_driver);
diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c
index da353dcb1e9d..ada844c3f7ec 100644
--- a/drivers/iio/adc/mcp3422.c
+++ b/drivers/iio/adc/mcp3422.c
@@ -330,9 +330,9 @@ static const struct iio_info mcp3422_info = {
.attrs = &mcp3422_attribute_group,
};
-static int mcp3422_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mcp3422_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct mcp3422 *adc;
int err;
@@ -417,7 +417,7 @@ static struct i2c_driver mcp3422_driver = {
.name = "mcp3422",
.of_match_table = mcp3422_of_match,
},
- .probe = mcp3422_probe,
+ .probe_new = mcp3422_probe,
.id_table = mcp3422_id,
};
module_i2c_driver(mcp3422_driver);
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
index 76b334f5ac61..974c5bd923a6 100644
--- a/drivers/iio/adc/mcp3911.c
+++ b/drivers/iio/adc/mcp3911.c
@@ -29,6 +29,8 @@
#define MCP3911_REG_MOD 0x06
#define MCP3911_REG_PHASE 0x07
#define MCP3911_REG_GAIN 0x09
+#define MCP3911_GAIN_MASK(ch) (GENMASK(2, 0) << 3 * ch)
+#define MCP3911_GAIN_VAL(ch, val) ((val << 3 * ch) & MCP3911_GAIN_MASK(ch))
#define MCP3911_REG_STATUSCOM 0x0a
#define MCP3911_STATUSCOM_DRHIZ BIT(12)
@@ -60,8 +62,10 @@
#define MCP3911_REG_MASK GENMASK(4, 1)
#define MCP3911_NUM_CHANNELS 2
+#define MCP3911_NUM_SCALES 6
static const int mcp3911_osr_table[] = { 32, 64, 128, 256, 512, 1024, 2048, 4096 };
+static u32 mcp3911_scale_table[MCP3911_NUM_SCALES][2];
struct mcp3911 {
struct spi_device *spi;
@@ -70,6 +74,7 @@ struct mcp3911 {
struct clk *clki;
u32 dev_addr;
struct iio_trigger *trig;
+ u32 gain[MCP3911_NUM_CHANNELS];
struct {
u32 channels[MCP3911_NUM_CHANNELS];
s64 ts __aligned(8);
@@ -146,6 +151,11 @@ static int mcp3911_read_avail(struct iio_dev *indio_dev,
*vals = mcp3911_osr_table;
*length = ARRAY_SIZE(mcp3911_osr_table);
return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ *type = IIO_VAL_INT_PLUS_NANO;
+ *vals = (int *)mcp3911_scale_table;
+ *length = ARRAY_SIZE(mcp3911_scale_table) * 2;
+ return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
@@ -190,29 +200,9 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev,
break;
case IIO_CHAN_INFO_SCALE:
- if (adc->vref) {
- ret = regulator_get_voltage(adc->vref);
- if (ret < 0) {
- dev_err(indio_dev->dev.parent,
- "failed to get vref voltage: %d\n",
- ret);
- goto out;
- }
-
- *val = ret / 1000;
- } else {
- *val = MCP3911_INT_VREF_MV;
- }
-
- /*
- * For 24bit Conversion
- * Raw = ((Voltage)/(Vref) * 2^23 * Gain * 1.5
- * Voltage = Raw * (Vref)/(2^23 * Gain * 1.5)
- */
-
- /* val2 = (2^23 * 1.5) */
- *val2 = 12582912;
- ret = IIO_VAL_FRACTIONAL;
+ *val = mcp3911_scale_table[ilog2(adc->gain[channel->channel])][0];
+ *val2 = mcp3911_scale_table[ilog2(adc->gain[channel->channel])][1];
+ ret = IIO_VAL_INT_PLUS_NANO;
break;
}
@@ -230,6 +220,18 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev,
mutex_lock(&adc->lock);
switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ for (int i = 0; i < MCP3911_NUM_SCALES; i++) {
+ if (val == mcp3911_scale_table[i][0] &&
+ val2 == mcp3911_scale_table[i][1]) {
+
+ adc->gain[channel->channel] = BIT(i);
+ ret = mcp3911_update(adc, MCP3911_REG_GAIN,
+ MCP3911_GAIN_MASK(channel->channel),
+ MCP3911_GAIN_VAL(channel->channel, i), 1);
+ }
+ }
+ break;
case IIO_CHAN_INFO_OFFSET:
if (val2 != 0) {
ret = -EINVAL;
@@ -265,6 +267,44 @@ out:
return ret;
}
+static int mcp3911_calc_scale_table(struct mcp3911 *adc)
+{
+ u32 ref = MCP3911_INT_VREF_MV;
+ u32 div;
+ int ret;
+ u64 tmp;
+
+ if (adc->vref) {
+ ret = regulator_get_voltage(adc->vref);
+ if (ret < 0) {
+ dev_err(&adc->spi->dev,
+ "failed to get vref voltage: %d\n",
+ ret);
+ return ret;
+ }
+
+ ref = ret / 1000;
+ }
+
+ /*
+ * For 24-bit Conversion
+ * Raw = ((Voltage)/(Vref) * 2^23 * Gain * 1.5
+ * Voltage = Raw * (Vref)/(2^23 * Gain * 1.5)
+ *
+ * ref = Reference voltage
+ * div = (2^23 * 1.5 * gain) = 12582912 * gain
+ */
+ for (int i = 0; i < MCP3911_NUM_SCALES; i++) {
+ div = 12582912 * BIT(i);
+ tmp = div_s64((s64)ref * 1000000000LL, div);
+
+ mcp3911_scale_table[i][0] = 0;
+ mcp3911_scale_table[i][1] = tmp;
+ }
+
+ return 0;
+}
+
#define MCP3911_CHAN(idx) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
@@ -274,8 +314,10 @@ out:
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_OFFSET) | \
BIT(IIO_CHAN_INFO_SCALE), \
- .info_mask_shared_by_type_available = \
+ .info_mask_shared_by_type_available = \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_separate_available = \
+ BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 's', \
.realbits = 24, \
@@ -482,6 +524,20 @@ static int mcp3911_probe(struct spi_device *spi)
if (ret)
return ret;
+ ret = mcp3911_calc_scale_table(adc);
+ if (ret)
+ return ret;
+
+ /* Set gain to 1 for all channels */
+ for (int i = 0; i < MCP3911_NUM_CHANNELS; i++) {
+ adc->gain[i] = 1;
+ ret = mcp3911_update(adc, MCP3911_REG_GAIN,
+ MCP3911_GAIN_MASK(i),
+ MCP3911_GAIN_VAL(i, 0), 1);
+ if (ret)
+ return ret;
+ }
+
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mcp3911_info;
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 1a68b099d323..85b6826cc10c 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -12,6 +12,7 @@
#include <linux/io.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/nvmem-consumer.h>
#include <linux/interrupt.h>
#include <linux/of.h>
@@ -276,6 +277,8 @@ struct meson_sar_adc_priv {
struct clk *adc_div_clk;
struct clk_divider clk_div;
struct completion done;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
int calibbias;
int calibscale;
struct regmap *tsc_regmap;
@@ -486,7 +489,7 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
int val, ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&priv->lock);
if (priv->param->has_bl30_integration) {
/* prevent BL30 from using the SAR ADC while we are using it */
@@ -504,7 +507,7 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
!(val & MESON_SAR_ADC_DELAY_BL30_BUSY),
1, 10000);
if (ret) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&priv->lock);
return ret;
}
}
@@ -521,7 +524,7 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&priv->lock);
}
static void meson_sar_adc_clear_fifo(struct iio_dev *indio_dev)
@@ -1250,6 +1253,8 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
if (ret)
goto err;
+ mutex_init(&priv->lock);
+
ret = meson_sar_adc_hw_enable(indio_dev);
if (ret)
goto err;
diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c
new file mode 100644
index 000000000000..bc62e5a9d50d
--- /dev/null
+++ b/drivers/iio/adc/mt6370-adc.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/sysfs.h>
+#include <linux/units.h>
+
+#include <dt-bindings/iio/adc/mediatek,mt6370_adc.h>
+
+#define MT6370_REG_CHG_CTRL3 0x113
+#define MT6370_REG_CHG_CTRL7 0x117
+#define MT6370_REG_CHG_ADC 0x121
+#define MT6370_REG_ADC_DATA_H 0x14C
+
+#define MT6370_ADC_START_MASK BIT(0)
+#define MT6370_ADC_IN_SEL_MASK GENMASK(7, 4)
+#define MT6370_AICR_ICHG_MASK GENMASK(7, 2)
+
+#define MT6370_AICR_100_mA 0x0
+#define MT6370_AICR_150_mA 0x1
+#define MT6370_AICR_200_mA 0x2
+#define MT6370_AICR_250_mA 0x3
+#define MT6370_AICR_300_mA 0x4
+#define MT6370_AICR_350_mA 0x5
+
+#define MT6370_ICHG_100_mA 0x0
+#define MT6370_ICHG_200_mA 0x1
+#define MT6370_ICHG_300_mA 0x2
+#define MT6370_ICHG_400_mA 0x3
+#define MT6370_ICHG_500_mA 0x4
+#define MT6370_ICHG_600_mA 0x5
+#define MT6370_ICHG_700_mA 0x6
+#define MT6370_ICHG_800_mA 0x7
+
+#define ADC_CONV_TIME_MS 35
+#define ADC_CONV_POLLING_TIME_US 1000
+
+struct mt6370_adc_data {
+ struct device *dev;
+ struct regmap *regmap;
+ /*
+ * This mutex lock is for preventing the different ADC channels
+ * from being read at the same time.
+ */
+ struct mutex adc_lock;
+};
+
+static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan,
+ unsigned long addr, int *val)
+{
+ unsigned int reg_val;
+ __be16 be_val;
+ int ret;
+
+ mutex_lock(&priv->adc_lock);
+
+ reg_val = MT6370_ADC_START_MASK |
+ FIELD_PREP(MT6370_ADC_IN_SEL_MASK, addr);
+ ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, reg_val);
+ if (ret)
+ goto adc_unlock;
+
+ msleep(ADC_CONV_TIME_MS);
+
+ ret = regmap_read_poll_timeout(priv->regmap,
+ MT6370_REG_CHG_ADC, reg_val,
+ !(reg_val & MT6370_ADC_START_MASK),
+ ADC_CONV_POLLING_TIME_US,
+ ADC_CONV_TIME_MS * MILLI * 3);
+ if (ret) {
+ dev_err(priv->dev, "Failed to read ADC register (%d)\n", ret);
+ goto adc_unlock;
+ }
+
+ ret = regmap_raw_read(priv->regmap, MT6370_REG_ADC_DATA_H,
+ &be_val, sizeof(be_val));
+ if (ret)
+ goto adc_unlock;
+
+ *val = be16_to_cpu(be_val);
+ ret = IIO_VAL_INT;
+
+adc_unlock:
+ mutex_unlock(&priv->adc_lock);
+
+ return ret;
+}
+
+static int mt6370_adc_read_scale(struct mt6370_adc_data *priv,
+ int chan, int *val1, int *val2)
+{
+ unsigned int reg_val;
+ int ret;
+
+ switch (chan) {
+ case MT6370_CHAN_VBAT:
+ case MT6370_CHAN_VSYS:
+ case MT6370_CHAN_CHG_VDDP:
+ *val1 = 5;
+ return IIO_VAL_INT;
+ case MT6370_CHAN_IBUS:
+ ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL3, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+ switch (reg_val) {
+ case MT6370_AICR_100_mA:
+ case MT6370_AICR_150_mA:
+ case MT6370_AICR_200_mA:
+ case MT6370_AICR_250_mA:
+ case MT6370_AICR_300_mA:
+ case MT6370_AICR_350_mA:
+ *val1 = 3350;
+ break;
+ default:
+ *val1 = 5000;
+ break;
+ }
+
+ *val2 = 100;
+
+ return IIO_VAL_FRACTIONAL;
+ case MT6370_CHAN_IBAT:
+ ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL7, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+ switch (reg_val) {
+ case MT6370_ICHG_100_mA:
+ case MT6370_ICHG_200_mA:
+ case MT6370_ICHG_300_mA:
+ case MT6370_ICHG_400_mA:
+ *val1 = 2375;
+ break;
+ case MT6370_ICHG_500_mA:
+ case MT6370_ICHG_600_mA:
+ case MT6370_ICHG_700_mA:
+ case MT6370_ICHG_800_mA:
+ *val1 = 2680;
+ break;
+ default:
+ *val1 = 5000;
+ break;
+ }
+
+ *val2 = 100;
+
+ return IIO_VAL_FRACTIONAL;
+ case MT6370_CHAN_VBUSDIV5:
+ *val1 = 25;
+ return IIO_VAL_INT;
+ case MT6370_CHAN_VBUSDIV2:
+ *val1 = 10;
+ return IIO_VAL_INT;
+ case MT6370_CHAN_TS_BAT:
+ *val1 = 25;
+ *val2 = 10000;
+ return IIO_VAL_FRACTIONAL;
+ case MT6370_CHAN_TEMP_JC:
+ *val1 = 2000;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mt6370_adc_read_offset(struct mt6370_adc_data *priv,
+ int chan, int *val)
+{
+ *val = -20;
+
+ return IIO_VAL_INT;
+}
+
+static int mt6370_adc_read_raw(struct iio_dev *iio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct mt6370_adc_data *priv = iio_priv(iio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return mt6370_adc_read_channel(priv, chan->channel,
+ chan->address, val);
+ case IIO_CHAN_INFO_SCALE:
+ return mt6370_adc_read_scale(priv, chan->channel, val, val2);
+ case IIO_CHAN_INFO_OFFSET:
+ return mt6370_adc_read_offset(priv, chan->channel, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const char * const mt6370_channel_labels[MT6370_CHAN_MAX] = {
+ [MT6370_CHAN_VBUSDIV5] = "vbusdiv5",
+ [MT6370_CHAN_VBUSDIV2] = "vbusdiv2",
+ [MT6370_CHAN_VSYS] = "vsys",
+ [MT6370_CHAN_VBAT] = "vbat",
+ [MT6370_CHAN_TS_BAT] = "ts_bat",
+ [MT6370_CHAN_IBUS] = "ibus",
+ [MT6370_CHAN_IBAT] = "ibat",
+ [MT6370_CHAN_CHG_VDDP] = "chg_vddp",
+ [MT6370_CHAN_TEMP_JC] = "temp_jc",
+};
+
+static int mt6370_adc_read_label(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan, char *label)
+{
+ return sysfs_emit(label, "%s\n", mt6370_channel_labels[chan->channel]);
+}
+
+static const struct iio_info mt6370_adc_iio_info = {
+ .read_raw = mt6370_adc_read_raw,
+ .read_label = mt6370_adc_read_label,
+};
+
+#define MT6370_ADC_CHAN(_idx, _type, _addr, _extra_info) { \
+ .type = _type, \
+ .channel = MT6370_CHAN_##_idx, \
+ .address = _addr, \
+ .scan_index = MT6370_CHAN_##_idx, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ _extra_info, \
+}
+
+static const struct iio_chan_spec mt6370_adc_channels[] = {
+ MT6370_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE, 1, 0),
+ MT6370_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE, 2, 0),
+ MT6370_ADC_CHAN(VSYS, IIO_VOLTAGE, 3, 0),
+ MT6370_ADC_CHAN(VBAT, IIO_VOLTAGE, 4, 0),
+ MT6370_ADC_CHAN(TS_BAT, IIO_VOLTAGE, 6, 0),
+ MT6370_ADC_CHAN(IBUS, IIO_CURRENT, 8, 0),
+ MT6370_ADC_CHAN(IBAT, IIO_CURRENT, 9, 0),
+ MT6370_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE, 11, 0),
+ MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12, BIT(IIO_CHAN_INFO_OFFSET)),
+};
+
+static int mt6370_adc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mt6370_adc_data *priv;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ int ret;
+
+ regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!regmap)
+ return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ priv = iio_priv(indio_dev);
+ priv->dev = dev;
+ priv->regmap = regmap;
+ mutex_init(&priv->adc_lock);
+
+ ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, 0);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to reset ADC\n");
+
+ indio_dev->name = "mt6370-adc";
+ indio_dev->info = &mt6370_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = mt6370_adc_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mt6370_adc_channels);
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id mt6370_adc_of_id[] = {
+ { .compatible = "mediatek,mt6370-adc", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mt6370_adc_of_id);
+
+static struct platform_driver mt6370_adc_driver = {
+ .driver = {
+ .name = "mt6370-adc",
+ .of_match_table = mt6370_adc_of_id,
+ },
+ .probe = mt6370_adc_probe,
+};
+module_platform_driver(mt6370_adc_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MT6370 ADC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index b87ea7148b58..79448c5ffc2a 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -5,6 +5,7 @@
*/
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -49,6 +50,8 @@ struct rockchip_saradc {
struct clk *clk;
struct completion completion;
struct regulator *vref;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
int uv_vref;
struct reset_control *reset;
const struct rockchip_saradc_data *data;
@@ -94,17 +97,17 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&info->lock);
ret = rockchip_saradc_conversion(info, chan);
if (ret) {
rockchip_saradc_power_down(info);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return ret;
}
*val = info->last_val;
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = info->uv_vref / 1000;
@@ -270,7 +273,7 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
int ret;
int i, j = 0;
- mutex_lock(&i_dev->mlock);
+ mutex_lock(&info->lock);
for_each_set_bit(i, i_dev->active_scan_mask, i_dev->masklength) {
const struct iio_chan_spec *chan = &i_dev->channels[i];
@@ -287,7 +290,7 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
iio_push_to_buffers_with_timestamp(i_dev, &data, iio_get_time_ns(i_dev));
out:
- mutex_unlock(&i_dev->mlock);
+ mutex_unlock(&info->lock);
iio_trigger_notify_done(i_dev->trig);
@@ -478,6 +481,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
if (ret)
return ret;
+ mutex_init(&info->lock);
+
return devm_iio_device_register(&pdev->dev, indio_dev);
}
diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c
index f8421cbba8fa..ff1fc329bb9b 100644
--- a/drivers/iio/adc/sc27xx_adc.c
+++ b/drivers/iio/adc/sc27xx_adc.c
@@ -4,6 +4,7 @@
#include <linux/hwspinlock.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -83,6 +84,8 @@ struct sc27xx_adc_data {
struct device *dev;
struct regulator *volref;
struct regmap *regmap;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
/*
* One hardware spinlock to synchronize between the multiple
* subsystems which will access the unique ADC controller.
@@ -664,9 +667,9 @@ static int sc27xx_adc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&data->lock);
ret = sc27xx_adc_read(data, chan->channel, scale, &tmp);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&data->lock);
if (ret)
return ret;
@@ -675,10 +678,10 @@ static int sc27xx_adc_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_PROCESSED:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&data->lock);
ret = sc27xx_adc_read_processed(data, chan->channel, scale,
&tmp);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&data->lock);
if (ret)
return ret;
@@ -934,6 +937,9 @@ static int sc27xx_adc_probe(struct platform_device *pdev)
indio_dev->info = &sc27xx_info;
indio_dev->channels = sc27xx_channels;
indio_dev->num_channels = ARRAY_SIZE(sc27xx_channels);
+
+ mutex_init(&sc27xx_data->lock);
+
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
dev_err(dev, "could not register iio (ADC)");
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 81d5db91c67b..48f02dcc81c1 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -22,6 +22,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/units.h>
#include "stm32-adc-core.h"
@@ -306,8 +307,8 @@ out:
static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
.csr = STM32F4_ADC_CSR,
.ccr = STM32F4_ADC_CCR,
- .eoc_msk = { STM32F4_EOC1, STM32F4_EOC2, STM32F4_EOC3},
- .ovr_msk = { STM32F4_OVR1, STM32F4_OVR2, STM32F4_OVR3},
+ .eoc_msk = { STM32F4_EOC1, STM32F4_EOC2, STM32F4_EOC3 },
+ .ovr_msk = { STM32F4_OVR1, STM32F4_OVR2, STM32F4_OVR3 },
.ier = STM32F4_ADC_CR1,
.eocie_msk = STM32F4_EOCIE,
};
@@ -316,8 +317,18 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
.csr = STM32H7_ADC_CSR,
.ccr = STM32H7_ADC_CCR,
- .eoc_msk = { STM32H7_EOC_MST, STM32H7_EOC_SLV},
- .ovr_msk = { STM32H7_OVR_MST, STM32H7_OVR_SLV},
+ .eoc_msk = { STM32H7_EOC_MST, STM32H7_EOC_SLV },
+ .ovr_msk = { STM32H7_OVR_MST, STM32H7_OVR_SLV },
+ .ier = STM32H7_ADC_IER,
+ .eocie_msk = STM32H7_EOCIE,
+};
+
+/* STM32MP13 common registers definitions */
+static const struct stm32_adc_common_regs stm32mp13_adc_common_regs = {
+ .csr = STM32H7_ADC_CSR,
+ .ccr = STM32H7_ADC_CCR,
+ .eoc_msk = { STM32H7_EOC_MST },
+ .ovr_msk = { STM32H7_OVR_MST },
.ier = STM32H7_ADC_IER,
.eocie_msk = STM32H7_EOCIE,
};
@@ -868,6 +879,14 @@ static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
.num_irqs = 2,
};
+static const struct stm32_adc_priv_cfg stm32mp13_adc_priv_cfg = {
+ .regs = &stm32mp13_adc_common_regs,
+ .clk_sel = stm32h7_adc_clk_sel,
+ .max_clk_rate_hz = 75 * HZ_PER_MHZ,
+ .ipid = STM32MP13_IPIDR_NUMBER,
+ .num_irqs = 1,
+};
+
static const struct of_device_id stm32_adc_of_match[] = {
{
.compatible = "st,stm32f4-adc-core",
@@ -879,6 +898,9 @@ static const struct of_device_id stm32_adc_of_match[] = {
.compatible = "st,stm32mp1-adc-core",
.data = (void *)&stm32mp1_adc_priv_cfg
}, {
+ .compatible = "st,stm32mp13-adc-core",
+ .data = (void *)&stm32mp13_adc_priv_cfg
+ }, {
},
};
MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h
index 2118ef63843d..73b2c2e91c08 100644
--- a/drivers/iio/adc/stm32-adc-core.h
+++ b/drivers/iio/adc/stm32-adc-core.h
@@ -112,6 +112,11 @@
#define STM32MP1_ADC_IPDR 0x3F8
#define STM32MP1_ADC_SIDR 0x3FC
+/* STM32MP13 - Registers for each ADC instance */
+#define STM32MP13_ADC_DIFSEL 0xB0
+#define STM32MP13_ADC_CALFACT 0xB4
+#define STM32MP13_ADC2_OR 0xC8
+
/* STM32H7 - common registers for all ADC instances */
#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
@@ -137,6 +142,7 @@
#define STM32H7_LINCALRDYW3 BIT(24)
#define STM32H7_LINCALRDYW2 BIT(23)
#define STM32H7_LINCALRDYW1 BIT(22)
+#define STM32H7_LINCALRDYW_MASK GENMASK(27, 22)
#define STM32H7_ADCALLIN BIT(16)
#define STM32H7_BOOST BIT(8)
#define STM32H7_ADSTP BIT(4)
@@ -161,6 +167,9 @@ enum stm32h7_adc_dmngt {
STM32H7_DMNGT_DMA_CIRC, /* DMA circular mode */
};
+/* STM32H7_ADC_DIFSEL - bit fields */
+#define STM32H7_DIFSEL_MASK GENMASK(19, 0)
+
/* STM32H7_ADC_CALFACT - bit fields */
#define STM32H7_CALFACT_D_SHIFT 16
#define STM32H7_CALFACT_D_MASK GENMASK(26, 16)
@@ -210,7 +219,29 @@ enum stm32h7_adc_dmngt {
/* STM32MP1_ADC_SIDR - bit fields */
#define STM32MP1_SIDR_MASK GENMASK(31, 0)
+/* STM32MP13_ADC_CFGR specific bit fields */
+#define STM32MP13_DMAEN BIT(0)
+#define STM32MP13_DMACFG BIT(1)
+#define STM32MP13_DFSDMCFG BIT(2)
+#define STM32MP13_RES_SHIFT 3
+#define STM32MP13_RES_MASK GENMASK(4, 3)
+
+/* STM32MP13_ADC_DIFSEL - bit fields */
+#define STM32MP13_DIFSEL_MASK GENMASK(18, 0)
+
+/* STM32MP13_ADC_CALFACT - bit fields */
+#define STM32MP13_CALFACT_D_SHIFT 16
+#define STM32MP13_CALFACT_D_MASK GENMASK(22, 16)
+#define STM32MP13_CALFACT_S_SHIFT 0
+#define STM32MP13_CALFACT_S_MASK GENMASK(6, 0)
+
+/* STM32MP13_ADC2_OR - bit fields */
+#define STM32MP13_OP2 BIT(2)
+#define STM32MP13_OP1 BIT(1)
+#define STM32MP13_OP0 BIT(0)
+
#define STM32MP15_IPIDR_NUMBER 0x00110005
+#define STM32MP13_IPIDR_NUMBER 0x00110006
/**
* struct stm32_adc_common - stm32 ADC driver common data (for all instances)
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 3cda529f081d..45d4e79f8e55 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -7,6 +7,7 @@
*/
#include <linux/clk.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
@@ -82,6 +83,8 @@ enum stm32_adc_extsel {
enum stm32_adc_int_ch {
STM32_ADC_INT_CH_NONE = -1,
STM32_ADC_INT_CH_VDDCORE,
+ STM32_ADC_INT_CH_VDDCPU,
+ STM32_ADC_INT_CH_VDDQ_DDR,
STM32_ADC_INT_CH_VREFINT,
STM32_ADC_INT_CH_VBAT,
STM32_ADC_INT_CH_NB,
@@ -99,6 +102,8 @@ struct stm32_adc_ic {
static const struct stm32_adc_ic stm32_adc_ic[STM32_ADC_INT_CH_NB] = {
{ "vddcore", STM32_ADC_INT_CH_VDDCORE },
+ { "vddcpu", STM32_ADC_INT_CH_VDDCPU },
+ { "vddq_ddr", STM32_ADC_INT_CH_VDDQ_DDR },
{ "vrefint", STM32_ADC_INT_CH_VREFINT },
{ "vbat", STM32_ADC_INT_CH_VBAT },
};
@@ -115,16 +120,12 @@ struct stm32_adc_trig_info {
/**
* struct stm32_adc_calib - optional adc calibration data
- * @calfact_s: Calibration offset for single ended channels
- * @calfact_d: Calibration offset in differential
* @lincalfact: Linearity calibration factor
- * @calibrated: Indicates calibration status
+ * @lincal_saved: Indicates that linear calibration factors are saved
*/
struct stm32_adc_calib {
- u32 calfact_s;
- u32 calfact_d;
u32 lincalfact[STM32H7_LINCALFACT_NUM];
- bool calibrated;
+ bool lincal_saved;
};
/**
@@ -160,9 +161,12 @@ struct stm32_adc_vrefint {
* @exten: trigger control register & bitfield
* @extsel: trigger selection register & bitfield
* @res: resolution selection register & bitfield
+ * @difsel: differential mode selection register & bitfield
* @smpr: smpr1 & smpr2 registers offset array
* @smp_bits: smpr1 & smpr2 index and bitfields
- * @or_vdd: option register & vddcore bitfield
+ * @or_vddcore: option register & vddcore bitfield
+ * @or_vddcpu: option register & vddcpu bitfield
+ * @or_vddq_ddr: option register & vddq_ddr bitfield
* @ccr_vbat: common register & vbat bitfield
* @ccr_vref: common register & vrefint bitfield
*/
@@ -176,9 +180,12 @@ struct stm32_adc_regspec {
const struct stm32_adc_regs exten;
const struct stm32_adc_regs extsel;
const struct stm32_adc_regs res;
+ const struct stm32_adc_regs difsel;
const u32 smpr[2];
const struct stm32_adc_regs *smp_bits;
- const struct stm32_adc_regs or_vdd;
+ const struct stm32_adc_regs or_vddcore;
+ const struct stm32_adc_regs or_vddcpu;
+ const struct stm32_adc_regs or_vddq_ddr;
const struct stm32_adc_regs ccr_vbat;
const struct stm32_adc_regs ccr_vref;
};
@@ -192,13 +199,16 @@ struct stm32_adc;
* @trigs: external trigger sources
* @clk_required: clock is required
* @has_vregready: vregready status flag presence
+ * @has_boostmode: boost mode support flag
+ * @has_linearcal: linear calibration support flag
+ * @has_presel: channel preselection support flag
* @prepare: optional prepare routine (power-up, enable)
* @start_conv: routine to start conversions
* @stop_conv: routine to stop conversions
* @unprepare: optional unprepare routine (disable, power-down)
* @irq_clear: routine to clear irqs
* @smp_cycles: programmable sampling time (ADC clock cycles)
- * @ts_vrefint_ns: vrefint minimum sampling time in ns
+ * @ts_int_ch: pointer to array of internal channels minimum sampling time in ns
*/
struct stm32_adc_cfg {
const struct stm32_adc_regspec *regs;
@@ -206,13 +216,16 @@ struct stm32_adc_cfg {
struct stm32_adc_trig_info *trigs;
bool clk_required;
bool has_vregready;
+ bool has_boostmode;
+ bool has_linearcal;
+ bool has_presel;
int (*prepare)(struct iio_dev *);
void (*start_conv)(struct iio_dev *, bool dma);
void (*stop_conv)(struct iio_dev *);
void (*unprepare)(struct iio_dev *);
void (*irq_clear)(struct iio_dev *indio_dev, u32 msk);
const unsigned int *smp_cycles;
- const unsigned int ts_vrefint_ns;
+ const unsigned int *ts_int_ch;
};
/**
@@ -312,6 +325,13 @@ static const struct stm32_adc_info stm32h7_adc_info = {
.num_res = ARRAY_SIZE(stm32h7_adc_resolutions),
};
+/* stm32mp13 can have up to 19 channels */
+static const struct stm32_adc_info stm32mp13_adc_info = {
+ .max_channels = 19,
+ .resolutions = stm32f4_adc_resolutions,
+ .num_res = ARRAY_SIZE(stm32f4_adc_resolutions),
+};
+
/*
* stm32f4_sq - describe regular sequence registers
* - L: sequence len (register & bit field)
@@ -497,10 +517,37 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = {
.extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
STM32H7_EXTSEL_SHIFT },
.res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
+ .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK},
.smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
.smp_bits = stm32h7_smp_bits,
};
+/* STM32MP13 programmable sampling time (ADC clock cycles, rounded down) */
+static const unsigned int stm32mp13_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
+ 2, 6, 12, 24, 47, 92, 247, 640,
+};
+
+static const struct stm32_adc_regspec stm32mp13_adc_regspec = {
+ .dr = STM32H7_ADC_DR,
+ .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
+ .ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE },
+ .isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC },
+ .isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR },
+ .sqr = stm32h7_sq,
+ .exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT },
+ .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
+ STM32H7_EXTSEL_SHIFT },
+ .res = { STM32H7_ADC_CFGR, STM32MP13_RES_MASK, STM32MP13_RES_SHIFT },
+ .difsel = { STM32MP13_ADC_DIFSEL, STM32MP13_DIFSEL_MASK},
+ .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
+ .smp_bits = stm32h7_smp_bits,
+ .or_vddcore = { STM32MP13_ADC2_OR, STM32MP13_OP0 },
+ .or_vddcpu = { STM32MP13_ADC2_OR, STM32MP13_OP1 },
+ .or_vddq_ddr = { STM32MP13_ADC2_OR, STM32MP13_OP2 },
+ .ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN },
+ .ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN },
+};
+
static const struct stm32_adc_regspec stm32mp1_adc_regspec = {
.dr = STM32H7_ADC_DR,
.ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
@@ -512,9 +559,10 @@ static const struct stm32_adc_regspec stm32mp1_adc_regspec = {
.extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
STM32H7_EXTSEL_SHIFT },
.res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
+ .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK},
.smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
.smp_bits = stm32h7_smp_bits,
- .or_vdd = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN },
+ .or_vddcore = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN },
.ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN },
.ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN },
};
@@ -675,8 +723,18 @@ static void stm32_adc_int_ch_enable(struct iio_dev *indio_dev)
switch (i) {
case STM32_ADC_INT_CH_VDDCORE:
dev_dbg(&indio_dev->dev, "Enable VDDCore\n");
- stm32_adc_set_bits(adc, adc->cfg->regs->or_vdd.reg,
- adc->cfg->regs->or_vdd.mask);
+ stm32_adc_set_bits(adc, adc->cfg->regs->or_vddcore.reg,
+ adc->cfg->regs->or_vddcore.mask);
+ break;
+ case STM32_ADC_INT_CH_VDDCPU:
+ dev_dbg(&indio_dev->dev, "Enable VDDCPU\n");
+ stm32_adc_set_bits(adc, adc->cfg->regs->or_vddcpu.reg,
+ adc->cfg->regs->or_vddcpu.mask);
+ break;
+ case STM32_ADC_INT_CH_VDDQ_DDR:
+ dev_dbg(&indio_dev->dev, "Enable VDDQ_DDR\n");
+ stm32_adc_set_bits(adc, adc->cfg->regs->or_vddq_ddr.reg,
+ adc->cfg->regs->or_vddq_ddr.mask);
break;
case STM32_ADC_INT_CH_VREFINT:
dev_dbg(&indio_dev->dev, "Enable VREFInt\n");
@@ -702,8 +760,16 @@ static void stm32_adc_int_ch_disable(struct stm32_adc *adc)
switch (i) {
case STM32_ADC_INT_CH_VDDCORE:
- stm32_adc_clr_bits(adc, adc->cfg->regs->or_vdd.reg,
- adc->cfg->regs->or_vdd.mask);
+ stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddcore.reg,
+ adc->cfg->regs->or_vddcore.mask);
+ break;
+ case STM32_ADC_INT_CH_VDDCPU:
+ stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddcpu.reg,
+ adc->cfg->regs->or_vddcpu.mask);
+ break;
+ case STM32_ADC_INT_CH_VDDQ_DDR:
+ stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddq_ddr.reg,
+ adc->cfg->regs->or_vddq_ddr.mask);
break;
case STM32_ADC_INT_CH_VREFINT:
stm32_adc_clr_bits_common(adc, adc->cfg->regs->ccr_vref.reg,
@@ -801,6 +867,7 @@ static void stm32h7_adc_stop_conv(struct iio_dev *indio_dev)
if (ret)
dev_warn(&indio_dev->dev, "stop failed\n");
+ /* STM32H7_DMNGT_MASK covers STM32MP13_DMAEN & STM32MP13_DMACFG */
stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32H7_DMNGT_MASK);
}
@@ -811,6 +878,17 @@ static void stm32h7_adc_irq_clear(struct iio_dev *indio_dev, u32 msk)
stm32_adc_set_bits(adc, adc->cfg->regs->isr_eoc.reg, msk);
}
+static void stm32mp13_adc_start_conv(struct iio_dev *indio_dev, bool dma)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+
+ if (dma)
+ stm32_adc_set_bits(adc, STM32H7_ADC_CFGR,
+ STM32MP13_DMAEN | STM32MP13_DMACFG);
+
+ stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADSTART);
+}
+
static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
@@ -821,7 +899,8 @@ static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev)
stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD);
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADVREGEN);
- if (adc->common->rate > STM32H7_BOOST_CLKRATE)
+ if (adc->cfg->has_boostmode &&
+ adc->common->rate > STM32H7_BOOST_CLKRATE)
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
/* Wait for startup time */
@@ -843,7 +922,8 @@ static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev)
static void stm32h7_adc_enter_pwr_down(struct stm32_adc *adc)
{
- stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
+ if (adc->cfg->has_boostmode)
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
/* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD);
@@ -922,14 +1002,7 @@ static int stm32h7_adc_read_selfcalib(struct iio_dev *indio_dev)
lincalrdyw_mask >>= 1;
}
-
- /* Read offset calibration */
- val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT);
- adc->cal.calfact_s = (val & STM32H7_CALFACT_S_MASK);
- adc->cal.calfact_s >>= STM32H7_CALFACT_S_SHIFT;
- adc->cal.calfact_d = (val & STM32H7_CALFACT_D_MASK);
- adc->cal.calfact_d >>= STM32H7_CALFACT_D_SHIFT;
- adc->cal.calibrated = true;
+ adc->cal.lincal_saved = true;
return 0;
}
@@ -945,10 +1018,6 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev)
int i, ret;
u32 lincalrdyw_mask, val;
- val = (adc->cal.calfact_s << STM32H7_CALFACT_S_SHIFT) |
- (adc->cal.calfact_d << STM32H7_CALFACT_D_SHIFT);
- stm32_adc_writel(adc, STM32H7_ADC_CALFACT, val);
-
lincalrdyw_mask = STM32H7_LINCALRDYW6;
for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) {
/*
@@ -1010,17 +1079,21 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev)
/**
* stm32h7_adc_selfcalib() - Procedure to calibrate ADC
* @indio_dev: IIO device instance
+ * @do_lincal: linear calibration request flag
* Note: Must be called once ADC is out of power down.
+ *
+ * Run offset calibration unconditionally.
+ * Run linear calibration if requested & supported.
*/
-static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
+static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev, int do_lincal)
{
struct stm32_adc *adc = iio_priv(indio_dev);
int ret;
+ u32 msk = STM32H7_ADCALDIF;
u32 val;
- if (adc->cal.calibrated)
- return true;
-
+ if (adc->cfg->has_linearcal && do_lincal)
+ msk |= STM32H7_ADCALLIN;
/* ADC must be disabled for calibration */
stm32h7_adc_disable(indio_dev);
@@ -1029,8 +1102,7 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
* - Offset calibration for single ended inputs
* - No linearity calibration (do it later, before reading it)
*/
- stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADCALDIF);
- stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADCALLIN);
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CR, msk);
/* Start calibration, then wait for completion */
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
@@ -1038,7 +1110,7 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
!(val & STM32H7_ADCAL), 100,
STM32H7_ADC_CALIB_TIMEOUT_US);
if (ret) {
- dev_err(&indio_dev->dev, "calibration failed\n");
+ dev_err(&indio_dev->dev, "calibration (single-ended) error %d\n", ret);
goto out;
}
@@ -1048,25 +1120,51 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
* - Linearity calibration (needs to be done only once for single/diff)
* will run simultaneously with offset calibration.
*/
- stm32_adc_set_bits(adc, STM32H7_ADC_CR,
- STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+ stm32_adc_set_bits(adc, STM32H7_ADC_CR, msk);
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val,
!(val & STM32H7_ADCAL), 100,
STM32H7_ADC_CALIB_TIMEOUT_US);
if (ret) {
- dev_err(&indio_dev->dev, "calibration failed\n");
+ dev_err(&indio_dev->dev, "calibration (diff%s) error %d\n",
+ (msk & STM32H7_ADCALLIN) ? "+linear" : "", ret);
goto out;
}
out:
- stm32_adc_clr_bits(adc, STM32H7_ADC_CR,
- STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CR, msk);
return ret;
}
/**
+ * stm32h7_adc_check_selfcalib() - Check linear calibration status
+ * @indio_dev: IIO device instance
+ *
+ * Used to check if linear calibration has been done.
+ * Return true if linear calibration factors are already saved in private data
+ * or if a linear calibration has been done at boot stage.
+ */
+static int stm32h7_adc_check_selfcalib(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ u32 val;
+
+ if (adc->cal.lincal_saved)
+ return true;
+
+ /*
+ * Check if linear calibration factors are available in ADC registers,
+ * by checking that all LINCALRDYWx bits are set.
+ */
+ val = stm32_adc_readl(adc, STM32H7_ADC_CR) & STM32H7_LINCALRDYW_MASK;
+ if (val == STM32H7_LINCALRDYW_MASK)
+ return true;
+
+ return false;
+}
+
+/**
* stm32h7_adc_prepare() - Leave power down mode to enable ADC.
* @indio_dev: IIO device instance
* Leave power down mode.
@@ -1080,34 +1178,41 @@ out:
static int stm32h7_adc_prepare(struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
- int calib, ret;
+ int lincal_done = false;
+ int ret;
ret = stm32h7_adc_exit_pwr_down(indio_dev);
if (ret)
return ret;
- ret = stm32h7_adc_selfcalib(indio_dev);
+ if (adc->cfg->has_linearcal)
+ lincal_done = stm32h7_adc_check_selfcalib(indio_dev);
+
+ /* Always run offset calibration. Run linear calibration only once */
+ ret = stm32h7_adc_selfcalib(indio_dev, !lincal_done);
if (ret < 0)
goto pwr_dwn;
- calib = ret;
stm32_adc_int_ch_enable(indio_dev);
- stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel);
+ stm32_adc_writel(adc, adc->cfg->regs->difsel.reg, adc->difsel);
ret = stm32h7_adc_enable(indio_dev);
if (ret)
goto ch_disable;
- /* Either restore or read calibration result for future reference */
- if (calib)
- ret = stm32h7_adc_restore_selfcalib(indio_dev);
- else
- ret = stm32h7_adc_read_selfcalib(indio_dev);
- if (ret)
- goto disable;
+ if (adc->cfg->has_linearcal) {
+ if (!adc->cal.lincal_saved)
+ ret = stm32h7_adc_read_selfcalib(indio_dev);
+ else
+ ret = stm32h7_adc_restore_selfcalib(indio_dev);
+
+ if (ret)
+ goto disable;
+ }
- stm32_adc_writel(adc, STM32H7_ADC_PCSEL, adc->pcsel);
+ if (adc->cfg->has_presel)
+ stm32_adc_writel(adc, STM32H7_ADC_PCSEL, adc->pcsel);
return 0;
@@ -1125,7 +1230,8 @@ static void stm32h7_adc_unprepare(struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
- stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0);
+ if (adc->cfg->has_presel)
+ stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0);
stm32h7_adc_disable(indio_dev);
stm32_adc_int_ch_disable(adc);
stm32h7_adc_enter_pwr_down(adc);
@@ -1774,6 +1880,23 @@ static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = {
{},
};
+static void stm32_adc_debugfs_init(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ struct dentry *d = iio_get_debugfs_dentry(indio_dev);
+ struct stm32_adc_calib *cal = &adc->cal;
+ char buf[16];
+ unsigned int i;
+
+ if (!adc->cfg->has_linearcal)
+ return;
+
+ for (i = 0; i < STM32H7_LINCALFACT_NUM; i++) {
+ snprintf(buf, sizeof(buf), "lincalfact%d", i + 1);
+ debugfs_create_u32(buf, 0444, d, &cal->lincalfact[i]);
+ }
+}
+
static int stm32_adc_fw_get_resolution(struct iio_dev *indio_dev)
{
struct device *dev = &indio_dev->dev;
@@ -1802,14 +1925,15 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
{
const struct stm32_adc_regs *smpr = &adc->cfg->regs->smp_bits[channel];
u32 period_ns, shift = smpr->shift, mask = smpr->mask;
- unsigned int smp, r = smpr->reg;
+ unsigned int i, smp, r = smpr->reg;
/*
- * For vrefint channel, ensure that the sampling time cannot
+ * For internal channels, ensure that the sampling time cannot
* be lower than the one specified in the datasheet
*/
- if (channel == adc->int_ch[STM32_ADC_INT_CH_VREFINT])
- smp_ns = max(smp_ns, adc->cfg->ts_vrefint_ns);
+ for (i = 0; i < STM32_ADC_INT_CH_NB; i++)
+ if (channel == adc->int_ch[i] && adc->int_ch[i] != STM32_ADC_INT_CH_NONE)
+ smp_ns = max(smp_ns, adc->cfg->ts_int_ch[i]);
/* Determine sampling time (ADC clock cycles) */
period_ns = NSEC_PER_SEC / adc->common->rate;
@@ -1857,7 +1981,7 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
adc->pcsel |= BIT(chan->channel);
if (differential) {
/* pre-build diff channels mask */
- adc->difsel |= BIT(chan->channel);
+ adc->difsel |= BIT(chan->channel) & adc->cfg->regs->difsel.mask;
/* Also add negative input to pre-selected channels */
adc->pcsel |= BIT(chan->channel2);
}
@@ -1998,6 +2122,35 @@ static int stm32_adc_populate_int_ch(struct iio_dev *indio_dev, const char *ch_n
for (i = 0; i < STM32_ADC_INT_CH_NB; i++) {
if (!strncmp(stm32_adc_ic[i].name, ch_name, STM32_ADC_CH_SZ)) {
+ /* Check internal channel availability */
+ switch (i) {
+ case STM32_ADC_INT_CH_VDDCORE:
+ if (!adc->cfg->regs->or_vddcore.reg)
+ dev_warn(&indio_dev->dev,
+ "%s channel not available\n", ch_name);
+ break;
+ case STM32_ADC_INT_CH_VDDCPU:
+ if (!adc->cfg->regs->or_vddcpu.reg)
+ dev_warn(&indio_dev->dev,
+ "%s channel not available\n", ch_name);
+ break;
+ case STM32_ADC_INT_CH_VDDQ_DDR:
+ if (!adc->cfg->regs->or_vddq_ddr.reg)
+ dev_warn(&indio_dev->dev,
+ "%s channel not available\n", ch_name);
+ break;
+ case STM32_ADC_INT_CH_VREFINT:
+ if (!adc->cfg->regs->ccr_vref.reg)
+ dev_warn(&indio_dev->dev,
+ "%s channel not available\n", ch_name);
+ break;
+ case STM32_ADC_INT_CH_VBAT:
+ if (!adc->cfg->regs->ccr_vbat.reg)
+ dev_warn(&indio_dev->dev,
+ "%s channel not available\n", ch_name);
+ break;
+ }
+
if (stm32_adc_ic[i].idx != STM32_ADC_INT_CH_VREFINT) {
adc->int_ch[i] = chan;
break;
@@ -2330,6 +2483,9 @@ static int stm32_adc_probe(struct platform_device *pdev)
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
+ if (IS_ENABLED(CONFIG_DEBUG_FS))
+ stm32_adc_debugfs_init(indio_dev);
+
return 0;
err_hw_stop:
@@ -2358,6 +2514,7 @@ static int stm32_adc_remove(struct platform_device *pdev)
struct stm32_adc *adc = iio_priv(indio_dev);
pm_runtime_get_sync(&pdev->dev);
+ /* iio_device_unregister() also removes debugfs entries */
iio_device_unregister(indio_dev);
stm32_adc_hw_stop(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -2431,36 +2588,66 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = {
.irq_clear = stm32f4_adc_irq_clear,
};
+const unsigned int stm32_adc_min_ts_h7[] = { 0, 0, 0, 4300, 9000 };
+static_assert(ARRAY_SIZE(stm32_adc_min_ts_h7) == STM32_ADC_INT_CH_NB);
+
static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.regs = &stm32h7_adc_regspec,
.adc_info = &stm32h7_adc_info,
.trigs = stm32h7_adc_trigs,
+ .has_boostmode = true,
+ .has_linearcal = true,
+ .has_presel = true,
.start_conv = stm32h7_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
.unprepare = stm32h7_adc_unprepare,
.smp_cycles = stm32h7_adc_smp_cycles,
.irq_clear = stm32h7_adc_irq_clear,
+ .ts_int_ch = stm32_adc_min_ts_h7,
};
+const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 };
+static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp1) == STM32_ADC_INT_CH_NB);
+
static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.regs = &stm32mp1_adc_regspec,
.adc_info = &stm32h7_adc_info,
.trigs = stm32h7_adc_trigs,
.has_vregready = true,
+ .has_boostmode = true,
+ .has_linearcal = true,
+ .has_presel = true,
.start_conv = stm32h7_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
.unprepare = stm32h7_adc_unprepare,
.smp_cycles = stm32h7_adc_smp_cycles,
.irq_clear = stm32h7_adc_irq_clear,
- .ts_vrefint_ns = 4300,
+ .ts_int_ch = stm32_adc_min_ts_mp1,
+};
+
+const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 };
+static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp13) == STM32_ADC_INT_CH_NB);
+
+static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
+ .regs = &stm32mp13_adc_regspec,
+ .adc_info = &stm32mp13_adc_info,
+ .trigs = stm32h7_adc_trigs,
+ .start_conv = stm32mp13_adc_start_conv,
+ .stop_conv = stm32h7_adc_stop_conv,
+ .prepare = stm32h7_adc_prepare,
+ .unprepare = stm32h7_adc_unprepare,
+ .smp_cycles = stm32mp13_adc_smp_cycles,
+ .irq_clear = stm32h7_adc_irq_clear,
+ .ts_int_ch = stm32_adc_min_ts_mp13,
};
static const struct of_device_id stm32_adc_of_match[] = {
{ .compatible = "st,stm32f4-adc", .data = (void *)&stm32f4_adc_cfg },
{ .compatible = "st,stm32h7-adc", .data = (void *)&stm32h7_adc_cfg },
{ .compatible = "st,stm32mp1-adc", .data = (void *)&stm32mp1_adc_cfg },
+ { .compatible = "st,stm32mp13-adc", .data = (void *)&stm32mp13_adc_cfg },
{},
};
MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index bd48b073e720..c663dc59d459 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -152,9 +152,9 @@ static void adc081c_reg_disable(void *reg)
regulator_disable(reg);
}
-static int adc081c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adc081c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *iio;
struct adc081c *adc;
const struct adcxx1c_model *model;
@@ -235,7 +235,7 @@ static struct i2c_driver adc081c_driver = {
.of_match_table = adc081c_of_match,
.acpi_match_table = adc081c_acpi_match,
},
- .probe = adc081c_probe,
+ .probe_new = adc081c_probe,
.id_table = adc081c_id,
};
module_i2c_driver(adc081c_driver);
diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c
index 622fd384983c..b3d5b9b7255b 100644
--- a/drivers/iio/adc/ti-adc128s052.c
+++ b/drivers/iio/adc/ti-adc128s052.c
@@ -181,13 +181,13 @@ static int adc128_probe(struct spi_device *spi)
}
static const struct of_device_id adc128_of_match[] = {
- { .compatible = "ti,adc128s052", },
- { .compatible = "ti,adc122s021", },
- { .compatible = "ti,adc122s051", },
- { .compatible = "ti,adc122s101", },
- { .compatible = "ti,adc124s021", },
- { .compatible = "ti,adc124s051", },
- { .compatible = "ti,adc124s101", },
+ { .compatible = "ti,adc128s052", .data = (void*)0L, },
+ { .compatible = "ti,adc122s021", .data = (void*)1L, },
+ { .compatible = "ti,adc122s051", .data = (void*)1L, },
+ { .compatible = "ti,adc122s101", .data = (void*)1L, },
+ { .compatible = "ti,adc124s021", .data = (void*)2L, },
+ { .compatible = "ti,adc124s051", .data = (void*)2L, },
+ { .compatible = "ti,adc124s101", .data = (void*)2L, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, adc128_of_match);
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 8bceba694026..56af5e148802 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -974,9 +974,9 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode)
mode << ADS1015_CFG_MOD_SHIFT);
}
-static int ads1015_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ads1015_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct ads1015_chip_data *chip;
struct iio_dev *indio_dev;
struct ads1015_data *data;
@@ -1195,7 +1195,7 @@ static struct i2c_driver ads1015_driver = {
.of_match_table = ads1015_of_match,
.pm = &ads1015_pm_ops,
},
- .probe = ads1015_probe,
+ .probe_new = ads1015_probe,
.remove = ads1015_remove,
.id_table = ads1015_id,
};
diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c
index 5235a93f28bc..fcfc46254313 100644
--- a/drivers/iio/adc/ti-ads131e08.c
+++ b/drivers/iio/adc/ti-ads131e08.c
@@ -807,6 +807,8 @@ static int ads131e08_probe(struct spi_device *spi)
int ret;
info = device_get_match_data(&spi->dev);
+ if (!info)
+ info = (void *)spi_get_device_id(spi)->driver_data;
if (!info) {
dev_err(&spi->dev, "failed to get match data\n");
return -ENODEV;
@@ -926,12 +928,21 @@ static const struct of_device_id ads131e08_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ads131e08_of_match);
+static const struct spi_device_id ads131e08_ids[] = {
+ { "ads131e04", (kernel_ulong_t)&ads131e08_info_tbl[ads131e04] },
+ { "ads131e06", (kernel_ulong_t)&ads131e08_info_tbl[ads131e06] },
+ { "ads131e08", (kernel_ulong_t)&ads131e08_info_tbl[ads131e08] },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ads131e08_ids);
+
static struct spi_driver ads131e08_driver = {
.driver = {
.name = "ads131e08",
.of_match_table = ads131e08_of_match,
},
.probe = ads131e08_probe,
+ .id_table = ads131e08_ids,
};
module_spi_driver(ads131e08_driver);
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index c6b16cf6e367..ae31aafd2653 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -7,6 +7,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
@@ -156,6 +157,9 @@ struct vf610_adc {
void __iomem *regs;
struct clk *clk;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
+
u32 vref_uv;
u32 value;
struct regulator *vref;
@@ -467,11 +471,11 @@ static int vf610_set_conversion_mode(struct iio_dev *indio_dev,
{
struct vf610_adc *info = iio_priv(indio_dev);
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&info->lock);
info->adc_feature.conv_mode = mode;
vf610_adc_calculate_rates(info);
vf610_adc_hw_init(info);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
return 0;
}
@@ -622,6 +626,58 @@ static const struct attribute_group vf610_attribute_group = {
.attrs = vf610_attributes,
};
+static int vf610_read_sample(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct vf610_adc *info = iio_priv(indio_dev);
+ unsigned int hc_cfg;
+ int ret;
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&info->lock);
+ reinit_completion(&info->completion);
+ hc_cfg = VF610_ADC_ADCHC(chan->channel);
+ hc_cfg |= VF610_ADC_AIEN;
+ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
+ ret = wait_for_completion_interruptible_timeout(&info->completion,
+ VF610_ADC_TIMEOUT);
+ if (ret == 0) {
+ ret = -ETIMEDOUT;
+ goto out_unlock;
+ }
+
+ if (ret < 0)
+ goto out_unlock;
+
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ *val = info->value;
+ break;
+ case IIO_TEMP:
+ /*
+ * Calculate in degree Celsius times 1000
+ * Using the typical sensor slope of 1.84 mV/°C
+ * and VREFH_ADC at 3.3V, V at 25°C of 699 mV
+ */
+ *val = 25000 - ((int)info->value - VF610_VTEMP25_3V3) *
+ 1000000 / VF610_TEMP_SLOPE_COEFF;
+
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+out_unlock:
+ mutex_unlock(&info->lock);
+ iio_device_release_direct_mode(indio_dev);
+
+ return ret;
+}
+
static int vf610_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
@@ -629,53 +685,15 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
long mask)
{
struct vf610_adc *info = iio_priv(indio_dev);
- unsigned int hc_cfg;
long ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
- mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
- mutex_unlock(&indio_dev->mlock);
- return -EBUSY;
- }
-
- reinit_completion(&info->completion);
- hc_cfg = VF610_ADC_ADCHC(chan->channel);
- hc_cfg |= VF610_ADC_AIEN;
- writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
- ret = wait_for_completion_interruptible_timeout
- (&info->completion, VF610_ADC_TIMEOUT);
- if (ret == 0) {
- mutex_unlock(&indio_dev->mlock);
- return -ETIMEDOUT;
- }
- if (ret < 0) {
- mutex_unlock(&indio_dev->mlock);
+ ret = vf610_read_sample(indio_dev, chan, val);
+ if (ret < 0)
return ret;
- }
- switch (chan->type) {
- case IIO_VOLTAGE:
- *val = info->value;
- break;
- case IIO_TEMP:
- /*
- * Calculate in degree Celsius times 1000
- * Using the typical sensor slope of 1.84 mV/°C
- * and VREFH_ADC at 3.3V, V at 25°C of 699 mV
- */
- *val = 25000 - ((int)info->value - VF610_VTEMP25_3V3) *
- 1000000 / VF610_TEMP_SLOPE_COEFF;
-
- break;
- default:
- mutex_unlock(&indio_dev->mlock);
- return -EINVAL;
- }
-
- mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@@ -878,6 +896,8 @@ static int vf610_adc_probe(struct platform_device *pdev)
goto error_iio_device_register;
}
+ mutex_init(&info->lock);
+
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register the device.\n");
diff --git a/drivers/iio/addac/Kconfig b/drivers/iio/addac/Kconfig
index fcf6d2269bfc..2843fcb70e24 100644
--- a/drivers/iio/addac/Kconfig
+++ b/drivers/iio/addac/Kconfig
@@ -5,6 +5,20 @@
menu "Analog to digital and digital to analog converters"
+config AD74115
+ tristate "Analog Devices AD74115H driver"
+ depends on GPIOLIB && SPI
+ select CRC8
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ select REGMAP_SPI
+ help
+ Say yes here to build support for Analog Devices AD74115H
+ single-channel software configurable input/output solution.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad74115.
+
config AD74413R
tristate "Analog Devices AD74412R/AD74413R driver"
depends on GPIOLIB && SPI
diff --git a/drivers/iio/addac/Makefile b/drivers/iio/addac/Makefile
index 17de20ef0d8e..577777276e43 100644
--- a/drivers/iio/addac/Makefile
+++ b/drivers/iio/addac/Makefile
@@ -4,5 +4,6 @@
#
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_AD74115) += ad74115.o
obj-$(CONFIG_AD74413R) += ad74413r.o
obj-$(CONFIG_STX104) += stx104.o
diff --git a/drivers/iio/addac/ad74115.c b/drivers/iio/addac/ad74115.c
new file mode 100644
index 000000000000..e6bc5eb3788d
--- /dev/null
+++ b/drivers/iio/addac/ad74115.c
@@ -0,0 +1,1943 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Analog Devices, Inc.
+ * Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/crc8.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+
+#include <asm/unaligned.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define AD74115_NAME "ad74115"
+
+#define AD74115_CH_FUNC_SETUP_REG 0x01
+
+#define AD74115_ADC_CONFIG_REG 0x02
+#define AD74115_ADC_CONFIG_CONV2_RATE_MASK GENMASK(15, 13)
+#define AD74115_ADC_CONFIG_CONV1_RATE_MASK GENMASK(12, 10)
+#define AD74115_ADC_CONFIG_CONV2_RANGE_MASK GENMASK(9, 7)
+#define AD74115_ADC_CONFIG_CONV1_RANGE_MASK GENMASK(6, 4)
+
+#define AD74115_PWR_OPTIM_CONFIG_REG 0x03
+
+#define AD74115_DIN_CONFIG1_REG 0x04
+#define AD74115_DIN_COMPARATOR_EN_MASK BIT(13)
+#define AD74115_DIN_SINK_MASK GENMASK(11, 7)
+#define AD74115_DIN_DEBOUNCE_MASK GENMASK(4, 0)
+
+#define AD74115_DIN_CONFIG2_REG 0x05
+#define AD74115_COMP_THRESH_MASK GENMASK(6, 0)
+
+#define AD74115_OUTPUT_CONFIG_REG 0x06
+#define AD74115_OUTPUT_SLEW_EN_MASK GENMASK(6, 5)
+#define AD74115_OUTPUT_SLEW_LIN_STEP_MASK GENMASK(4, 3)
+#define AD74115_OUTPUT_SLEW_LIN_RATE_MASK GENMASK(2, 1)
+
+#define AD74115_RTD3W4W_CONFIG_REG 0x07
+
+#define AD74115_BURNOUT_CONFIG_REG 0x0a
+#define AD74115_BURNOUT_EXT2_EN_MASK BIT(10)
+#define AD74115_BURNOUT_EXT1_EN_MASK BIT(5)
+#define AD74115_BURNOUT_VIOUT_EN_MASK BIT(0)
+
+#define AD74115_DAC_CODE_REG 0x0b
+
+#define AD74115_DAC_ACTIVE_REG 0x0d
+
+#define AD74115_GPIO_CONFIG_X_REG(x) (0x35 + (x))
+#define AD74115_GPIO_CONFIG_GPI_DATA BIT(5)
+#define AD74115_GPIO_CONFIG_GPO_DATA BIT(4)
+#define AD74115_GPIO_CONFIG_SELECT_MASK GENMASK(2, 0)
+
+#define AD74115_CHARGE_PUMP_REG 0x3a
+
+#define AD74115_ADC_CONV_CTRL_REG 0x3b
+#define AD74115_ADC_CONV_SEQ_MASK GENMASK(13, 12)
+
+#define AD74115_DIN_COMP_OUT_REG 0x40
+
+#define AD74115_LIVE_STATUS_REG 0x42
+#define AD74115_ADC_DATA_RDY_MASK BIT(3)
+
+#define AD74115_READ_SELECT_REG 0x64
+
+#define AD74115_CMD_KEY_REG 0x78
+#define AD74115_CMD_KEY_RESET1 0x15fa
+#define AD74115_CMD_KEY_RESET2 0xaf51
+
+#define AD74115_CRC_POLYNOMIAL 0x7
+DECLARE_CRC8_TABLE(ad74115_crc8_table);
+
+#define AD74115_ADC_CODE_MAX ((int)GENMASK(15, 0))
+#define AD74115_ADC_CODE_HALF (AD74115_ADC_CODE_MAX / 2)
+
+#define AD74115_DAC_VOLTAGE_MAX 12000
+#define AD74115_DAC_CURRENT_MAX 25
+#define AD74115_DAC_CODE_MAX ((int)GENMASK(13, 0))
+#define AD74115_DAC_CODE_HALF (AD74115_DAC_CODE_MAX / 2)
+
+#define AD74115_COMP_THRESH_MAX 98
+
+#define AD74115_SENSE_RESISTOR_OHMS 100
+#define AD74115_REF_RESISTOR_OHMS 2100
+
+#define AD74115_DIN_SINK_LOW_STEP 120
+#define AD74115_DIN_SINK_HIGH_STEP 240
+#define AD74115_DIN_SINK_MAX 31
+
+#define AD74115_FRAME_SIZE 4
+#define AD74115_GPIO_NUM 4
+
+#define AD74115_CONV_TIME_US 1000000
+
+enum ad74115_dac_ch {
+ AD74115_DAC_CH_MAIN,
+ AD74115_DAC_CH_COMPARATOR,
+};
+
+enum ad74115_adc_ch {
+ AD74115_ADC_CH_CONV1,
+ AD74115_ADC_CH_CONV2,
+ AD74115_ADC_CH_NUM
+};
+
+enum ad74115_ch_func {
+ AD74115_CH_FUNC_HIGH_IMPEDANCE,
+ AD74115_CH_FUNC_VOLTAGE_OUTPUT,
+ AD74115_CH_FUNC_CURRENT_OUTPUT,
+ AD74115_CH_FUNC_VOLTAGE_INPUT,
+ AD74115_CH_FUNC_CURRENT_INPUT_EXT_POWER,
+ AD74115_CH_FUNC_CURRENT_INPUT_LOOP_POWER,
+ AD74115_CH_FUNC_2_WIRE_RESISTANCE_INPUT,
+ AD74115_CH_FUNC_3_4_WIRE_RESISTANCE_INPUT,
+ AD74115_CH_FUNC_DIGITAL_INPUT_LOGIC,
+ AD74115_CH_FUNC_DIGITAL_INPUT_LOOP_POWER,
+ AD74115_CH_FUNC_CURRENT_OUTPUT_HART,
+ AD74115_CH_FUNC_CURRENT_INPUT_EXT_POWER_HART,
+ AD74115_CH_FUNC_CURRENT_INPUT_LOOP_POWER_HART,
+ AD74115_CH_FUNC_MAX = AD74115_CH_FUNC_CURRENT_INPUT_LOOP_POWER_HART,
+ AD74115_CH_FUNC_NUM
+};
+
+enum ad74115_adc_range {
+ AD74115_ADC_RANGE_12V,
+ AD74115_ADC_RANGE_12V_BIPOLAR,
+ AD74115_ADC_RANGE_2_5V_BIPOLAR,
+ AD74115_ADC_RANGE_2_5V_NEG,
+ AD74115_ADC_RANGE_2_5V,
+ AD74115_ADC_RANGE_0_625V,
+ AD74115_ADC_RANGE_104MV_BIPOLAR,
+ AD74115_ADC_RANGE_12V_OTHER,
+ AD74115_ADC_RANGE_MAX = AD74115_ADC_RANGE_12V_OTHER,
+ AD74115_ADC_RANGE_NUM
+};
+
+enum ad74115_adc_conv_seq {
+ AD74115_ADC_CONV_SEQ_STANDBY = 0b00,
+ AD74115_ADC_CONV_SEQ_SINGLE = 0b01,
+ AD74115_ADC_CONV_SEQ_CONTINUOUS = 0b10,
+};
+
+enum ad74115_din_threshold_mode {
+ AD74115_DIN_THRESHOLD_MODE_AVDD,
+ AD74115_DIN_THRESHOLD_MODE_FIXED,
+ AD74115_DIN_THRESHOLD_MODE_MAX = AD74115_DIN_THRESHOLD_MODE_FIXED,
+};
+
+enum ad74115_slew_mode {
+ AD74115_SLEW_MODE_DISABLED,
+ AD74115_SLEW_MODE_LINEAR,
+ AD74115_SLEW_MODE_HART,
+};
+
+enum ad74115_slew_step {
+ AD74115_SLEW_STEP_0_8_PERCENT,
+ AD74115_SLEW_STEP_1_5_PERCENT,
+ AD74115_SLEW_STEP_6_1_PERCENT,
+ AD74115_SLEW_STEP_22_2_PERCENT,
+};
+
+enum ad74115_slew_rate {
+ AD74115_SLEW_RATE_4KHZ,
+ AD74115_SLEW_RATE_64KHZ,
+ AD74115_SLEW_RATE_150KHZ,
+ AD74115_SLEW_RATE_240KHZ,
+};
+
+enum ad74115_gpio_config {
+ AD74115_GPIO_CONFIG_OUTPUT_BUFFERED = 0b010,
+ AD74115_GPIO_CONFIG_INPUT = 0b011,
+};
+
+enum ad74115_gpio_mode {
+ AD74115_GPIO_MODE_LOGIC = 1,
+ AD74115_GPIO_MODE_SPECIAL = 2,
+};
+
+struct ad74115_channels {
+ struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+struct ad74115_state {
+ struct spi_device *spi;
+ struct regmap *regmap;
+ struct iio_trigger *trig;
+ struct regulator *avdd;
+
+ /*
+ * Synchronize consecutive operations when doing a one-shot
+ * conversion and when updating the ADC samples SPI message.
+ */
+ struct mutex lock;
+ struct gpio_chip gc;
+ struct gpio_chip comp_gc;
+ int irq;
+
+ unsigned int avdd_mv;
+ unsigned long gpio_valid_mask;
+ bool dac_bipolar;
+ bool dac_hart_slew;
+ bool rtd_mode_4_wire;
+ enum ad74115_ch_func ch_func;
+ enum ad74115_din_threshold_mode din_threshold_mode;
+
+ struct completion adc_data_completion;
+ struct spi_message adc_samples_msg;
+ struct spi_transfer adc_samples_xfer[AD74115_ADC_CH_NUM + 1];
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ u8 reg_tx_buf[AD74115_FRAME_SIZE] __aligned(IIO_DMA_MINALIGN);
+ u8 reg_rx_buf[AD74115_FRAME_SIZE];
+ u8 adc_samples_tx_buf[AD74115_FRAME_SIZE * AD74115_ADC_CH_NUM];
+ u8 adc_samples_rx_buf[AD74115_FRAME_SIZE * AD74115_ADC_CH_NUM];
+};
+
+struct ad74115_fw_prop {
+ const char *name;
+ bool is_boolean;
+ bool negate;
+ unsigned int max;
+ unsigned int reg;
+ unsigned int mask;
+ const unsigned int *lookup_tbl;
+ unsigned int lookup_tbl_len;
+};
+
+#define AD74115_FW_PROP(_name, _max, _reg, _mask) \
+{ \
+ .name = (_name), \
+ .max = (_max), \
+ .reg = (_reg), \
+ .mask = (_mask), \
+}
+
+#define AD74115_FW_PROP_TBL(_name, _tbl, _reg, _mask) \
+{ \
+ .name = (_name), \
+ .reg = (_reg), \
+ .mask = (_mask), \
+ .lookup_tbl = (_tbl), \
+ .lookup_tbl_len = ARRAY_SIZE(_tbl), \
+}
+
+#define AD74115_FW_PROP_BOOL(_name, _reg, _mask) \
+{ \
+ .name = (_name), \
+ .is_boolean = true, \
+ .reg = (_reg), \
+ .mask = (_mask), \
+}
+
+#define AD74115_FW_PROP_BOOL_NEG(_name, _reg, _mask) \
+{ \
+ .name = (_name), \
+ .is_boolean = true, \
+ .negate = true, \
+ .reg = (_reg), \
+ .mask = (_mask), \
+}
+
+static const int ad74115_dac_rate_tbl[] = {
+ 0,
+ 4 * 8,
+ 4 * 15,
+ 4 * 61,
+ 4 * 222,
+ 64 * 8,
+ 64 * 15,
+ 64 * 61,
+ 64 * 222,
+ 150 * 8,
+ 150 * 15,
+ 150 * 61,
+ 150 * 222,
+ 240 * 8,
+ 240 * 15,
+ 240 * 61,
+ 240 * 222,
+};
+
+static const unsigned int ad74115_dac_rate_step_tbl[][3] = {
+ { AD74115_SLEW_MODE_DISABLED },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_0_8_PERCENT, AD74115_SLEW_RATE_4KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_1_5_PERCENT, AD74115_SLEW_RATE_4KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_6_1_PERCENT, AD74115_SLEW_RATE_4KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_22_2_PERCENT, AD74115_SLEW_RATE_4KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_0_8_PERCENT, AD74115_SLEW_RATE_64KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_1_5_PERCENT, AD74115_SLEW_RATE_64KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_6_1_PERCENT, AD74115_SLEW_RATE_64KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_22_2_PERCENT, AD74115_SLEW_RATE_64KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_0_8_PERCENT, AD74115_SLEW_RATE_150KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_1_5_PERCENT, AD74115_SLEW_RATE_150KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_6_1_PERCENT, AD74115_SLEW_RATE_150KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_22_2_PERCENT, AD74115_SLEW_RATE_150KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_0_8_PERCENT, AD74115_SLEW_RATE_240KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_1_5_PERCENT, AD74115_SLEW_RATE_240KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_6_1_PERCENT, AD74115_SLEW_RATE_240KHZ },
+ { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_22_2_PERCENT, AD74115_SLEW_RATE_240KHZ },
+};
+
+static const unsigned int ad74115_rtd_excitation_current_ua_tbl[] = {
+ 250, 500, 750, 1000
+};
+
+static const unsigned int ad74115_burnout_current_na_tbl[] = {
+ 0, 50, 0, 500, 1000, 0, 10000, 0
+};
+
+static const unsigned int ad74115_viout_burnout_current_na_tbl[] = {
+ 0, 0, 0, 0, 1000, 0, 10000, 0
+};
+
+static const unsigned int ad74115_gpio_mode_tbl[] = {
+ 0, 0, 0, 1, 2, 3, 4, 5
+};
+
+static const unsigned int ad74115_adc_conv_rate_tbl[] = {
+ 10, 20, 1200, 4800, 9600
+};
+
+static const unsigned int ad74115_debounce_tbl[] = {
+ 0, 13, 18, 24, 32, 42, 56, 75,
+ 100, 130, 180, 240, 320, 420, 560, 750,
+ 1000, 1300, 1800, 2400, 3200, 4200, 5600, 7500,
+ 10000, 13000, 18000, 24000, 32000, 42000, 56000, 75000,
+};
+
+static const unsigned int ad74115_adc_ch_data_regs_tbl[] = {
+ [AD74115_ADC_CH_CONV1] = 0x44,
+ [AD74115_ADC_CH_CONV2] = 0x46,
+};
+
+static const unsigned int ad74115_adc_ch_en_bit_tbl[] = {
+ [AD74115_ADC_CH_CONV1] = BIT(0),
+ [AD74115_ADC_CH_CONV2] = BIT(1),
+};
+
+static const bool ad74115_adc_bipolar_tbl[AD74115_ADC_RANGE_NUM] = {
+ [AD74115_ADC_RANGE_12V_BIPOLAR] = true,
+ [AD74115_ADC_RANGE_2_5V_BIPOLAR] = true,
+ [AD74115_ADC_RANGE_104MV_BIPOLAR] = true,
+};
+
+static const unsigned int ad74115_adc_conv_mul_tbl[AD74115_ADC_RANGE_NUM] = {
+ [AD74115_ADC_RANGE_12V] = 12000,
+ [AD74115_ADC_RANGE_12V_BIPOLAR] = 24000,
+ [AD74115_ADC_RANGE_2_5V_BIPOLAR] = 5000,
+ [AD74115_ADC_RANGE_2_5V_NEG] = 2500,
+ [AD74115_ADC_RANGE_2_5V] = 2500,
+ [AD74115_ADC_RANGE_0_625V] = 625,
+ [AD74115_ADC_RANGE_104MV_BIPOLAR] = 208,
+ [AD74115_ADC_RANGE_12V_OTHER] = 12000,
+};
+
+static const unsigned int ad74115_adc_gain_tbl[AD74115_ADC_RANGE_NUM][2] = {
+ [AD74115_ADC_RANGE_12V] = { 5, 24 },
+ [AD74115_ADC_RANGE_12V_BIPOLAR] = { 5, 24 },
+ [AD74115_ADC_RANGE_2_5V_BIPOLAR] = { 1, 1 },
+ [AD74115_ADC_RANGE_2_5V_NEG] = { 1, 1 },
+ [AD74115_ADC_RANGE_2_5V] = { 1, 1 },
+ [AD74115_ADC_RANGE_0_625V] = { 4, 1 },
+ [AD74115_ADC_RANGE_104MV_BIPOLAR] = { 24, 1 },
+ [AD74115_ADC_RANGE_12V_OTHER] = { 5, 24 },
+};
+
+static const int ad74115_adc_range_tbl[AD74115_ADC_RANGE_NUM][2] = {
+ [AD74115_ADC_RANGE_12V] = { 0, 12000000 },
+ [AD74115_ADC_RANGE_12V_BIPOLAR] = { -12000000, 12000000 },
+ [AD74115_ADC_RANGE_2_5V_BIPOLAR] = { -2500000, 2500000 },
+ [AD74115_ADC_RANGE_2_5V_NEG] = { -2500000, 0 },
+ [AD74115_ADC_RANGE_2_5V] = { 0, 2500000 },
+ [AD74115_ADC_RANGE_0_625V] = { 0, 625000 },
+ [AD74115_ADC_RANGE_104MV_BIPOLAR] = { -104000, 104000 },
+ [AD74115_ADC_RANGE_12V_OTHER] = { 0, 12000000 },
+};
+
+static int _ad74115_find_tbl_index(const unsigned int *tbl, unsigned int tbl_len,
+ unsigned int val, unsigned int *index)
+{
+ unsigned int i;
+
+ for (i = 0; i < tbl_len; i++)
+ if (val == tbl[i]) {
+ *index = i;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+#define ad74115_find_tbl_index(tbl, val, index) \
+ _ad74115_find_tbl_index(tbl, ARRAY_SIZE(tbl), val, index)
+
+static int ad74115_crc(u8 *buf)
+{
+ return crc8(ad74115_crc8_table, buf, 3, 0);
+}
+
+static void ad74115_format_reg_write(u8 reg, u16 val, u8 *buf)
+{
+ buf[0] = reg;
+ put_unaligned_be16(val, &buf[1]);
+ buf[3] = ad74115_crc(buf);
+}
+
+static int ad74115_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct ad74115_state *st = context;
+
+ ad74115_format_reg_write(reg, val, st->reg_tx_buf);
+
+ return spi_write(st->spi, st->reg_tx_buf, AD74115_FRAME_SIZE);
+}
+
+static int ad74115_crc_check(struct ad74115_state *st, u8 *buf)
+{
+ struct device *dev = &st->spi->dev;
+ u8 expected_crc = ad74115_crc(buf);
+
+ if (buf[3] != expected_crc) {
+ dev_err(dev, "Bad CRC %02x for %02x%02x%02x, expected %02x\n",
+ buf[3], buf[0], buf[1], buf[2], expected_crc);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ad74115_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct ad74115_state *st = context;
+ struct spi_transfer reg_read_xfer[] = {
+ {
+ .tx_buf = st->reg_tx_buf,
+ .len = sizeof(st->reg_tx_buf),
+ .cs_change = 1,
+ },
+ {
+ .rx_buf = st->reg_rx_buf,
+ .len = sizeof(st->reg_rx_buf),
+ },
+ };
+ int ret;
+
+ ad74115_format_reg_write(AD74115_READ_SELECT_REG, reg, st->reg_tx_buf);
+
+ ret = spi_sync_transfer(st->spi, reg_read_xfer, ARRAY_SIZE(reg_read_xfer));
+ if (ret)
+ return ret;
+
+ ret = ad74115_crc_check(st, st->reg_rx_buf);
+ if (ret)
+ return ret;
+
+ *val = get_unaligned_be16(&st->reg_rx_buf[1]);
+
+ return 0;
+}
+
+static const struct regmap_config ad74115_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .reg_read = ad74115_reg_read,
+ .reg_write = ad74115_reg_write,
+};
+
+static int ad74115_gpio_config_set(struct ad74115_state *st, unsigned int offset,
+ enum ad74115_gpio_config cfg)
+{
+ return regmap_update_bits(st->regmap, AD74115_GPIO_CONFIG_X_REG(offset),
+ AD74115_GPIO_CONFIG_SELECT_MASK,
+ FIELD_PREP(AD74115_GPIO_CONFIG_SELECT_MASK, cfg));
+}
+
+static int ad74115_gpio_init_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask,
+ unsigned int ngpios)
+{
+ struct ad74115_state *st = gpiochip_get_data(gc);
+
+ *valid_mask = st->gpio_valid_mask;
+
+ return 0;
+}
+
+static int ad74115_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ struct ad74115_state *st = gpiochip_get_data(gc);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->regmap, AD74115_GPIO_CONFIG_X_REG(offset), &val);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(AD74115_GPIO_CONFIG_SELECT_MASK, val) == AD74115_GPIO_CONFIG_INPUT;
+}
+
+static int ad74115_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+{
+ struct ad74115_state *st = gpiochip_get_data(gc);
+
+ return ad74115_gpio_config_set(st, offset, AD74115_GPIO_CONFIG_INPUT);
+}
+
+static int ad74115_gpio_direction_output(struct gpio_chip *gc, unsigned int offset,
+ int value)
+{
+ struct ad74115_state *st = gpiochip_get_data(gc);
+
+ return ad74115_gpio_config_set(st, offset, AD74115_GPIO_CONFIG_OUTPUT_BUFFERED);
+}
+
+static int ad74115_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct ad74115_state *st = gpiochip_get_data(gc);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->regmap, AD74115_GPIO_CONFIG_X_REG(offset), &val);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(AD74115_GPIO_CONFIG_GPI_DATA, val);
+}
+
+static void ad74115_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ struct ad74115_state *st = gpiochip_get_data(gc);
+ struct device *dev = &st->spi->dev;
+ int ret;
+
+ ret = regmap_update_bits(st->regmap, AD74115_GPIO_CONFIG_X_REG(offset),
+ AD74115_GPIO_CONFIG_GPO_DATA,
+ FIELD_PREP(AD74115_GPIO_CONFIG_GPO_DATA, value));
+ if (ret)
+ dev_err(dev, "Failed to set GPIO %u output value, err: %d\n",
+ offset, ret);
+}
+
+static int ad74115_set_comp_debounce(struct ad74115_state *st, unsigned int val)
+{
+ unsigned int len = ARRAY_SIZE(ad74115_debounce_tbl);
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ if (val <= ad74115_debounce_tbl[i])
+ break;
+
+ if (i == len)
+ i = len - 1;
+
+ return regmap_update_bits(st->regmap, AD74115_DIN_CONFIG1_REG,
+ AD74115_DIN_DEBOUNCE_MASK,
+ FIELD_PREP(AD74115_DIN_DEBOUNCE_MASK, val));
+}
+
+static int ad74115_comp_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_IN;
+}
+
+static int ad74115_comp_gpio_set_config(struct gpio_chip *chip,
+ unsigned int offset,
+ unsigned long config)
+{
+ struct ad74115_state *st = gpiochip_get_data(chip);
+ u32 param = pinconf_to_config_param(config);
+ u32 arg = pinconf_to_config_argument(config);
+
+ switch (param) {
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ return ad74115_set_comp_debounce(st, arg);
+ default:
+ return -ENOTSUPP;
+ }
+}
+
+static int ad74115_comp_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct ad74115_state *st = gpiochip_get_data(chip);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->regmap, AD74115_DIN_COMP_OUT_REG, &val);
+ if (ret)
+ return ret;
+
+ return !!val;
+}
+
+static irqreturn_t ad74115_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad74115_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = spi_sync(st->spi, &st->adc_samples_msg);
+ if (ret)
+ goto out;
+
+ iio_push_to_buffers(indio_dev, st->adc_samples_rx_buf);
+
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ad74115_adc_data_interrupt(int irq, void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct ad74115_state *st = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev))
+ iio_trigger_poll(st->trig);
+ else
+ complete(&st->adc_data_completion);
+
+ return IRQ_HANDLED;
+}
+
+static int ad74115_set_adc_ch_en(struct ad74115_state *st,
+ enum ad74115_adc_ch channel, bool status)
+{
+ unsigned int mask = ad74115_adc_ch_en_bit_tbl[channel];
+
+ return regmap_update_bits(st->regmap, AD74115_ADC_CONV_CTRL_REG, mask,
+ status ? mask : 0);
+}
+
+static int ad74115_set_adc_conv_seq(struct ad74115_state *st,
+ enum ad74115_adc_conv_seq conv_seq)
+{
+ return regmap_update_bits(st->regmap, AD74115_ADC_CONV_CTRL_REG,
+ AD74115_ADC_CONV_SEQ_MASK,
+ FIELD_PREP(AD74115_ADC_CONV_SEQ_MASK, conv_seq));
+}
+
+static int ad74115_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *active_scan_mask)
+{
+ struct ad74115_state *st = iio_priv(indio_dev);
+ struct spi_transfer *xfer = st->adc_samples_xfer;
+ u8 *rx_buf = st->adc_samples_rx_buf;
+ u8 *tx_buf = st->adc_samples_tx_buf;
+ unsigned int i;
+ int ret = 0;
+
+ mutex_lock(&st->lock);
+
+ spi_message_init(&st->adc_samples_msg);
+
+ for_each_clear_bit(i, active_scan_mask, AD74115_ADC_CH_NUM) {
+ ret = ad74115_set_adc_ch_en(st, i, false);
+ if (ret)
+ goto out;
+ }
+
+ /*
+ * The read select register is used to select which register's value
+ * will be sent by the slave on the next SPI frame.
+ *
+ * Create an SPI message that, on each step, writes to the read select
+ * register to select the ADC result of the next enabled channel, and
+ * reads the ADC result of the previous enabled channel.
+ *
+ * Example:
+ * W: [WCH1] [WCH2] [WCH2] [WCH3] [ ]
+ * R: [ ] [RCH1] [RCH2] [RCH3] [RCH4]
+ */
+ for_each_set_bit(i, active_scan_mask, AD74115_ADC_CH_NUM) {
+ ret = ad74115_set_adc_ch_en(st, i, true);
+ if (ret)
+ goto out;
+
+ if (xfer == st->adc_samples_xfer)
+ xfer->rx_buf = NULL;
+ else
+ xfer->rx_buf = rx_buf;
+
+ xfer->tx_buf = tx_buf;
+ xfer->len = AD74115_FRAME_SIZE;
+ xfer->cs_change = 1;
+
+ ad74115_format_reg_write(AD74115_READ_SELECT_REG,
+ ad74115_adc_ch_data_regs_tbl[i], tx_buf);
+
+ spi_message_add_tail(xfer, &st->adc_samples_msg);
+
+ tx_buf += AD74115_FRAME_SIZE;
+ if (xfer != st->adc_samples_xfer)
+ rx_buf += AD74115_FRAME_SIZE;
+ xfer++;
+ }
+
+ xfer->rx_buf = rx_buf;
+ xfer->tx_buf = NULL;
+ xfer->len = AD74115_FRAME_SIZE;
+ xfer->cs_change = 0;
+
+ spi_message_add_tail(xfer, &st->adc_samples_msg);
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int ad74115_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad74115_state *st = iio_priv(indio_dev);
+
+ return ad74115_set_adc_conv_seq(st, AD74115_ADC_CONV_SEQ_CONTINUOUS);
+}
+
+static int ad74115_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad74115_state *st = iio_priv(indio_dev);
+ unsigned int i;
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ ret = ad74115_set_adc_conv_seq(st, AD74115_ADC_CONV_SEQ_STANDBY);
+ if (ret)
+ goto out;
+
+ /*
+ * update_scan_mode() is not called in the disable path, disable all
+ * channels here.
+ */
+ for (i = 0; i < AD74115_ADC_CH_NUM; i++) {
+ ret = ad74115_set_adc_ch_en(st, i, false);
+ if (ret)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static const struct iio_buffer_setup_ops ad74115_buffer_ops = {
+ .postenable = &ad74115_buffer_postenable,
+ .predisable = &ad74115_buffer_predisable,
+};
+
+static const struct iio_trigger_ops ad74115_trigger_ops = {
+ .validate_device = iio_trigger_validate_own_device,
+};
+
+static int ad74115_get_adc_rate(struct ad74115_state *st,
+ enum ad74115_adc_ch channel, int *val)
+{
+ unsigned int i;
+ int ret;
+
+ ret = regmap_read(st->regmap, AD74115_ADC_CONFIG_REG, &i);
+ if (ret)
+ return ret;
+
+ if (channel == AD74115_ADC_CH_CONV1)
+ i = FIELD_GET(AD74115_ADC_CONFIG_CONV1_RATE_MASK, i);
+ else
+ i = FIELD_GET(AD74115_ADC_CONFIG_CONV2_RATE_MASK, i);
+
+ *val = ad74115_adc_conv_rate_tbl[i];
+
+ return IIO_VAL_INT;
+}
+
+static int _ad74115_get_adc_code(struct ad74115_state *st,
+ enum ad74115_adc_ch channel, int *val)
+{
+ unsigned int uval;
+ int ret;
+
+ reinit_completion(&st->adc_data_completion);
+
+ ret = ad74115_set_adc_ch_en(st, channel, true);
+ if (ret)
+ return ret;
+
+ ret = ad74115_set_adc_conv_seq(st, AD74115_ADC_CONV_SEQ_SINGLE);
+ if (ret)
+ return ret;
+
+ if (st->irq) {
+ ret = wait_for_completion_timeout(&st->adc_data_completion,
+ msecs_to_jiffies(1000));
+ if (!ret)
+ return -ETIMEDOUT;
+ } else {
+ unsigned int regval, wait_time;
+ int rate;
+
+ ret = ad74115_get_adc_rate(st, channel, &rate);
+ if (ret < 0)
+ return ret;
+
+ wait_time = DIV_ROUND_CLOSEST(AD74115_CONV_TIME_US, rate);
+
+ ret = regmap_read_poll_timeout(st->regmap, AD74115_LIVE_STATUS_REG,
+ regval, regval & AD74115_ADC_DATA_RDY_MASK,
+ wait_time, 5 * wait_time);
+ if (ret)
+ return ret;
+
+ /*
+ * The ADC_DATA_RDY bit is W1C.
+ * See datasheet page 98, Table 62. Bit Descriptions for
+ * LIVE_STATUS.
+ * Although the datasheet mentions that the bit will auto-clear
+ * when writing to the ADC_CONV_CTRL register, this does not
+ * seem to happen.
+ */
+ ret = regmap_write_bits(st->regmap, AD74115_LIVE_STATUS_REG,
+ AD74115_ADC_DATA_RDY_MASK,
+ FIELD_PREP(AD74115_ADC_DATA_RDY_MASK, 1));
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_read(st->regmap, ad74115_adc_ch_data_regs_tbl[channel], &uval);
+ if (ret)
+ return ret;
+
+ ret = ad74115_set_adc_conv_seq(st, AD74115_ADC_CONV_SEQ_STANDBY);
+ if (ret)
+ return ret;
+
+ ret = ad74115_set_adc_ch_en(st, channel, false);
+ if (ret)
+ return ret;
+
+ *val = uval;
+
+ return IIO_VAL_INT;
+}
+
+static int ad74115_get_adc_code(struct iio_dev *indio_dev,
+ enum ad74115_adc_ch channel, int *val)
+{
+ struct ad74115_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&st->lock);
+ ret = _ad74115_get_adc_code(st, channel, val);
+ mutex_unlock(&st->lock);
+
+ iio_device_release_direct_mode(indio_dev);
+
+ return ret;
+}
+
+static int ad74115_adc_code_to_resistance(int code, int *val, int *val2)
+{
+ if (code == AD74115_ADC_CODE_MAX)
+ code--;
+
+ *val = code * AD74115_REF_RESISTOR_OHMS;
+ *val2 = AD74115_ADC_CODE_MAX - code;
+
+ return IIO_VAL_FRACTIONAL;
+}
+
+static int ad74115_set_dac_code(struct ad74115_state *st,
+ enum ad74115_dac_ch channel, int val)
+{
+ if (val < 0)
+ return -EINVAL;
+
+ if (channel == AD74115_DAC_CH_COMPARATOR) {
+ if (val > AD74115_COMP_THRESH_MAX)
+ return -EINVAL;
+
+ return regmap_update_bits(st->regmap, AD74115_DIN_CONFIG2_REG,
+ AD74115_COMP_THRESH_MASK,
+ FIELD_PREP(AD74115_COMP_THRESH_MASK, val));
+ }
+
+ if (val > AD74115_DAC_CODE_MAX)
+ return -EINVAL;
+
+ return regmap_write(st->regmap, AD74115_DAC_CODE_REG, val);
+}
+
+static int ad74115_get_dac_code(struct ad74115_state *st,
+ enum ad74115_dac_ch channel, int *val)
+{
+ unsigned int uval;
+ int ret;
+
+ if (channel == AD74115_DAC_CH_COMPARATOR)
+ return -EINVAL;
+
+ ret = regmap_read(st->regmap, AD74115_DAC_ACTIVE_REG, &uval);
+ if (ret)
+ return ret;
+
+ *val = uval;
+
+ return IIO_VAL_INT;
+}
+
+static int ad74115_set_adc_rate(struct ad74115_state *st,
+ enum ad74115_adc_ch channel, int val)
+{
+ unsigned int i;
+ int ret;
+
+ ret = ad74115_find_tbl_index(ad74115_adc_conv_rate_tbl, val, &i);
+ if (ret)
+ return ret;
+
+ if (channel == AD74115_ADC_CH_CONV1)
+ return regmap_update_bits(st->regmap, AD74115_ADC_CONFIG_REG,
+ AD74115_ADC_CONFIG_CONV1_RATE_MASK,
+ FIELD_PREP(AD74115_ADC_CONFIG_CONV1_RATE_MASK, i));
+
+ return regmap_update_bits(st->regmap, AD74115_ADC_CONFIG_REG,
+ AD74115_ADC_CONFIG_CONV2_RATE_MASK,
+ FIELD_PREP(AD74115_ADC_CONFIG_CONV2_RATE_MASK, i));
+}
+
+static int ad74115_get_dac_rate(struct ad74115_state *st, int *val)
+{
+ unsigned int i, en_val, step_val, rate_val, tmp;
+ int ret;
+
+ ret = regmap_read(st->regmap, AD74115_OUTPUT_CONFIG_REG, &tmp);
+ if (ret)
+ return ret;
+
+ en_val = FIELD_GET(AD74115_OUTPUT_SLEW_EN_MASK, tmp);
+ step_val = FIELD_GET(AD74115_OUTPUT_SLEW_LIN_STEP_MASK, tmp);
+ rate_val = FIELD_GET(AD74115_OUTPUT_SLEW_LIN_RATE_MASK, tmp);
+
+ for (i = 0; i < ARRAY_SIZE(ad74115_dac_rate_step_tbl); i++)
+ if (en_val == ad74115_dac_rate_step_tbl[i][0] &&
+ step_val == ad74115_dac_rate_step_tbl[i][1] &&
+ rate_val == ad74115_dac_rate_step_tbl[i][2])
+ break;
+
+ if (i == ARRAY_SIZE(ad74115_dac_rate_step_tbl))
+ return -EINVAL;
+
+ *val = ad74115_dac_rate_tbl[i];
+
+ return IIO_VAL_INT;
+}
+
+static int ad74115_set_dac_rate(struct ad74115_state *st, int val)
+{
+ unsigned int i, en_val, step_val, rate_val, mask, tmp;
+ int ret;
+
+ ret = ad74115_find_tbl_index(ad74115_dac_rate_tbl, val, &i);
+ if (ret)
+ return ret;
+
+ en_val = ad74115_dac_rate_step_tbl[i][0];
+ step_val = ad74115_dac_rate_step_tbl[i][1];
+ rate_val = ad74115_dac_rate_step_tbl[i][2];
+
+ mask = AD74115_OUTPUT_SLEW_EN_MASK;
+ mask |= AD74115_OUTPUT_SLEW_LIN_STEP_MASK;
+ mask |= AD74115_OUTPUT_SLEW_LIN_RATE_MASK;
+
+ tmp = FIELD_PREP(AD74115_OUTPUT_SLEW_EN_MASK, en_val);
+ tmp |= FIELD_PREP(AD74115_OUTPUT_SLEW_LIN_STEP_MASK, step_val);
+ tmp |= FIELD_PREP(AD74115_OUTPUT_SLEW_LIN_RATE_MASK, rate_val);
+
+ return regmap_update_bits(st->regmap, AD74115_OUTPUT_CONFIG_REG, mask, tmp);
+}
+
+static int ad74115_get_dac_scale(struct ad74115_state *st,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2)
+{
+ if (chan->channel == AD74115_DAC_CH_MAIN) {
+ if (chan->type == IIO_VOLTAGE) {
+ *val = AD74115_DAC_VOLTAGE_MAX;
+
+ if (st->dac_bipolar)
+ *val *= 2;
+
+ } else {
+ *val = AD74115_DAC_CURRENT_MAX;
+ }
+
+ *val2 = AD74115_DAC_CODE_MAX;
+ } else {
+ if (st->din_threshold_mode == AD74115_DIN_THRESHOLD_MODE_AVDD) {
+ *val = 196 * st->avdd_mv;
+ *val2 = 10 * AD74115_COMP_THRESH_MAX;
+ } else {
+ *val = 49000;
+ *val2 = AD74115_COMP_THRESH_MAX;
+ }
+ }
+
+ return IIO_VAL_FRACTIONAL;
+}
+
+static int ad74115_get_dac_offset(struct ad74115_state *st,
+ struct iio_chan_spec const *chan, int *val)
+{
+ if (chan->channel == AD74115_DAC_CH_MAIN) {
+ if (chan->type == IIO_VOLTAGE && st->dac_bipolar)
+ *val = -AD74115_DAC_CODE_HALF;
+ else
+ *val = 0;
+ } else {
+ if (st->din_threshold_mode == AD74115_DIN_THRESHOLD_MODE_AVDD)
+ *val = -48;
+ else
+ *val = -38;
+ }
+
+ return IIO_VAL_INT;
+}
+
+static int ad74115_get_adc_range(struct ad74115_state *st,
+ enum ad74115_adc_ch channel, unsigned int *val)
+{
+ int ret;
+
+ ret = regmap_read(st->regmap, AD74115_ADC_CONFIG_REG, val);
+ if (ret)
+ return ret;
+
+ if (channel == AD74115_ADC_CH_CONV1)
+ *val = FIELD_GET(AD74115_ADC_CONFIG_CONV1_RANGE_MASK, *val);
+ else
+ *val = FIELD_GET(AD74115_ADC_CONFIG_CONV2_RANGE_MASK, *val);
+
+ return 0;
+}
+
+static int ad74115_get_adc_resistance_scale(struct ad74115_state *st,
+ unsigned int range,
+ int *val, int *val2)
+{
+ *val = ad74115_adc_gain_tbl[range][1] * AD74115_REF_RESISTOR_OHMS;
+ *val2 = ad74115_adc_gain_tbl[range][0];
+
+ if (ad74115_adc_bipolar_tbl[range])
+ *val2 *= AD74115_ADC_CODE_HALF;
+ else
+ *val2 *= AD74115_ADC_CODE_MAX;
+
+ return IIO_VAL_FRACTIONAL;
+}
+
+static int ad74115_get_adc_scale(struct ad74115_state *st,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2)
+{
+ unsigned int range;
+ int ret;
+
+ ret = ad74115_get_adc_range(st, chan->channel, &range);
+ if (ret)
+ return ret;
+
+ if (chan->type == IIO_RESISTANCE)
+ return ad74115_get_adc_resistance_scale(st, range, val, val2);
+
+ *val = ad74115_adc_conv_mul_tbl[range];
+ *val2 = AD74115_ADC_CODE_MAX;
+
+ if (chan->type == IIO_CURRENT)
+ *val2 *= AD74115_SENSE_RESISTOR_OHMS;
+
+ return IIO_VAL_FRACTIONAL;
+}
+
+static int ad74115_get_adc_resistance_offset(struct ad74115_state *st,
+ unsigned int range,
+ int *val, int *val2)
+{
+ unsigned int d = 10 * AD74115_REF_RESISTOR_OHMS
+ * ad74115_adc_gain_tbl[range][1];
+
+ *val = 5;
+
+ if (ad74115_adc_bipolar_tbl[range])
+ *val -= AD74115_ADC_CODE_HALF;
+
+ *val *= d;
+
+ if (!st->rtd_mode_4_wire) {
+ /* Add 0.2 Ohm to the final result for 3-wire RTD. */
+ unsigned int v = 2 * ad74115_adc_gain_tbl[range][0];
+
+ if (ad74115_adc_bipolar_tbl[range])
+ v *= AD74115_ADC_CODE_HALF;
+ else
+ v *= AD74115_ADC_CODE_MAX;
+
+ *val += v;
+ }
+
+ *val2 = d;
+
+ return IIO_VAL_FRACTIONAL;
+}
+
+static int ad74115_get_adc_offset(struct ad74115_state *st,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2)
+{
+ unsigned int range;
+ int ret;
+
+ ret = ad74115_get_adc_range(st, chan->channel, &range);
+ if (ret)
+ return ret;
+
+ if (chan->type == IIO_RESISTANCE)
+ return ad74115_get_adc_resistance_offset(st, range, val, val2);
+
+ if (ad74115_adc_bipolar_tbl[range])
+ *val = -AD74115_ADC_CODE_HALF;
+ else if (range == AD74115_ADC_RANGE_2_5V_NEG)
+ *val = -AD74115_ADC_CODE_MAX;
+ else
+ *val = 0;
+
+ return IIO_VAL_INT;
+}
+
+static int ad74115_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct ad74115_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ if (chan->output)
+ return ad74115_get_dac_code(st, chan->channel, val);
+
+ return ad74115_get_adc_code(indio_dev, chan->channel, val);
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = ad74115_get_adc_code(indio_dev, chan->channel, val);
+ if (ret)
+ return ret;
+
+ return ad74115_adc_code_to_resistance(*val, val, val2);
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->output)
+ return ad74115_get_dac_scale(st, chan, val, val2);
+
+ return ad74115_get_adc_scale(st, chan, val, val2);
+ case IIO_CHAN_INFO_OFFSET:
+ if (chan->output)
+ return ad74115_get_dac_offset(st, chan, val);
+
+ return ad74115_get_adc_offset(st, chan, val, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (chan->output)
+ return ad74115_get_dac_rate(st, val);
+
+ return ad74115_get_adc_rate(st, chan->channel, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad74115_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2,
+ long info)
+{
+ struct ad74115_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ if (!chan->output)
+ return -EINVAL;
+
+ return ad74115_set_dac_code(st, chan->channel, val);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (chan->output)
+ return ad74115_set_dac_rate(st, val);
+
+ return ad74115_set_adc_rate(st, chan->channel, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad74115_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length, long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (chan->output) {
+ *vals = ad74115_dac_rate_tbl;
+ *length = ARRAY_SIZE(ad74115_dac_rate_tbl);
+ } else {
+ *vals = ad74115_adc_conv_rate_tbl;
+ *length = ARRAY_SIZE(ad74115_adc_conv_rate_tbl);
+ }
+
+ *type = IIO_VAL_INT;
+
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad74115_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct ad74115_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static const struct iio_info ad74115_info = {
+ .read_raw = ad74115_read_raw,
+ .write_raw = ad74115_write_raw,
+ .read_avail = ad74115_read_avail,
+ .update_scan_mode = ad74115_update_scan_mode,
+ .debugfs_reg_access = ad74115_reg_access,
+};
+
+#define AD74115_DAC_CHANNEL(_type, index) \
+ { \
+ .type = (_type), \
+ .channel = (index), \
+ .indexed = 1, \
+ .output = 1, \
+ .scan_index = -1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
+ | BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_OFFSET), \
+ }
+
+#define _AD74115_ADC_CHANNEL(_type, index, extra_mask_separate) \
+ { \
+ .type = (_type), \
+ .channel = (index), \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
+ | BIT(IIO_CHAN_INFO_SAMP_FREQ) \
+ | (extra_mask_separate), \
+ .info_mask_separate_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 32, \
+ .shift = 8, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+#define AD74115_ADC_CHANNEL(_type, index) \
+ _AD74115_ADC_CHANNEL(_type, index, BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_OFFSET))
+
+static struct iio_chan_spec ad74115_voltage_input_channels[] = {
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_voltage_output_channels[] = {
+ AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_MAIN),
+ AD74115_ADC_CHANNEL(IIO_CURRENT, AD74115_ADC_CH_CONV1),
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_current_input_channels[] = {
+ AD74115_ADC_CHANNEL(IIO_CURRENT, AD74115_ADC_CH_CONV1),
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_current_output_channels[] = {
+ AD74115_DAC_CHANNEL(IIO_CURRENT, AD74115_DAC_CH_MAIN),
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_2_wire_resistance_input_channels[] = {
+ _AD74115_ADC_CHANNEL(IIO_RESISTANCE, AD74115_ADC_CH_CONV1,
+ BIT(IIO_CHAN_INFO_PROCESSED)),
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_3_4_wire_resistance_input_channels[] = {
+ AD74115_ADC_CHANNEL(IIO_RESISTANCE, AD74115_ADC_CH_CONV1),
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_digital_input_logic_channels[] = {
+ AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_COMPARATOR),
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_digital_input_loop_channels[] = {
+ AD74115_DAC_CHANNEL(IIO_CURRENT, AD74115_DAC_CH_MAIN),
+ AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_COMPARATOR),
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
+ AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+#define _AD74115_CHANNELS(_channels) \
+ { \
+ .channels = _channels, \
+ .num_channels = ARRAY_SIZE(_channels), \
+ }
+
+#define AD74115_CHANNELS(name) \
+ _AD74115_CHANNELS(ad74115_ ## name ## _channels)
+
+static const struct ad74115_channels ad74115_channels_map[AD74115_CH_FUNC_NUM] = {
+ [AD74115_CH_FUNC_HIGH_IMPEDANCE] = AD74115_CHANNELS(voltage_input),
+ [AD74115_CH_FUNC_VOLTAGE_INPUT] = AD74115_CHANNELS(voltage_input),
+
+ [AD74115_CH_FUNC_VOLTAGE_OUTPUT] = AD74115_CHANNELS(voltage_output),
+
+ [AD74115_CH_FUNC_CURRENT_INPUT_EXT_POWER] = AD74115_CHANNELS(current_input),
+ [AD74115_CH_FUNC_CURRENT_INPUT_LOOP_POWER] = AD74115_CHANNELS(current_input),
+ [AD74115_CH_FUNC_CURRENT_INPUT_EXT_POWER_HART] = AD74115_CHANNELS(current_input),
+ [AD74115_CH_FUNC_CURRENT_INPUT_LOOP_POWER_HART] = AD74115_CHANNELS(current_input),
+
+ [AD74115_CH_FUNC_CURRENT_OUTPUT] = AD74115_CHANNELS(current_output),
+ [AD74115_CH_FUNC_CURRENT_OUTPUT_HART] = AD74115_CHANNELS(current_output),
+
+ [AD74115_CH_FUNC_2_WIRE_RESISTANCE_INPUT] = AD74115_CHANNELS(2_wire_resistance_input),
+ [AD74115_CH_FUNC_3_4_WIRE_RESISTANCE_INPUT] = AD74115_CHANNELS(3_4_wire_resistance_input),
+
+ [AD74115_CH_FUNC_DIGITAL_INPUT_LOGIC] = AD74115_CHANNELS(digital_input_logic),
+
+ [AD74115_CH_FUNC_DIGITAL_INPUT_LOOP_POWER] = AD74115_CHANNELS(digital_input_loop),
+};
+
+#define AD74115_GPIO_MODE_FW_PROP(i) \
+{ \
+ .name = "adi,gpio" __stringify(i) "-mode", \
+ .reg = AD74115_GPIO_CONFIG_X_REG(i), \
+ .mask = AD74115_GPIO_CONFIG_SELECT_MASK, \
+ .lookup_tbl = ad74115_gpio_mode_tbl, \
+ .lookup_tbl_len = ARRAY_SIZE(ad74115_gpio_mode_tbl), \
+}
+
+static const struct ad74115_fw_prop ad74115_gpio_mode_fw_props[] = {
+ AD74115_GPIO_MODE_FW_PROP(0),
+ AD74115_GPIO_MODE_FW_PROP(1),
+ AD74115_GPIO_MODE_FW_PROP(2),
+ AD74115_GPIO_MODE_FW_PROP(3),
+};
+
+static const struct ad74115_fw_prop ad74115_din_threshold_mode_fw_prop =
+ AD74115_FW_PROP_BOOL("adi,digital-input-threshold-mode-fixed",
+ AD74115_DIN_CONFIG2_REG, BIT(7));
+
+static const struct ad74115_fw_prop ad74115_dac_bipolar_fw_prop =
+ AD74115_FW_PROP_BOOL("adi,dac-bipolar", AD74115_OUTPUT_CONFIG_REG, BIT(7));
+
+static const struct ad74115_fw_prop ad74115_ch_func_fw_prop =
+ AD74115_FW_PROP("adi,ch-func", AD74115_CH_FUNC_MAX,
+ AD74115_CH_FUNC_SETUP_REG, GENMASK(3, 0));
+
+static const struct ad74115_fw_prop ad74115_rtd_mode_fw_prop =
+ AD74115_FW_PROP_BOOL("adi,4-wire-rtd", AD74115_RTD3W4W_CONFIG_REG, BIT(3));
+
+static const struct ad74115_fw_prop ad74115_din_range_fw_prop =
+ AD74115_FW_PROP_BOOL("adi,digital-input-sink-range-high",
+ AD74115_DIN_CONFIG1_REG, BIT(12));
+
+static const struct ad74115_fw_prop ad74115_ext2_burnout_current_fw_prop =
+ AD74115_FW_PROP_TBL("adi,ext2-burnout-current-nanoamp",
+ ad74115_burnout_current_na_tbl,
+ AD74115_BURNOUT_CONFIG_REG, GENMASK(14, 12));
+
+static const struct ad74115_fw_prop ad74115_ext1_burnout_current_fw_prop =
+ AD74115_FW_PROP_TBL("adi,ext1-burnout-current-nanoamp",
+ ad74115_burnout_current_na_tbl,
+ AD74115_BURNOUT_CONFIG_REG, GENMASK(9, 7));
+
+static const struct ad74115_fw_prop ad74115_viout_burnout_current_fw_prop =
+ AD74115_FW_PROP_TBL("adi,viout-burnout-current-nanoamp",
+ ad74115_viout_burnout_current_na_tbl,
+ AD74115_BURNOUT_CONFIG_REG, GENMASK(4, 2));
+
+static const struct ad74115_fw_prop ad74115_fw_props[] = {
+ AD74115_FW_PROP("adi,conv2-mux", 3,
+ AD74115_ADC_CONFIG_REG, GENMASK(3, 2)),
+
+ AD74115_FW_PROP_BOOL_NEG("adi,sense-agnd-buffer-low-power",
+ AD74115_PWR_OPTIM_CONFIG_REG, BIT(4)),
+ AD74115_FW_PROP_BOOL_NEG("adi,lf-buffer-low-power",
+ AD74115_PWR_OPTIM_CONFIG_REG, BIT(3)),
+ AD74115_FW_PROP_BOOL_NEG("adi,hf-buffer-low-power",
+ AD74115_PWR_OPTIM_CONFIG_REG, BIT(2)),
+ AD74115_FW_PROP_BOOL_NEG("adi,ext2-buffer-low-power",
+ AD74115_PWR_OPTIM_CONFIG_REG, BIT(1)),
+ AD74115_FW_PROP_BOOL_NEG("adi,ext1-buffer-low-power",
+ AD74115_PWR_OPTIM_CONFIG_REG, BIT(0)),
+
+ AD74115_FW_PROP_BOOL("adi,comparator-invert",
+ AD74115_DIN_CONFIG1_REG, BIT(14)),
+ AD74115_FW_PROP_BOOL("adi,digital-input-debounce-mode-counter-reset",
+ AD74115_DIN_CONFIG1_REG, BIT(6)),
+
+ AD74115_FW_PROP_BOOL("adi,digital-input-unbuffered",
+ AD74115_DIN_CONFIG2_REG, BIT(10)),
+ AD74115_FW_PROP_BOOL("adi,digital-input-short-circuit-detection",
+ AD74115_DIN_CONFIG2_REG, BIT(9)),
+ AD74115_FW_PROP_BOOL("adi,digital-input-open-circuit-detection",
+ AD74115_DIN_CONFIG2_REG, BIT(8)),
+
+ AD74115_FW_PROP_BOOL("adi,dac-current-limit-low",
+ AD74115_OUTPUT_CONFIG_REG, BIT(0)),
+
+ AD74115_FW_PROP_BOOL("adi,3-wire-rtd-excitation-swap",
+ AD74115_RTD3W4W_CONFIG_REG, BIT(2)),
+ AD74115_FW_PROP_TBL("adi,rtd-excitation-current-microamp",
+ ad74115_rtd_excitation_current_ua_tbl,
+ AD74115_RTD3W4W_CONFIG_REG, GENMASK(1, 0)),
+
+ AD74115_FW_PROP_BOOL("adi,ext2-burnout-current-polarity-sourcing",
+ AD74115_BURNOUT_CONFIG_REG, BIT(11)),
+ AD74115_FW_PROP_BOOL("adi,ext1-burnout-current-polarity-sourcing",
+ AD74115_BURNOUT_CONFIG_REG, BIT(6)),
+ AD74115_FW_PROP_BOOL("adi,viout-burnout-current-polarity-sourcing",
+ AD74115_BURNOUT_CONFIG_REG, BIT(1)),
+
+ AD74115_FW_PROP_BOOL("adi,charge-pump",
+ AD74115_CHARGE_PUMP_REG, BIT(0)),
+};
+
+static int ad74115_apply_fw_prop(struct ad74115_state *st,
+ const struct ad74115_fw_prop *prop, u32 *retval)
+{
+ struct device *dev = &st->spi->dev;
+ u32 val = 0;
+ int ret;
+
+ if (prop->is_boolean) {
+ val = device_property_read_bool(dev, prop->name);
+ } else {
+ ret = device_property_read_u32(dev, prop->name, &val);
+ if (ret && prop->lookup_tbl)
+ val = prop->lookup_tbl[0];
+ }
+
+ *retval = val;
+
+ if (prop->negate)
+ val = !val;
+
+ if (prop->lookup_tbl)
+ ret = _ad74115_find_tbl_index(prop->lookup_tbl,
+ prop->lookup_tbl_len, val, &val);
+ else if (prop->max && val > prop->max)
+ ret = -EINVAL;
+ else
+ ret = 0;
+
+ if (ret)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid value %u for prop %s\n",
+ val, prop->name);
+
+ WARN(!prop->mask, "Prop %s mask is empty\n", prop->name);
+
+ val = (val << __ffs(prop->mask)) & prop->mask;
+
+ return regmap_update_bits(st->regmap, prop->reg, prop->mask, val);
+}
+
+static int ad74115_setup_adc_conv2_range(struct ad74115_state *st)
+{
+ unsigned int tbl_len = ARRAY_SIZE(ad74115_adc_range_tbl);
+ const char *prop_name = "adi,conv2-range-microvolt";
+ s32 vals[2] = {
+ ad74115_adc_range_tbl[0][0],
+ ad74115_adc_range_tbl[0][1],
+ };
+ struct device *dev = &st->spi->dev;
+ unsigned int i;
+
+ device_property_read_u32_array(dev, prop_name, vals, 2);
+
+ for (i = 0; i < tbl_len; i++)
+ if (vals[0] == ad74115_adc_range_tbl[i][0] &&
+ vals[1] == ad74115_adc_range_tbl[i][1])
+ break;
+
+ if (i == tbl_len)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid value %d, %d for prop %s\n",
+ vals[0], vals[1], prop_name);
+
+ return regmap_update_bits(st->regmap, AD74115_ADC_CONFIG_REG,
+ AD74115_ADC_CONFIG_CONV2_RANGE_MASK,
+ FIELD_PREP(AD74115_ADC_CONFIG_CONV2_RANGE_MASK, i));
+}
+
+static int ad74115_setup_iio_channels(struct iio_dev *indio_dev)
+{
+ struct ad74115_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ struct iio_chan_spec *channels;
+
+ channels = devm_kcalloc(dev, sizeof(*channels),
+ indio_dev->num_channels, GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ indio_dev->channels = channels;
+
+ memcpy(channels, ad74115_channels_map[st->ch_func].channels,
+ sizeof(*channels) * ad74115_channels_map[st->ch_func].num_channels);
+
+ if (channels[0].output && channels[0].channel == AD74115_DAC_CH_MAIN &&
+ channels[0].type == IIO_VOLTAGE && !st->dac_hart_slew) {
+ channels[0].info_mask_separate |= BIT(IIO_CHAN_INFO_SAMP_FREQ);
+ channels[0].info_mask_separate_available |= BIT(IIO_CHAN_INFO_SAMP_FREQ);
+ }
+
+ return 0;
+}
+
+static int ad74115_setup_gpio_chip(struct ad74115_state *st)
+{
+ struct device *dev = &st->spi->dev;
+
+ if (!st->gpio_valid_mask)
+ return 0;
+
+ st->gc = (struct gpio_chip) {
+ .owner = THIS_MODULE,
+ .label = AD74115_NAME,
+ .base = -1,
+ .ngpio = AD74115_GPIO_NUM,
+ .parent = dev,
+ .can_sleep = true,
+ .init_valid_mask = ad74115_gpio_init_valid_mask,
+ .get_direction = ad74115_gpio_get_direction,
+ .direction_input = ad74115_gpio_direction_input,
+ .direction_output = ad74115_gpio_direction_output,
+ .get = ad74115_gpio_get,
+ .set = ad74115_gpio_set,
+ };
+
+ return devm_gpiochip_add_data(dev, &st->gc, st);
+}
+
+static int ad74115_setup_comp_gpio_chip(struct ad74115_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ u32 val;
+ int ret;
+
+ ret = regmap_read(st->regmap, AD74115_DIN_CONFIG1_REG, &val);
+ if (ret)
+ return ret;
+
+ if (!(val & AD74115_DIN_COMPARATOR_EN_MASK))
+ return 0;
+
+ st->comp_gc = (struct gpio_chip) {
+ .owner = THIS_MODULE,
+ .label = AD74115_NAME,
+ .base = -1,
+ .ngpio = 1,
+ .parent = dev,
+ .can_sleep = true,
+ .get_direction = ad74115_comp_gpio_get_direction,
+ .get = ad74115_comp_gpio_get,
+ .set_config = ad74115_comp_gpio_set_config,
+ };
+
+ return devm_gpiochip_add_data(dev, &st->comp_gc, st);
+}
+
+static int ad74115_setup(struct iio_dev *indio_dev)
+{
+ struct ad74115_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ u32 val, din_range_high;
+ unsigned int i;
+ int ret;
+
+ ret = ad74115_apply_fw_prop(st, &ad74115_ch_func_fw_prop, &val);
+ if (ret)
+ return ret;
+
+ indio_dev->num_channels += ad74115_channels_map[val].num_channels;
+ st->ch_func = val;
+
+ ret = ad74115_setup_adc_conv2_range(st);
+ if (ret)
+ return ret;
+
+ val = device_property_read_bool(dev, "adi,dac-hart-slew");
+ if (val) {
+ st->dac_hart_slew = val;
+
+ ret = regmap_update_bits(st->regmap, AD74115_OUTPUT_CONFIG_REG,
+ AD74115_OUTPUT_SLEW_EN_MASK,
+ FIELD_PREP(AD74115_OUTPUT_SLEW_EN_MASK,
+ AD74115_SLEW_MODE_HART));
+ if (ret)
+ return ret;
+ }
+
+ ret = ad74115_apply_fw_prop(st, &ad74115_din_range_fw_prop,
+ &din_range_high);
+ if (ret)
+ return ret;
+
+ ret = device_property_read_u32(dev, "adi,digital-input-sink-microamp", &val);
+ if (!ret) {
+ if (din_range_high)
+ val = DIV_ROUND_CLOSEST(val, AD74115_DIN_SINK_LOW_STEP);
+ else
+ val = DIV_ROUND_CLOSEST(val, AD74115_DIN_SINK_HIGH_STEP);
+
+ if (val > AD74115_DIN_SINK_MAX)
+ val = AD74115_DIN_SINK_MAX;
+
+ ret = regmap_update_bits(st->regmap, AD74115_DIN_CONFIG1_REG,
+ AD74115_DIN_SINK_MASK,
+ FIELD_PREP(AD74115_DIN_SINK_MASK, val));
+ if (ret)
+ return ret;
+ }
+
+ ret = ad74115_apply_fw_prop(st, &ad74115_din_threshold_mode_fw_prop, &val);
+ if (ret)
+ return ret;
+
+ if (val == AD74115_DIN_THRESHOLD_MODE_AVDD) {
+ ret = regulator_get_voltage(st->avdd);
+ if (ret < 0)
+ return ret;
+
+ st->avdd_mv = ret / 1000;
+ }
+
+ st->din_threshold_mode = val;
+
+ ret = ad74115_apply_fw_prop(st, &ad74115_dac_bipolar_fw_prop, &val);
+ if (ret)
+ return ret;
+
+ st->dac_bipolar = val;
+
+ ret = ad74115_apply_fw_prop(st, &ad74115_rtd_mode_fw_prop, &val);
+ if (ret)
+ return ret;
+
+ st->rtd_mode_4_wire = val;
+
+ ret = ad74115_apply_fw_prop(st, &ad74115_ext2_burnout_current_fw_prop, &val);
+ if (ret)
+ return ret;
+
+ if (val) {
+ ret = regmap_update_bits(st->regmap, AD74115_BURNOUT_CONFIG_REG,
+ AD74115_BURNOUT_EXT2_EN_MASK,
+ FIELD_PREP(AD74115_BURNOUT_EXT2_EN_MASK, 1));
+ if (ret)
+ return ret;
+ }
+
+ ret = ad74115_apply_fw_prop(st, &ad74115_ext1_burnout_current_fw_prop, &val);
+ if (ret)
+ return ret;
+
+ if (val) {
+ ret = regmap_update_bits(st->regmap, AD74115_BURNOUT_CONFIG_REG,
+ AD74115_BURNOUT_EXT1_EN_MASK,
+ FIELD_PREP(AD74115_BURNOUT_EXT1_EN_MASK, 1));
+ if (ret)
+ return ret;
+ }
+
+ ret = ad74115_apply_fw_prop(st, &ad74115_viout_burnout_current_fw_prop, &val);
+ if (ret)
+ return ret;
+
+ if (val) {
+ ret = regmap_update_bits(st->regmap, AD74115_BURNOUT_CONFIG_REG,
+ AD74115_BURNOUT_VIOUT_EN_MASK,
+ FIELD_PREP(AD74115_BURNOUT_VIOUT_EN_MASK, 1));
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < AD74115_GPIO_NUM; i++) {
+ ret = ad74115_apply_fw_prop(st, &ad74115_gpio_mode_fw_props[i], &val);
+ if (ret)
+ return ret;
+
+ if (val == AD74115_GPIO_MODE_LOGIC)
+ st->gpio_valid_mask |= BIT(i);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ad74115_fw_props); i++) {
+ ret = ad74115_apply_fw_prop(st, &ad74115_fw_props[i], &val);
+ if (ret)
+ return ret;
+ }
+
+ ret = ad74115_setup_gpio_chip(st);
+ if (ret)
+ return ret;
+
+ ret = ad74115_setup_comp_gpio_chip(st);
+ if (ret)
+ return ret;
+
+ return ad74115_setup_iio_channels(indio_dev);
+}
+
+static int ad74115_reset(struct ad74115_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ struct gpio_desc *reset_gpio;
+ int ret;
+
+ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(reset_gpio),
+ "Failed to find reset GPIO\n");
+
+ if (reset_gpio) {
+ fsleep(100);
+
+ gpiod_set_value_cansleep(reset_gpio, 0);
+ } else {
+ ret = regmap_write(st->regmap, AD74115_CMD_KEY_REG,
+ AD74115_CMD_KEY_RESET1);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD74115_CMD_KEY_REG,
+ AD74115_CMD_KEY_RESET2);
+ if (ret)
+ return ret;
+ }
+
+ fsleep(1000);
+
+ return 0;
+}
+
+static void ad74115_regulator_disable(void *data)
+{
+ regulator_disable(data);
+}
+
+static int ad74115_setup_trigger(struct iio_dev *indio_dev)
+{
+ struct ad74115_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ int ret;
+
+ st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "adc_rdy");
+
+ if (st->irq == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ if (st->irq < 0) {
+ st->irq = 0;
+ return 0;
+ }
+
+ ret = devm_request_irq(dev, st->irq, ad74115_adc_data_interrupt,
+ 0, AD74115_NAME, indio_dev);
+ if (ret)
+ return ret;
+
+ st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", AD74115_NAME,
+ iio_device_id(indio_dev));
+ if (!st->trig)
+ return -ENOMEM;
+
+ st->trig->ops = &ad74115_trigger_ops;
+ iio_trigger_set_drvdata(st->trig, st);
+
+ ret = devm_iio_trigger_register(dev, st->trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(st->trig);
+
+ return 0;
+}
+
+static int ad74115_probe(struct spi_device *spi)
+{
+ static const char * const regulator_names[] = {
+ "avcc", "dvcc", "dovdd", "refin",
+ };
+ struct device *dev = &spi->dev;
+ struct ad74115_state *st;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ st->spi = spi;
+ mutex_init(&st->lock);
+ init_completion(&st->adc_data_completion);
+
+ indio_dev->name = AD74115_NAME;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &ad74115_info;
+
+ st->avdd = devm_regulator_get(dev, "avdd");
+ if (IS_ERR(st->avdd))
+ return PTR_ERR(st->avdd);
+
+ ret = regulator_enable(st->avdd);
+ if (ret) {
+ dev_err(dev, "Failed to enable avdd regulator\n");
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(dev, ad74115_regulator_disable, st->avdd);
+ if (ret)
+ return ret;
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
+ regulator_names);
+ if (ret)
+ return ret;
+
+ st->regmap = devm_regmap_init(dev, NULL, st, &ad74115_regmap_config);
+ if (IS_ERR(st->regmap))
+ return PTR_ERR(st->regmap);
+
+ ret = ad74115_reset(st);
+ if (ret)
+ return ret;
+
+ ret = ad74115_setup(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ad74115_setup_trigger(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ ad74115_trigger_handler,
+ &ad74115_buffer_ops);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static int ad74115_unregister_driver(struct spi_driver *spi)
+{
+ spi_unregister_driver(spi);
+
+ return 0;
+}
+
+static int __init ad74115_register_driver(struct spi_driver *spi)
+{
+ crc8_populate_msb(ad74115_crc8_table, AD74115_CRC_POLYNOMIAL);
+
+ return spi_register_driver(spi);
+}
+
+static const struct spi_device_id ad74115_spi_id[] = {
+ { "ad74115h" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(spi, ad74115_spi_id);
+
+static const struct of_device_id ad74115_dt_id[] = {
+ { .compatible = "adi,ad74115h" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad74115_dt_id);
+
+static struct spi_driver ad74115_driver = {
+ .driver = {
+ .name = "ad74115",
+ .of_match_table = ad74115_dt_id,
+ },
+ .probe = ad74115_probe,
+ .id_table = ad74115_spi_id,
+};
+
+module_driver(ad74115_driver,
+ ad74115_register_driver, ad74115_unregister_driver);
+
+MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD74115 ADDAC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c
index 899bcd83f40b..f32c8c2fb26d 100644
--- a/drivers/iio/addac/ad74413r.c
+++ b/drivers/iio/addac/ad74413r.c
@@ -71,6 +71,7 @@ struct ad74413r_state {
struct regmap *regmap;
struct device *dev;
struct iio_trigger *trig;
+ struct gpio_desc *reset_gpio;
size_t adc_active_channels;
struct spi_message adc_samples_msg;
@@ -393,6 +394,13 @@ static int ad74413r_reset(struct ad74413r_state *st)
{
int ret;
+ if (st->reset_gpio) {
+ gpiod_set_value_cansleep(st->reset_gpio, 1);
+ fsleep(50);
+ gpiod_set_value_cansleep(st->reset_gpio, 0);
+ return 0;
+ }
+
ret = regmap_write(st->regmap, AD74413R_REG_CMD_KEY,
AD74413R_CMD_KEY_RESET1);
if (ret)
@@ -691,7 +699,7 @@ static int ad74413_get_input_current_offset(struct ad74413r_state *st,
if (ret)
return ret;
- *val = voltage_offset * AD74413R_ADC_RESULT_MAX / voltage_range;
+ *val = voltage_offset * (int)AD74413R_ADC_RESULT_MAX / voltage_range;
return IIO_VAL_INT;
}
@@ -1305,6 +1313,16 @@ static int ad74413r_probe(struct spi_device *spi)
st->spi = spi;
st->dev = &spi->dev;
st->chip_info = device_get_match_data(&spi->dev);
+ if (!st->chip_info) {
+ const struct spi_device_id *id = spi_get_device_id(spi);
+
+ if (id)
+ st->chip_info =
+ (struct ad74413r_chip_info *)id->driver_data;
+ if (!st->chip_info)
+ return -EINVAL;
+ }
+
mutex_init(&st->lock);
init_completion(&st->adc_data_completion);
@@ -1313,6 +1331,10 @@ static int ad74413r_probe(struct spi_device *spi)
if (IS_ERR(st->regmap))
return PTR_ERR(st->regmap);
+ st->reset_gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(st->reset_gpio))
+ return PTR_ERR(st->reset_gpio);
+
st->refin_reg = devm_regulator_get(st->dev, "refin");
if (IS_ERR(st->refin_reg))
return dev_err_probe(st->dev, PTR_ERR(st->refin_reg),
@@ -1457,12 +1479,20 @@ static const struct of_device_id ad74413r_dt_id[] = {
};
MODULE_DEVICE_TABLE(of, ad74413r_dt_id);
+static const struct spi_device_id ad74413r_spi_id[] = {
+ { .name = "ad74412r", .driver_data = (kernel_ulong_t)&ad74412r_chip_info_data },
+ { .name = "ad74413r", .driver_data = (kernel_ulong_t)&ad74413r_chip_info_data },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad74413r_spi_id);
+
static struct spi_driver ad74413r_driver = {
.driver = {
.name = "ad74413r",
.of_match_table = ad74413r_dt_id,
},
.probe = ad74413r_probe,
+ .id_table = ad74413r_spi_id,
};
module_driver(ad74413r_driver,
diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c
index ce80e0c916f4..108f0f1685ef 100644
--- a/drivers/iio/amplifiers/hmc425a.c
+++ b/drivers/iio/amplifiers/hmc425a.c
@@ -34,7 +34,6 @@ struct hmc425a_chip_info {
};
struct hmc425a_state {
- struct regulator *reg;
struct mutex lock; /* protect sensor state */
struct hmc425a_chip_info *chip_info;
struct gpio_descs *gpios;
@@ -162,13 +161,6 @@ static const struct of_device_id hmc425a_of_match[] = {
};
MODULE_DEVICE_TABLE(of, hmc425a_of_match);
-static void hmc425a_reg_disable(void *data)
-{
- struct hmc425a_state *st = data;
-
- regulator_disable(st->reg);
-}
-
static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
[ID_HMC425A] = {
.name = "hmc425a",
@@ -211,14 +203,7 @@ static int hmc425a_probe(struct platform_device *pdev)
return -ENODEV;
}
- st->reg = devm_regulator_get(&pdev->dev, "vcc-supply");
- if (IS_ERR(st->reg))
- return PTR_ERR(st->reg);
-
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
- ret = devm_add_action_or_reset(&pdev->dev, hmc425a_reg_disable, st);
+ ret = devm_regulator_get_enable(&pdev->dev, "vcc-supply");
if (ret)
return ret;
diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
index f744b62a636a..5f85ba38e6f6 100644
--- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c
+++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
@@ -142,8 +142,8 @@ static ssize_t iio_dmaengine_buffer_get_length_align(struct device *dev,
static IIO_DEVICE_ATTR(length_align_bytes, 0444,
iio_dmaengine_buffer_get_length_align, NULL, 0);
-static const struct attribute *iio_dmaengine_buffer_attrs[] = {
- &iio_dev_attr_length_align_bytes.dev_attr.attr,
+static const struct iio_dev_attr *iio_dmaengine_buffer_attrs[] = {
+ &iio_dev_attr_length_align_bytes,
NULL,
};
diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c
index 8d4fc97d1005..c7671b1f5ead 100644
--- a/drivers/iio/buffer/industrialio-triggered-buffer.c
+++ b/drivers/iio/buffer/industrialio-triggered-buffer.c
@@ -41,7 +41,7 @@ int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev,
irqreturn_t (*thread)(int irq, void *p),
enum iio_buffer_direction direction,
const struct iio_buffer_setup_ops *setup_ops,
- const struct attribute **buffer_attrs)
+ const struct iio_dev_attr **buffer_attrs)
{
struct iio_buffer *buffer;
int ret;
@@ -110,7 +110,7 @@ int devm_iio_triggered_buffer_setup_ext(struct device *dev,
irqreturn_t (*thread)(int irq, void *p),
enum iio_buffer_direction direction,
const struct iio_buffer_setup_ops *ops,
- const struct attribute **buffer_attrs)
+ const struct iio_dev_attr **buffer_attrs)
{
int ret;
diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c
index 35d8b4077376..05b285f0eb22 100644
--- a/drivers/iio/buffer/kfifo_buf.c
+++ b/drivers/iio/buffer/kfifo_buf.c
@@ -270,7 +270,7 @@ static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
int devm_iio_kfifo_buffer_setup_ext(struct device *dev,
struct iio_dev *indio_dev,
const struct iio_buffer_setup_ops *setup_ops,
- const struct attribute **buffer_attrs)
+ const struct iio_dev_attr **buffer_attrs)
{
struct iio_buffer *buffer;
diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c
index ebe112b4618b..79aeb0aaea67 100644
--- a/drivers/iio/cdc/ad7150.c
+++ b/drivers/iio/cdc/ad7150.c
@@ -536,19 +536,11 @@ static const struct iio_info ad7150_info_no_irq = {
.read_raw = &ad7150_read_raw,
};
-static void ad7150_reg_disable(void *data)
-{
- struct regulator *reg = data;
-
- regulator_disable(reg);
-}
-
-static int ad7150_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ad7150_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ad7150_chip_info *chip;
struct iio_dev *indio_dev;
- struct regulator *reg;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
@@ -563,15 +555,7 @@ static int ad7150_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
- reg = devm_regulator_get(&client->dev, "vdd");
- if (IS_ERR(reg))
- return PTR_ERR(reg);
-
- ret = regulator_enable(reg);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&client->dev, ad7150_reg_disable, reg);
+ ret = devm_regulator_get_enable(&client->dev, "vdd");
if (ret)
return ret;
@@ -663,7 +647,7 @@ static struct i2c_driver ad7150_driver = {
.name = "ad7150",
.of_match_table = ad7150_of_match,
},
- .probe = ad7150_probe,
+ .probe_new = 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 b266f5328140..6f68651ce1d5 100644
--- a/drivers/iio/cdc/ad7746.c
+++ b/drivers/iio/cdc/ad7746.c
@@ -717,9 +717,9 @@ static const struct iio_info ad7746_info = {
.write_raw = ad7746_write_raw,
};
-static int ad7746_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ad7746_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct ad7746_chip_info *chip;
struct iio_dev *indio_dev;
@@ -810,7 +810,7 @@ static struct i2c_driver ad7746_driver = {
.name = KBUILD_MODNAME,
.of_match_table = ad7746_of_match,
},
- .probe = ad7746_probe,
+ .probe_new = 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 97be3669c554..0a0fbcdd4469 100644
--- a/drivers/iio/chemical/ams-iaq-core.c
+++ b/drivers/iio/chemical/ams-iaq-core.c
@@ -135,8 +135,7 @@ static const struct iio_info ams_iaqcore_info = {
.read_raw = ams_iaqcore_read_raw,
};
-static int ams_iaqcore_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ams_iaqcore_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct ams_iaqcore_data *data;
@@ -180,7 +179,7 @@ static struct i2c_driver ams_iaqcore_driver = {
.name = "ams-iaq-core",
.of_match_table = ams_iaqcore_dt_ids,
},
- .probe = ams_iaqcore_probe,
+ .probe_new = 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 bbcf5a59c1f4..307c3488f4bd 100644
--- a/drivers/iio/chemical/atlas-ezo-sensor.c
+++ b/drivers/iio/chemical/atlas-ezo-sensor.c
@@ -201,9 +201,9 @@ static const struct of_device_id atlas_ezo_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids);
-static int atlas_ezo_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int atlas_ezo_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct atlas_ezo_device *chip;
struct atlas_ezo_data *data;
struct iio_dev *indio_dev;
@@ -238,7 +238,7 @@ static struct i2c_driver atlas_ezo_driver = {
.name = ATLAS_EZO_DRV_NAME,
.of_match_table = atlas_ezo_dt_ids,
},
- .probe = atlas_ezo_probe,
+ .probe_new = 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 7cac77a931c7..024657bc59e1 100644
--- a/drivers/iio/chemical/atlas-sensor.c
+++ b/drivers/iio/chemical/atlas-sensor.c
@@ -608,9 +608,9 @@ static const struct of_device_id atlas_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, atlas_dt_ids);
-static int atlas_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int atlas_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct atlas_data *data;
struct atlas_device *chip;
struct iio_trigger *trig;
@@ -767,7 +767,7 @@ static struct i2c_driver atlas_driver = {
.of_match_table = atlas_dt_ids,
.pm = pm_ptr(&atlas_pm_ops),
},
- .probe = atlas_probe,
+ .probe_new = 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 20f2c20b6b02..61b12079858d 100644
--- a/drivers/iio/chemical/bme680_i2c.c
+++ b/drivers/iio/chemical/bme680_i2c.c
@@ -17,9 +17,9 @@
#include "bme680.h"
-static int bme680_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bme680_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct regmap *regmap;
const char *name = NULL;
@@ -52,7 +52,7 @@ static struct i2c_driver bme680_i2c_driver = {
.name = "bme680_i2c",
.of_match_table = bme680_of_i2c_match,
},
- .probe = bme680_i2c_probe,
+ .probe_new = 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 ba4045e20303..6ead80c08924 100644
--- a/drivers/iio/chemical/ccs811.c
+++ b/drivers/iio/chemical/ccs811.c
@@ -401,9 +401,9 @@ static int ccs811_reset(struct i2c_client *client)
return 0;
}
-static int ccs811_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ccs811_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct ccs811_data *data;
int ret;
@@ -567,7 +567,7 @@ static struct i2c_driver ccs811_driver = {
.name = "ccs811",
.of_match_table = ccs811_dt_ids,
},
- .probe = ccs811_probe,
+ .probe_new = ccs811_probe,
.remove = ccs811_remove,
.id_table = ccs811_id,
};
diff --git a/drivers/iio/chemical/scd4x.c b/drivers/iio/chemical/scd4x.c
index 54066532ea45..f7ed9455b3c8 100644
--- a/drivers/iio/chemical/scd4x.c
+++ b/drivers/iio/chemical/scd4x.c
@@ -615,7 +615,7 @@ out:
return IRQ_HANDLED;
}
-static int scd4x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int scd4x_probe(struct i2c_client *client)
{
static const unsigned long scd4x_scan_masks[] = { 0x07, 0x00 };
struct device *dev = &client->dev;
@@ -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 = scd4x_probe,
+ .probe_new = scd4x_probe,
};
module_i2c_driver(scd4x_i2c_driver);
diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c
index e2c13c78c7e0..9d0c68485b63 100644
--- a/drivers/iio/chemical/sgp30.c
+++ b/drivers/iio/chemical/sgp30.c
@@ -496,9 +496,9 @@ static const struct of_device_id sgp_dt_ids[] = {
{ }
};
-static int sgp_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int sgp_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct sgp_data *data;
@@ -575,7 +575,7 @@ static struct i2c_driver sgp_driver = {
.name = "sgp30",
.of_match_table = sgp_dt_ids,
},
- .probe = sgp_probe,
+ .probe_new = sgp_probe,
.remove = sgp_remove,
.id_table = sgp_id,
};
diff --git a/drivers/iio/chemical/sgp40.c b/drivers/iio/chemical/sgp40.c
index 8a56394cea4e..c0ea01300908 100644
--- a/drivers/iio/chemical/sgp40.c
+++ b/drivers/iio/chemical/sgp40.c
@@ -311,9 +311,9 @@ static const struct iio_info sgp40_info = {
.write_raw = sgp40_write_raw,
};
-static int sgp40_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int sgp40_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct sgp40_data *data;
@@ -368,7 +368,7 @@ static struct i2c_driver sgp40_driver = {
.name = "sgp40",
.of_match_table = sgp40_dt_ids,
},
- .probe = sgp40_probe,
+ .probe_new = sgp40_probe,
.id_table = sgp40_id,
};
module_i2c_driver(sgp40_driver);
diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c
index e7e1c74a351e..d4604f7ccd1e 100644
--- a/drivers/iio/chemical/vz89x.c
+++ b/drivers/iio/chemical/vz89x.c
@@ -348,9 +348,9 @@ static const struct of_device_id vz89x_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
-static int vz89x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int vz89x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct vz89x_data *data;
@@ -402,7 +402,7 @@ static struct i2c_driver vz89x_driver = {
.name = "vz89x",
.of_match_table = vz89x_dt_ids,
},
- .probe = vz89x_probe,
+ .probe_new = vz89x_probe,
.id_table = vz89x_id,
};
module_i2c_driver(vz89x_driver);
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
index 05a28d353e34..943e9e14d1e9 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
@@ -172,9 +172,9 @@ static ssize_t hwfifo_watermark_max_show(struct device *dev,
static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
-static const struct attribute *cros_ec_sensor_fifo_attributes[] = {
- &iio_dev_attr_hwfifo_timeout.dev_attr.attr,
- &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
+static const struct iio_dev_attr *cros_ec_sensor_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_timeout,
+ &iio_dev_attr_hwfifo_watermark_max,
NULL,
};
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 1151434038d4..ad8910e6ad59 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -75,9 +75,9 @@ static IIO_DEVICE_ATTR(hwfifo_timeout, 0644,
static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
_hid_sensor_get_fifo_state, NULL, 0);
-static const struct attribute *hid_sensor_fifo_attributes[] = {
- &iio_dev_attr_hwfifo_timeout.dev_attr.attr,
- &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+static const struct iio_dev_attr *hid_sensor_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_timeout,
+ &iio_dev_attr_hwfifo_enabled,
NULL,
};
@@ -231,7 +231,7 @@ static const struct iio_trigger_ops hid_sensor_trigger_ops = {
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_common *attrb)
{
- const struct attribute **fifo_attrs;
+ const struct iio_dev_attr **fifo_attrs;
int ret;
struct iio_trigger *trig;
diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c
index 54ccf19ab2bb..d92f7f651f7b 100644
--- a/drivers/iio/common/scmi_sensors/scmi_iio.c
+++ b/drivers/iio/common/scmi_sensors/scmi_iio.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/scmi_protocol.h>
#include <linux/time.h>
#include <linux/types.h>
@@ -27,6 +28,8 @@ struct scmi_iio_priv {
struct scmi_protocol_handle *ph;
const struct scmi_sensor_info *sensor_info;
struct iio_dev *indio_dev;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
/* adding one additional channel for timestamp */
s64 iio_buf[SCMI_IIO_NUM_OF_AXIS + 1];
struct notifier_block sensor_update_nb;
@@ -198,13 +201,14 @@ static int scmi_iio_write_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
{
+ struct scmi_iio_priv *sensor = iio_priv(iio_dev);
int err;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
- mutex_lock(&iio_dev->mlock);
+ mutex_lock(&sensor->lock);
err = scmi_iio_set_odr_val(iio_dev, val, val2);
- mutex_unlock(&iio_dev->mlock);
+ mutex_unlock(&sensor->lock);
return err;
default:
return -EINVAL;
@@ -586,6 +590,7 @@ scmi_alloc_iiodev(struct scmi_device *sdev,
sensor->sensor_info = sensor_info;
sensor->sensor_update_nb.notifier_call = scmi_iio_sensor_update_cb;
sensor->indio_dev = iiodev;
+ mutex_init(&sensor->lock);
/* adding one additional channel for timestamp */
iiodev->num_channels = sensor_info->num_axis + 1;
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 35720c64fea8..c77d7bdcc121 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -219,47 +219,22 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
}
EXPORT_SYMBOL_NS(st_sensors_set_axis_enable, IIO_ST_SENSORS);
-static void st_reg_disable(void *reg)
-{
- regulator_disable(reg);
-}
int st_sensors_power_enable(struct iio_dev *indio_dev)
{
- struct st_sensor_data *pdata = iio_priv(indio_dev);
+ static const char * const regulator_names[] = { "vdd", "vddio" };
struct device *parent = indio_dev->dev.parent;
int err;
/* Regulators not mandatory, but if requested we should enable them. */
- pdata->vdd = devm_regulator_get(parent, "vdd");
- if (IS_ERR(pdata->vdd))
- return dev_err_probe(&indio_dev->dev, PTR_ERR(pdata->vdd),
- "unable to get Vdd supply\n");
-
- err = regulator_enable(pdata->vdd);
- if (err != 0) {
- dev_warn(&indio_dev->dev,
- "Failed to enable specified Vdd supply\n");
- return err;
- }
-
- err = devm_add_action_or_reset(parent, st_reg_disable, pdata->vdd);
+ err = devm_regulator_bulk_get_enable(parent,
+ ARRAY_SIZE(regulator_names),
+ regulator_names);
if (err)
- return err;
+ return dev_err_probe(&indio_dev->dev, err,
+ "unable to enable supplies\n");
- pdata->vdd_io = devm_regulator_get(parent, "vddio");
- if (IS_ERR(pdata->vdd_io))
- return dev_err_probe(&indio_dev->dev, PTR_ERR(pdata->vdd_io),
- "unable to get Vdd_IO supply\n");
-
- err = regulator_enable(pdata->vdd_io);
- if (err != 0) {
- dev_warn(&indio_dev->dev,
- "Failed to enable specified Vdd_IO supply\n");
- return err;
- }
-
- return devm_add_action_or_reset(parent, st_reg_disable, pdata->vdd_io);
+ return 0;
}
EXPORT_SYMBOL_NS(st_sensors_power_enable, IIO_ST_SENSORS);
diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c
index 4447b8811827..f01249c1ba93 100644
--- a/drivers/iio/dac/ad5064.c
+++ b/drivers/iio/dac/ad5064.c
@@ -993,9 +993,9 @@ static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd,
return 0;
}
-static int ad5064_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int ad5064_i2c_probe(struct i2c_client *i2c)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
return ad5064_probe(&i2c->dev, id->driver_data, id->name,
ad5064_i2c_write);
}
@@ -1056,7 +1056,7 @@ static struct i2c_driver ad5064_i2c_driver = {
.driver = {
.name = "ad5064",
},
- .probe = ad5064_i2c_probe,
+ .probe_new = ad5064_i2c_probe,
.id_table = ad5064_i2c_ids,
};
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c
index a81bfa47a221..64b4519f8f5e 100644
--- a/drivers/iio/dac/ad5380.c
+++ b/drivers/iio/dac/ad5380.c
@@ -546,9 +546,9 @@ static inline void ad5380_spi_unregister_driver(void)
#if IS_ENABLED(CONFIG_I2C)
-static int ad5380_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int ad5380_i2c_probe(struct i2c_client *i2c)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
struct regmap *regmap;
regmap = devm_regmap_init_i2c(i2c, &ad5380_regmap_config);
@@ -589,7 +589,7 @@ static struct i2c_driver ad5380_i2c_driver = {
.driver = {
.name = "ad5380",
},
- .probe = ad5380_i2c_probe,
+ .probe_new = 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 7324065d3782..aa3130b33456 100644
--- a/drivers/iio/dac/ad5446.c
+++ b/drivers/iio/dac/ad5446.c
@@ -568,9 +568,9 @@ static const struct ad5446_chip_info ad5446_i2c_chip_info[] = {
},
};
-static int ad5446_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int ad5446_i2c_probe(struct i2c_client *i2c)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
return ad5446_probe(&i2c->dev, id->name,
&ad5446_i2c_chip_info[id->driver_data]);
}
@@ -595,7 +595,7 @@ static struct i2c_driver ad5446_i2c_driver = {
.driver = {
.name = "ad5446",
},
- .probe = ad5446_i2c_probe,
+ .probe_new = 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 8e5e014e0c28..d311567ab324 100644
--- a/drivers/iio/dac/ad5593r.c
+++ b/drivers/iio/dac/ad5593r.c
@@ -99,9 +99,9 @@ static const struct ad5592r_rw_ops ad5593r_rw_ops = {
.gpio_read = ad5593r_gpio_read,
};
-static int ad5593r_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int ad5593r_i2c_probe(struct i2c_client *i2c)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
if (!i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
return -EOPNOTSUPP;
@@ -138,7 +138,7 @@ static struct i2c_driver ad5593r_driver = {
.of_match_table = ad5593r_of_match,
.acpi_match_table = ad5593r_acpi_match,
},
- .probe = ad5593r_i2c_probe,
+ .probe_new = 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 aa36cbf0137c..160e80cf9135 100644
--- a/drivers/iio/dac/ad5696-i2c.c
+++ b/drivers/iio/dac/ad5696-i2c.c
@@ -58,9 +58,9 @@ static int ad5686_i2c_write(struct ad5686_state *st,
return (ret != 3) ? -EIO : 0;
}
-static int ad5686_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int ad5686_i2c_probe(struct i2c_client *i2c)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
return ad5686_probe(&i2c->dev, id->driver_data, id->name,
ad5686_i2c_write, ad5686_i2c_read);
}
@@ -113,7 +113,7 @@ static struct i2c_driver ad5686_i2c_driver = {
.name = "ad5696",
.of_match_table = ad5686_of_match,
},
- .probe = ad5686_i2c_probe,
+ .probe_new = 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 3e17a681174e..a16a6a934d9d 100644
--- a/drivers/iio/dac/ds4424.c
+++ b/drivers/iio/dac/ds4424.c
@@ -213,9 +213,9 @@ static const struct iio_info ds4424_info = {
.write_raw = ds4424_write_raw,
};
-static int ds4424_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ds4424_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ds4424_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -312,7 +312,7 @@ static struct i2c_driver ds4424_driver = {
.of_match_table = ds4424_of_match,
.pm = pm_sleep_ptr(&ds4424_pm_ops),
},
- .probe = ds4424_probe,
+ .probe_new = ds4424_probe,
.remove = ds4424_remove,
.id_table = ds4424_id,
};
diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c
index 28bdde2d3088..fc8eb53c65be 100644
--- a/drivers/iio/dac/ltc2688.c
+++ b/drivers/iio/dac/ltc2688.c
@@ -84,7 +84,6 @@ struct ltc2688_chan {
struct ltc2688_state {
struct spi_device *spi;
struct regmap *regmap;
- struct regulator_bulk_data regulators[2];
struct ltc2688_chan channels[LTC2688_DAC_CHANNELS];
struct iio_chan_spec *iio_chan;
/* lock to protect against multiple access to the device and shared data */
@@ -902,13 +901,6 @@ static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref)
LTC2688_CONFIG_EXT_REF);
}
-static void ltc2688_disable_regulators(void *data)
-{
- struct ltc2688_state *st = data;
-
- regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators);
-}
-
static void ltc2688_disable_regulator(void *regulator)
{
regulator_disable(regulator);
@@ -965,6 +957,7 @@ static const struct iio_info ltc2688_info = {
static int ltc2688_probe(struct spi_device *spi)
{
+ static const char * const regulators[] = { "vcc", "iovcc" };
struct ltc2688_state *st;
struct iio_dev *indio_dev;
struct regulator *vref_reg;
@@ -988,21 +981,11 @@ static int ltc2688_probe(struct spi_device *spi)
return dev_err_probe(dev, PTR_ERR(st->regmap),
"Failed to init regmap");
- st->regulators[0].supply = "vcc";
- st->regulators[1].supply = "iovcc";
- ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(st->regulators),
- st->regulators);
- if (ret)
- return dev_err_probe(dev, ret, "Failed to get regulators\n");
-
- ret = regulator_bulk_enable(ARRAY_SIZE(st->regulators), st->regulators);
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators),
+ regulators);
if (ret)
return dev_err_probe(dev, ret, "Failed to enable regulators\n");
- ret = devm_add_action_or_reset(dev, ltc2688_disable_regulators, st);
- if (ret)
- return ret;
-
vref_reg = devm_regulator_get_optional(dev, "vref");
if (IS_ERR(vref_reg)) {
if (PTR_ERR(vref_reg) != -ENODEV)
diff --git a/drivers/iio/dac/m62332.c b/drivers/iio/dac/m62332.c
index 5a812f87970c..b692459b0f23 100644
--- a/drivers/iio/dac/m62332.c
+++ b/drivers/iio/dac/m62332.c
@@ -176,8 +176,7 @@ static const struct iio_chan_spec m62332_channels[M62332_CHANNELS] = {
M62332_CHANNEL(1)
};
-static int m62332_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int m62332_probe(struct i2c_client *client)
{
struct m62332_data *data;
struct iio_dev *indio_dev;
@@ -239,7 +238,7 @@ static struct i2c_driver m62332_driver = {
.name = "m62332",
.pm = pm_sleep_ptr(&m62332_pm_ops),
},
- .probe = m62332_probe,
+ .probe_new = m62332_probe,
.remove = m62332_remove,
.id_table = m62332_id,
};
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
index 373ce6ff83b7..25967c39365d 100644
--- a/drivers/iio/dac/max517.c
+++ b/drivers/iio/dac/max517.c
@@ -141,9 +141,9 @@ static const struct iio_chan_spec max517_channels[] = {
MAX517_CHANNEL(7),
};
-static int max517_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max517_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct max517_data *data;
struct iio_dev *indio_dev;
struct max517_platform_data *platform_data = client->dev.platform_data;
@@ -203,7 +203,7 @@ static struct i2c_driver max517_driver = {
.name = MAX517_DRV_NAME,
.pm = pm_sleep_ptr(&max517_pm_ops),
},
- .probe = max517_probe,
+ .probe_new = 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 e001b594d5b1..23da345b9250 100644
--- a/drivers/iio/dac/max5821.c
+++ b/drivers/iio/dac/max5821.c
@@ -300,9 +300,9 @@ static void max5821_regulator_disable(void *reg)
regulator_disable(reg);
}
-static int max5821_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max5821_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct max5821_data *data;
struct iio_dev *indio_dev;
u32 tmp;
@@ -377,7 +377,7 @@ static struct i2c_driver max5821_driver = {
.of_match_table = max5821_of_match,
.pm = pm_sleep_ptr(&max5821_pm_ops),
},
- .probe = max5821_probe,
+ .probe_new = 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 446d1a8fe4be..46bf758760f8 100644
--- a/drivers/iio/dac/mcp4725.c
+++ b/drivers/iio/dac/mcp4725.c
@@ -369,9 +369,9 @@ static int mcp4725_probe_dt(struct device *dev,
return 0;
}
-static int mcp4725_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mcp4725_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct mcp4725_data *data;
struct iio_dev *indio_dev;
struct mcp4725_platform_data *pdata, pdata_dt;
@@ -524,7 +524,7 @@ static struct i2c_driver mcp4725_driver = {
.of_match_table = mcp4725_of_match,
.pm = pm_sleep_ptr(&mcp4725_pm_ops),
},
- .probe = mcp4725_probe,
+ .probe_new = 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 3210e3098f9a..40191947fea3 100644
--- a/drivers/iio/dac/ti-dac5571.c
+++ b/drivers/iio/dac/ti-dac5571.c
@@ -306,9 +306,9 @@ static const struct iio_info dac5571_info = {
.write_raw_get_fmt = dac5571_write_raw_get_fmt,
};
-static int dac5571_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int dac5571_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
const struct dac5571_spec *spec;
struct dac5571_data *data;
@@ -426,7 +426,7 @@ static struct i2c_driver dac5571_driver = {
.name = "ti-dac5571",
.of_match_table = dac5571_of_id,
},
- .probe = dac5571_probe,
+ .probe_new = dac5571_probe,
.remove = dac5571_remove,
.id_table = dac5571_id,
};
diff --git a/drivers/iio/filter/admv8818.c b/drivers/iio/filter/admv8818.c
index 68de45fe21b4..fe8d46cb7f1d 100644
--- a/drivers/iio/filter/admv8818.c
+++ b/drivers/iio/filter/admv8818.c
@@ -265,7 +265,7 @@ static int __admv8818_read_hpf_freq(struct admv8818_state *st, u64 *hpf_freq)
return ret;
hpf_band = FIELD_GET(ADMV8818_SW_IN_WR0_MSK, data);
- if (!hpf_band) {
+ if (!hpf_band || hpf_band > 4) {
*hpf_freq = 0;
return ret;
}
@@ -303,7 +303,7 @@ static int __admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)
return ret;
lpf_band = FIELD_GET(ADMV8818_SW_OUT_WR0_MSK, data);
- if (!lpf_band) {
+ if (!lpf_band || lpf_band > 4) {
*lpf_freq = 0;
return ret;
}
diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig
index f3702f36436c..9e85dfa58508 100644
--- a/drivers/iio/frequency/Kconfig
+++ b/drivers/iio/frequency/Kconfig
@@ -50,6 +50,16 @@ config ADF4371
To compile this driver as a module, choose M here: the
module will be called adf4371.
+config ADF4377
+ tristate "Analog Devices ADF4377 Microwave Wideband Synthesizer"
+ depends on SPI && COMMON_CLK
+ help
+ Say yes here to build support for Analog Devices ADF4377 Microwave
+ Wideband Synthesizer.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adf4377.
+
config ADMV1013
tristate "Analog Devices ADMV1013 Microwave Upconverter"
depends on SPI && COMMON_CLK
diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile
index 48add732f1d3..b616c29b4a08 100644
--- a/drivers/iio/frequency/Makefile
+++ b/drivers/iio/frequency/Makefile
@@ -7,6 +7,7 @@
obj-$(CONFIG_AD9523) += ad9523.o
obj-$(CONFIG_ADF4350) += adf4350.o
obj-$(CONFIG_ADF4371) += adf4371.o
+obj-$(CONFIG_ADF4377) += adf4377.o
obj-$(CONFIG_ADMV1013) += admv1013.o
obj-$(CONFIG_ADMV1014) += admv1014.o
obj-$(CONFIG_ADMV4420) += admv4420.o
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index 97662ca1ca96..b391c6e27ab0 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -265,7 +265,6 @@ enum {
struct ad9523_state {
struct spi_device *spi;
- struct regulator *reg;
struct ad9523_platform_data *pdata;
struct iio_chan_spec ad9523_channels[AD9523_NUM_CHAN];
struct gpio_desc *pwrdown_gpio;
@@ -969,13 +968,6 @@ static int ad9523_setup(struct iio_dev *indio_dev)
return 0;
}
-static void ad9523_reg_disable(void *data)
-{
- struct regulator *reg = data;
-
- regulator_disable(reg);
-}
-
static int ad9523_probe(struct spi_device *spi)
{
struct ad9523_platform_data *pdata = spi->dev.platform_data;
@@ -996,17 +988,9 @@ static int ad9523_probe(struct spi_device *spi)
mutex_init(&st->lock);
- st->reg = devm_regulator_get(&spi->dev, "vcc");
- if (!IS_ERR(st->reg)) {
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&spi->dev, ad9523_reg_disable,
- st->reg);
- if (ret)
- return ret;
- }
+ ret = devm_regulator_get_enable(&spi->dev, "vcc");
+ if (ret)
+ return ret;
st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
GPIOD_OUT_HIGH);
diff --git a/drivers/iio/frequency/adf4377.c b/drivers/iio/frequency/adf4377.c
new file mode 100644
index 000000000000..26abecbd51e0
--- /dev/null
+++ b/drivers/iio/frequency/adf4377.c
@@ -0,0 +1,994 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ADF4377 driver
+ *
+ * Copyright 2022 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
+#include <linux/iio/iio.h>
+#include <linux/regmap.h>
+#include <linux/units.h>
+
+#include <asm/unaligned.h>
+
+/* ADF4377 REG0000 Map */
+#define ADF4377_0000_SOFT_RESET_R_MSK BIT(7)
+#define ADF4377_0000_LSB_FIRST_R_MSK BIT(6)
+#define ADF4377_0000_ADDRESS_ASC_R_MSK BIT(5)
+#define ADF4377_0000_SDO_ACTIVE_R_MSK BIT(4)
+#define ADF4377_0000_SDO_ACTIVE_MSK BIT(3)
+#define ADF4377_0000_ADDRESS_ASC_MSK BIT(2)
+#define ADF4377_0000_LSB_FIRST_MSK BIT(1)
+#define ADF4377_0000_SOFT_RESET_MSK BIT(0)
+
+/* ADF4377 REG0000 Bit Definition */
+#define ADF4377_0000_SDO_ACTIVE_SPI_3W 0x0
+#define ADF4377_0000_SDO_ACTIVE_SPI_4W 0x1
+
+#define ADF4377_0000_ADDR_ASC_AUTO_DECR 0x0
+#define ADF4377_0000_ADDR_ASC_AUTO_INCR 0x1
+
+#define ADF4377_0000_LSB_FIRST_MSB 0x0
+#define ADF4377_0000_LSB_FIRST_LSB 0x1
+
+#define ADF4377_0000_SOFT_RESET_N_OP 0x0
+#define ADF4377_0000_SOFT_RESET_EN 0x1
+
+/* ADF4377 REG0001 Map */
+#define ADF4377_0001_SINGLE_INSTR_MSK BIT(7)
+#define ADF4377_0001_MASTER_RB_CTRL_MSK BIT(5)
+
+/* ADF4377 REG0003 Bit Definition */
+#define ADF4377_0003_CHIP_TYPE 0x06
+
+/* ADF4377 REG0004 Bit Definition */
+#define ADF4377_0004_PRODUCT_ID_LSB 0x0005
+
+/* ADF4377 REG0005 Bit Definition */
+#define ADF4377_0005_PRODUCT_ID_MSB 0x0005
+
+/* ADF4377 REG000A Map */
+#define ADF4377_000A_SCRATCHPAD_MSK GENMASK(7, 0)
+
+/* ADF4377 REG000C Bit Definition */
+#define ADF4377_000C_VENDOR_ID_LSB 0x56
+
+/* ADF4377 REG000D Bit Definition */
+#define ADF4377_000D_VENDOR_ID_MSB 0x04
+
+/* ADF4377 REG000F Bit Definition */
+#define ADF4377_000F_R00F_RSV1_MSK GENMASK(7, 0)
+
+/* ADF4377 REG0010 Map*/
+#define ADF4377_0010_N_INT_LSB_MSK GENMASK(7, 0)
+
+/* ADF4377 REG0011 Map*/
+#define ADF4377_0011_EN_AUTOCAL_MSK BIT(7)
+#define ADF4377_0011_EN_RDBLR_MSK BIT(6)
+#define ADF4377_0011_DCLK_DIV2_MSK GENMASK(5, 4)
+#define ADF4377_0011_N_INT_MSB_MSK GENMASK(3, 0)
+
+/* ADF4377 REG0011 Bit Definition */
+#define ADF4377_0011_DCLK_DIV2_1 0x0
+#define ADF4377_0011_DCLK_DIV2_2 0x1
+#define ADF4377_0011_DCLK_DIV2_4 0x2
+#define ADF4377_0011_DCLK_DIV2_8 0x3
+
+/* ADF4377 REG0012 Map*/
+#define ADF4377_0012_CLKOUT_DIV_MSK GENMASK(7, 6)
+#define ADF4377_0012_R_DIV_MSK GENMASK(5, 0)
+
+/* ADF4377 REG0012 Bit Definition */
+#define ADF4377_0012_CLKOUT_DIV_1 0x0
+#define ADF4377_0012_CLKOUT_DIV_2 0x1
+#define ADF4377_0012_CLKOUT_DIV_4 0x2
+#define ADF4377_0012_CLKOUT_DIV_8 0x3
+
+/* ADF4377 REG0013 Map */
+#define ADF4377_0013_M_VCO_CORE_MSK GENMASK(5, 4)
+#define ADF4377_0013_VCO_BIAS_MSK GENMASK(3, 0)
+
+/* ADF4377 REG0013 Bit Definition */
+#define ADF4377_0013_M_VCO_0 0x0
+#define ADF4377_0013_M_VCO_1 0x1
+#define ADF4377_0013_M_VCO_2 0x2
+#define ADF4377_0013_M_VCO_3 0x3
+
+/* ADF4377 REG0014 Map */
+#define ADF4377_0014_M_VCO_BAND_MSK GENMASK(7, 0)
+
+/* ADF4377 REG0015 Map */
+#define ADF4377_0015_BLEED_I_LSB_MSK GENMASK(7, 6)
+#define ADF4377_0015_BLEED_POL_MSK BIT(5)
+#define ADF4377_0015_EN_BLEED_MSK BIT(4)
+#define ADF4377_0015_CP_I_MSK GENMASK(3, 0)
+
+/* ADF4377 REG0015 Bit Definition */
+#define ADF4377_CURRENT_SINK 0x0
+#define ADF4377_CURRENT_SOURCE 0x1
+
+#define ADF4377_0015_CP_0MA7 0x0
+#define ADF4377_0015_CP_0MA9 0x1
+#define ADF4377_0015_CP_1MA1 0x2
+#define ADF4377_0015_CP_1MA3 0x3
+#define ADF4377_0015_CP_1MA4 0x4
+#define ADF4377_0015_CP_1MA8 0x5
+#define ADF4377_0015_CP_2MA2 0x6
+#define ADF4377_0015_CP_2MA5 0x7
+#define ADF4377_0015_CP_2MA9 0x8
+#define ADF4377_0015_CP_3MA6 0x9
+#define ADF4377_0015_CP_4MA3 0xA
+#define ADF4377_0015_CP_5MA0 0xB
+#define ADF4377_0015_CP_5MA7 0xC
+#define ADF4377_0015_CP_7MA2 0xD
+#define ADF4377_0015_CP_8MA6 0xE
+#define ADF4377_0015_CP_10MA1 0xF
+
+/* ADF4377 REG0016 Map */
+#define ADF4377_0016_BLEED_I_MSB_MSK GENMASK(7, 0)
+
+/* ADF4377 REG0017 Map */
+#define ADF4377_0016_INV_CLKOUT_MSK BIT(7)
+#define ADF4377_0016_N_DEL_MSK GENMASK(6, 0)
+
+/* ADF4377 REG0018 Map */
+#define ADF4377_0018_CMOS_OV_MSK BIT(7)
+#define ADF4377_0018_R_DEL_MSK GENMASK(6, 0)
+
+/* ADF4377 REG0018 Bit Definition */
+#define ADF4377_0018_1V8_LOGIC 0x0
+#define ADF4377_0018_3V3_LOGIC 0x1
+
+/* ADF4377 REG0019 Map */
+#define ADF4377_0019_CLKOUT2_OP_MSK GENMASK(7, 6)
+#define ADF4377_0019_CLKOUT1_OP_MSK GENMASK(5, 4)
+#define ADF4377_0019_PD_CLK_MSK BIT(3)
+#define ADF4377_0019_PD_RDET_MSK BIT(2)
+#define ADF4377_0019_PD_ADC_MSK BIT(1)
+#define ADF4377_0019_PD_CALADC_MSK BIT(0)
+
+/* ADF4377 REG0019 Bit Definition */
+#define ADF4377_0019_CLKOUT_320MV 0x0
+#define ADF4377_0019_CLKOUT_420MV 0x1
+#define ADF4377_0019_CLKOUT_530MV 0x2
+#define ADF4377_0019_CLKOUT_640MV 0x3
+
+/* ADF4377 REG001A Map */
+#define ADF4377_001A_PD_ALL_MSK BIT(7)
+#define ADF4377_001A_PD_RDIV_MSK BIT(6)
+#define ADF4377_001A_PD_NDIV_MSK BIT(5)
+#define ADF4377_001A_PD_VCO_MSK BIT(4)
+#define ADF4377_001A_PD_LD_MSK BIT(3)
+#define ADF4377_001A_PD_PFDCP_MSK BIT(2)
+#define ADF4377_001A_PD_CLKOUT1_MSK BIT(1)
+#define ADF4377_001A_PD_CLKOUT2_MSK BIT(0)
+
+/* ADF4377 REG001B Map */
+#define ADF4377_001B_EN_LOL_MSK BIT(7)
+#define ADF4377_001B_LDWIN_PW_MSK BIT(6)
+#define ADF4377_001B_EN_LDWIN_MSK BIT(5)
+#define ADF4377_001B_LD_COUNT_MSK GENMASK(4, 0)
+
+/* ADF4377 REG001B Bit Definition */
+#define ADF4377_001B_LDWIN_PW_NARROW 0x0
+#define ADF4377_001B_LDWIN_PW_WIDE 0x1
+
+/* ADF4377 REG001C Map */
+#define ADF4377_001C_EN_DNCLK_MSK BIT(7)
+#define ADF4377_001C_EN_DRCLK_MSK BIT(6)
+#define ADF4377_001C_RST_LD_MSK BIT(2)
+#define ADF4377_001C_R01C_RSV1_MSK BIT(0)
+
+/* ADF4377 REG001C Bit Definition */
+#define ADF4377_001C_RST_LD_INACTIVE 0x0
+#define ADF4377_001C_RST_LD_ACTIVE 0x1
+
+#define ADF4377_001C_R01C_RSV1 0x1
+
+/* ADF4377 REG001D Map */
+#define ADF4377_001D_MUXOUT_MSK GENMASK(7, 4)
+#define ADF4377_001D_EN_CPTEST_MSK BIT(2)
+#define ADF4377_001D_CP_DOWN_MSK BIT(1)
+#define ADF4377_001D_CP_UP_MSK BIT(0)
+
+#define ADF4377_001D_EN_CPTEST_OFF 0x0
+#define ADF4377_001D_EN_CPTEST_ON 0x1
+
+#define ADF4377_001D_CP_DOWN_OFF 0x0
+#define ADF4377_001D_CP_DOWN_ON 0x1
+
+#define ADF4377_001D_CP_UP_OFF 0x0
+#define ADF4377_001D_CP_UP_ON 0x1
+
+/* ADF4377 REG001F Map */
+#define ADF4377_001F_BST_REF_MSK BIT(7)
+#define ADF4377_001F_FILT_REF_MSK BIT(6)
+#define ADF4377_001F_REF_SEL_MSK BIT(5)
+#define ADF4377_001F_R01F_RSV1_MSK GENMASK(4, 0)
+
+/* ADF4377 REG001F Bit Definition */
+#define ADF4377_001F_BST_LARGE_REF_IN 0x0
+#define ADF4377_001F_BST_SMALL_REF_IN 0x1
+
+#define ADF4377_001F_FILT_REF_OFF 0x0
+#define ADF4377_001F_FILT_REF_ON 0x1
+
+#define ADF4377_001F_REF_SEL_DMA 0x0
+#define ADF4377_001F_REF_SEL_LNA 0x1
+
+#define ADF4377_001F_R01F_RSV1 0x7
+
+/* ADF4377 REG0020 Map */
+#define ADF4377_0020_RST_SYS_MSK BIT(4)
+#define ADF4377_0020_EN_ADC_CLK_MSK BIT(3)
+#define ADF4377_0020_R020_RSV1_MSK BIT(0)
+
+/* ADF4377 REG0021 Bit Definition */
+#define ADF4377_0021_R021_RSV1 0xD3
+
+/* ADF4377 REG0022 Bit Definition */
+#define ADF4377_0022_R022_RSV1 0x32
+
+/* ADF4377 REG0023 Map */
+#define ADF4377_0023_CAT_CT_SEL BIT(7)
+#define ADF4377_0023_R023_RSV1_MSK GENMASK(6, 0)
+
+/* ADF4377 REG0023 Bit Definition */
+#define ADF4377_0023_R023_RSV1 0x18
+
+/* ADF4377 REG0024 Map */
+#define ADF4377_0024_DCLK_MODE_MSK BIT(2)
+
+/* ADF4377 REG0025 Map */
+#define ADF4377_0025_CLKODIV_DB_MSK BIT(7)
+#define ADF4377_0025_DCLK_DB_MSK BIT(6)
+#define ADF4377_0025_R025_RSV1_MSK GENMASK(5, 0)
+
+/* ADF4377 REG0025 Bit Definition */
+#define ADF4377_0025_R025_RSV1 0x16
+
+/* ADF4377 REG0026 Map */
+#define ADF4377_0026_VCO_BAND_DIV_MSK GENMASK(7, 0)
+
+/* ADF4377 REG0027 Map */
+#define ADF4377_0027_SYNTH_LOCK_TO_LSB_MSK GENMASK(7, 0)
+
+/* ADF4377 REG0028 Map */
+#define ADF4377_0028_O_VCO_DB_MSK BIT(7)
+#define ADF4377_0028_SYNTH_LOCK_TO_MSB_MSK GENMASK(6, 0)
+
+/* ADF4377 REG0029 Map */
+#define ADF4377_0029_VCO_ALC_TO_LSB_MSK GENMASK(7, 0)
+
+/* ADF4377 REG002A Map */
+#define ADF4377_002A_DEL_CTRL_DB_MSK BIT(7)
+#define ADF4377_002A_VCO_ALC_TO_MSB_MSK GENMASK(6, 0)
+
+/* ADF4377 REG002C Map */
+#define ADF4377_002C_R02C_RSV1 0xC0
+
+/* ADF4377 REG002D Map */
+#define ADF4377_002D_ADC_CLK_DIV_MSK GENMASK(7, 0)
+
+/* ADF4377 REG002E Map */
+#define ADF4377_002E_EN_ADC_CNV_MSK BIT(7)
+#define ADF4377_002E_EN_ADC_MSK BIT(1)
+#define ADF4377_002E_ADC_A_CONV_MSK BIT(0)
+
+/* ADF4377 REG002E Bit Definition */
+#define ADF4377_002E_ADC_A_CONV_ADC_ST_CNV 0x0
+#define ADF4377_002E_ADC_A_CONV_VCO_CALIB 0x1
+
+/* ADF4377 REG002F Map */
+#define ADF4377_002F_DCLK_DIV1_MSK GENMASK(1, 0)
+
+/* ADF4377 REG002F Bit Definition */
+#define ADF4377_002F_DCLK_DIV1_1 0x0
+#define ADF4377_002F_DCLK_DIV1_2 0x1
+#define ADF4377_002F_DCLK_DIV1_8 0x2
+#define ADF4377_002F_DCLK_DIV1_32 0x3
+
+/* ADF4377 REG0031 Bit Definition */
+#define ADF4377_0031_R031_RSV1 0x09
+
+/* ADF4377 REG0032 Map */
+#define ADF4377_0032_ADC_CLK_SEL_MSK BIT(6)
+#define ADF4377_0032_R032_RSV1_MSK GENMASK(5, 0)
+
+/* ADF4377 REG0032 Bit Definition */
+#define ADF4377_0032_ADC_CLK_SEL_N_OP 0x0
+#define ADF4377_0032_ADC_CLK_SEL_SPI_CLK 0x1
+
+#define ADF4377_0032_R032_RSV1 0x9
+
+/* ADF4377 REG0033 Bit Definition */
+#define ADF4377_0033_R033_RSV1 0x18
+
+/* ADF4377 REG0034 Bit Definition */
+#define ADF4377_0034_R034_RSV1 0x08
+
+/* ADF4377 REG003A Bit Definition */
+#define ADF4377_003A_R03A_RSV1 0x5D
+
+/* ADF4377 REG003B Bit Definition */
+#define ADF4377_003B_R03B_RSV1 0x2B
+
+/* ADF4377 REG003D Map */
+#define ADF4377_003D_O_VCO_BAND_MSK BIT(3)
+#define ADF4377_003D_O_VCO_CORE_MSK BIT(2)
+#define ADF4377_003D_O_VCO_BIAS_MSK BIT(1)
+
+/* ADF4377 REG003D Bit Definition */
+#define ADF4377_003D_O_VCO_BAND_VCO_CALIB 0x0
+#define ADF4377_003D_O_VCO_BAND_M_VCO 0x1
+
+#define ADF4377_003D_O_VCO_CORE_VCO_CALIB 0x0
+#define ADF4377_003D_O_VCO_CORE_M_VCO 0x1
+
+#define ADF4377_003D_O_VCO_BIAS_VCO_CALIB 0x0
+#define ADF4377_003D_O_VCO_BIAS_M_VCO 0x1
+
+/* ADF4377 REG0042 Map */
+#define ADF4377_0042_R042_RSV1 0x05
+
+/* ADF4377 REG0045 Map */
+#define ADF4377_0045_ADC_ST_CNV_MSK BIT(0)
+
+/* ADF4377 REG0049 Map */
+#define ADF4377_0049_EN_CLK2_MSK BIT(7)
+#define ADF4377_0049_EN_CLK1_MSK BIT(6)
+#define ADF4377_0049_REF_OK_MSK BIT(3)
+#define ADF4377_0049_ADC_BUSY_MSK BIT(2)
+#define ADF4377_0049_FSM_BUSY_MSK BIT(1)
+#define ADF4377_0049_LOCKED_MSK BIT(0)
+
+/* ADF4377 REG004B Map */
+#define ADF4377_004B_VCO_CORE_MSK GENMASK(1, 0)
+
+/* ADF4377 REG004C Map */
+#define ADF4377_004C_CHIP_TEMP_LSB_MSK GENMASK(7, 0)
+
+/* ADF4377 REG004D Map */
+#define ADF4377_004D_CHIP_TEMP_MSB_MSK BIT(0)
+
+/* ADF4377 REG004F Map */
+#define ADF4377_004F_VCO_BAND_MSK GENMASK(7, 0)
+
+/* ADF4377 REG0051 Map */
+#define ADF4377_0051_VCO_BIAS_MSK GENMASK(3, 0)
+
+/* ADF4377 REG0054 Map */
+#define ADF4377_0054_CHIP_VERSION_MSK GENMASK(7, 0)
+
+/* Specifications */
+#define ADF4377_SPI_READ_CMD BIT(7)
+#define ADF4377_MAX_VCO_FREQ (12800ULL * HZ_PER_MHZ)
+#define ADF4377_MIN_VCO_FREQ (6400ULL * HZ_PER_MHZ)
+#define ADF4377_MAX_REFIN_FREQ (1000 * HZ_PER_MHZ)
+#define ADF4377_MIN_REFIN_FREQ (10 * HZ_PER_MHZ)
+#define ADF4377_MAX_FREQ_PFD (500 * HZ_PER_MHZ)
+#define ADF4377_MIN_FREQ_PFD (3 * HZ_PER_MHZ)
+#define ADF4377_MAX_CLKPN_FREQ ADF4377_MAX_VCO_FREQ
+#define ADF4377_MIN_CLKPN_FREQ (ADF4377_MIN_VCO_FREQ / 8)
+#define ADF4377_FREQ_PFD_80MHZ (80 * HZ_PER_MHZ)
+#define ADF4377_FREQ_PFD_125MHZ (125 * HZ_PER_MHZ)
+#define ADF4377_FREQ_PFD_160MHZ (160 * HZ_PER_MHZ)
+#define ADF4377_FREQ_PFD_250MHZ (250 * HZ_PER_MHZ)
+#define ADF4377_FREQ_PFD_320MHZ (320 * HZ_PER_MHZ)
+
+enum {
+ ADF4377_FREQ,
+};
+
+enum muxout_select_mode {
+ ADF4377_MUXOUT_HIGH_Z = 0x0,
+ ADF4377_MUXOUT_LKDET = 0x1,
+ ADF4377_MUXOUT_LOW = 0x2,
+ ADF4377_MUXOUT_DIV_RCLK_2 = 0x4,
+ ADF4377_MUXOUT_DIV_NCLK_2 = 0x5,
+ ADF4377_MUXOUT_HIGH = 0x8,
+};
+
+struct adf4377_state {
+ struct spi_device *spi;
+ struct regmap *regmap;
+ struct clk *clkin;
+ /* Protect against concurrent accesses to the device and data content */
+ struct mutex lock;
+ struct notifier_block nb;
+ /* Reference Divider */
+ unsigned int ref_div_factor;
+ /* PFD Frequency */
+ unsigned int f_pfd;
+ /* Input Reference Clock */
+ unsigned int clkin_freq;
+ /* CLKOUT Divider */
+ u8 clkout_div_sel;
+ /* Feedback Divider (N) */
+ u16 n_int;
+ u16 synth_lock_timeout;
+ u16 vco_alc_timeout;
+ u16 adc_clk_div;
+ u16 vco_band_div;
+ u8 dclk_div1;
+ u8 dclk_div2;
+ u8 dclk_mode;
+ unsigned int f_div_rclk;
+ enum muxout_select_mode muxout_select;
+ struct gpio_desc *gpio_ce;
+ struct gpio_desc *gpio_enclk1;
+ struct gpio_desc *gpio_enclk2;
+ u8 buf[2] __aligned(IIO_DMA_MINALIGN);
+};
+
+static const char * const adf4377_muxout_modes[] = {
+ [ADF4377_MUXOUT_HIGH_Z] = "high_z",
+ [ADF4377_MUXOUT_LKDET] = "lock_detect",
+ [ADF4377_MUXOUT_LOW] = "muxout_low",
+ [ADF4377_MUXOUT_DIV_RCLK_2] = "f_div_rclk_2",
+ [ADF4377_MUXOUT_DIV_NCLK_2] = "f_div_nclk_2",
+ [ADF4377_MUXOUT_HIGH] = "muxout_high",
+};
+
+static const struct reg_sequence adf4377_reg_defaults[] = {
+ { 0x42, ADF4377_0042_R042_RSV1 },
+ { 0x3B, ADF4377_003B_R03B_RSV1 },
+ { 0x3A, ADF4377_003A_R03A_RSV1 },
+ { 0x34, ADF4377_0034_R034_RSV1 },
+ { 0x33, ADF4377_0033_R033_RSV1 },
+ { 0x32, ADF4377_0032_R032_RSV1 },
+ { 0x31, ADF4377_0031_R031_RSV1 },
+ { 0x2C, ADF4377_002C_R02C_RSV1 },
+ { 0x25, ADF4377_0025_R025_RSV1 },
+ { 0x23, ADF4377_0023_R023_RSV1 },
+ { 0x22, ADF4377_0022_R022_RSV1 },
+ { 0x21, ADF4377_0021_R021_RSV1 },
+ { 0x1f, ADF4377_001F_R01F_RSV1 },
+ { 0x1c, ADF4377_001C_R01C_RSV1 },
+};
+
+static const struct regmap_config adf4377_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .read_flag_mask = BIT(7),
+ .max_register = 0x54,
+};
+
+static int adf4377_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg,
+ unsigned int write_val,
+ unsigned int *read_val)
+{
+ struct adf4377_state *st = iio_priv(indio_dev);
+
+ if (read_val)
+ return regmap_read(st->regmap, reg, read_val);
+
+ return regmap_write(st->regmap, reg, write_val);
+}
+
+static const struct iio_info adf4377_info = {
+ .debugfs_reg_access = &adf4377_reg_access,
+};
+
+static int adf4377_soft_reset(struct adf4377_state *st)
+{
+ unsigned int read_val;
+ int ret;
+
+ ret = regmap_update_bits(st->regmap, 0x0, ADF4377_0000_SOFT_RESET_MSK |
+ ADF4377_0000_SOFT_RESET_R_MSK,
+ FIELD_PREP(ADF4377_0000_SOFT_RESET_MSK, 1) |
+ FIELD_PREP(ADF4377_0000_SOFT_RESET_R_MSK, 1));
+ if (ret)
+ return ret;
+
+ return regmap_read_poll_timeout(st->regmap, 0x0, read_val,
+ !(read_val & (ADF4377_0000_SOFT_RESET_R_MSK |
+ ADF4377_0000_SOFT_RESET_R_MSK)), 200, 200 * 100);
+}
+
+static int adf4377_get_freq(struct adf4377_state *st, u64 *freq)
+{
+ unsigned int ref_div_factor, n_int;
+ u64 clkin_freq;
+ int ret;
+
+ mutex_lock(&st->lock);
+ ret = regmap_read(st->regmap, 0x12, &ref_div_factor);
+ if (ret)
+ goto exit;
+
+ ret = regmap_bulk_read(st->regmap, 0x10, st->buf, sizeof(st->buf));
+ if (ret)
+ goto exit;
+
+ clkin_freq = clk_get_rate(st->clkin);
+ ref_div_factor = FIELD_GET(ADF4377_0012_R_DIV_MSK, ref_div_factor);
+ n_int = FIELD_GET(ADF4377_0010_N_INT_LSB_MSK | ADF4377_0011_N_INT_MSB_MSK,
+ get_unaligned_le16(&st->buf));
+
+ *freq = div_u64(clkin_freq, ref_div_factor) * n_int;
+exit:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int adf4377_set_freq(struct adf4377_state *st, u64 freq)
+{
+ unsigned int read_val;
+ u64 f_vco;
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ if (freq > ADF4377_MAX_CLKPN_FREQ || freq < ADF4377_MIN_CLKPN_FREQ) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = regmap_update_bits(st->regmap, 0x1C, ADF4377_001C_EN_DNCLK_MSK |
+ ADF4377_001C_EN_DRCLK_MSK,
+ FIELD_PREP(ADF4377_001C_EN_DNCLK_MSK, 1) |
+ FIELD_PREP(ADF4377_001C_EN_DRCLK_MSK, 1));
+ if (ret)
+ goto exit;
+
+ ret = regmap_update_bits(st->regmap, 0x11, ADF4377_0011_EN_AUTOCAL_MSK |
+ ADF4377_0011_DCLK_DIV2_MSK,
+ FIELD_PREP(ADF4377_0011_EN_AUTOCAL_MSK, 1) |
+ FIELD_PREP(ADF4377_0011_DCLK_DIV2_MSK, st->dclk_div2));
+ if (ret)
+ goto exit;
+
+ ret = regmap_update_bits(st->regmap, 0x2E, ADF4377_002E_EN_ADC_CNV_MSK |
+ ADF4377_002E_EN_ADC_MSK |
+ ADF4377_002E_ADC_A_CONV_MSK,
+ FIELD_PREP(ADF4377_002E_EN_ADC_CNV_MSK, 1) |
+ FIELD_PREP(ADF4377_002E_EN_ADC_MSK, 1) |
+ FIELD_PREP(ADF4377_002E_ADC_A_CONV_MSK,
+ ADF4377_002E_ADC_A_CONV_VCO_CALIB));
+ if (ret)
+ goto exit;
+
+ ret = regmap_update_bits(st->regmap, 0x20, ADF4377_0020_EN_ADC_CLK_MSK,
+ FIELD_PREP(ADF4377_0020_EN_ADC_CLK_MSK, 1));
+ if (ret)
+ goto exit;
+
+ ret = regmap_update_bits(st->regmap, 0x2F, ADF4377_002F_DCLK_DIV1_MSK,
+ FIELD_PREP(ADF4377_002F_DCLK_DIV1_MSK, st->dclk_div1));
+ if (ret)
+ goto exit;
+
+ ret = regmap_update_bits(st->regmap, 0x24, ADF4377_0024_DCLK_MODE_MSK,
+ FIELD_PREP(ADF4377_0024_DCLK_MODE_MSK, st->dclk_mode));
+ if (ret)
+ goto exit;
+
+ ret = regmap_write(st->regmap, 0x27,
+ FIELD_PREP(ADF4377_0027_SYNTH_LOCK_TO_LSB_MSK,
+ st->synth_lock_timeout));
+ if (ret)
+ goto exit;
+
+ ret = regmap_update_bits(st->regmap, 0x28, ADF4377_0028_SYNTH_LOCK_TO_MSB_MSK,
+ FIELD_PREP(ADF4377_0028_SYNTH_LOCK_TO_MSB_MSK,
+ st->synth_lock_timeout >> 8));
+ if (ret)
+ goto exit;
+
+ ret = regmap_write(st->regmap, 0x29,
+ FIELD_PREP(ADF4377_0029_VCO_ALC_TO_LSB_MSK,
+ st->vco_alc_timeout));
+ if (ret)
+ goto exit;
+
+ ret = regmap_update_bits(st->regmap, 0x2A, ADF4377_002A_VCO_ALC_TO_MSB_MSK,
+ FIELD_PREP(ADF4377_002A_VCO_ALC_TO_MSB_MSK,
+ st->vco_alc_timeout >> 8));
+ if (ret)
+ goto exit;
+
+ ret = regmap_write(st->regmap, 0x26,
+ FIELD_PREP(ADF4377_0026_VCO_BAND_DIV_MSK, st->vco_band_div));
+ if (ret)
+ goto exit;
+
+ ret = regmap_write(st->regmap, 0x2D,
+ FIELD_PREP(ADF4377_002D_ADC_CLK_DIV_MSK, st->adc_clk_div));
+ if (ret)
+ goto exit;
+
+ st->clkout_div_sel = 0;
+
+ f_vco = freq;
+
+ while (f_vco < ADF4377_MIN_VCO_FREQ) {
+ f_vco <<= 1;
+ st->clkout_div_sel++;
+ }
+
+ st->n_int = div_u64(freq, st->f_pfd);
+
+ ret = regmap_update_bits(st->regmap, 0x11, ADF4377_0011_EN_RDBLR_MSK |
+ ADF4377_0011_N_INT_MSB_MSK,
+ FIELD_PREP(ADF4377_0011_EN_RDBLR_MSK, 0) |
+ FIELD_PREP(ADF4377_0011_N_INT_MSB_MSK, st->n_int >> 8));
+ if (ret)
+ goto exit;
+
+ ret = regmap_update_bits(st->regmap, 0x12, ADF4377_0012_R_DIV_MSK |
+ ADF4377_0012_CLKOUT_DIV_MSK,
+ FIELD_PREP(ADF4377_0012_CLKOUT_DIV_MSK, st->clkout_div_sel) |
+ FIELD_PREP(ADF4377_0012_R_DIV_MSK, st->ref_div_factor));
+ if (ret)
+ goto exit;
+
+ ret = regmap_write(st->regmap, 0x10,
+ FIELD_PREP(ADF4377_0010_N_INT_LSB_MSK, st->n_int));
+ if (ret)
+ goto exit;
+
+ ret = regmap_read_poll_timeout(st->regmap, 0x49, read_val,
+ !(read_val & (ADF4377_0049_FSM_BUSY_MSK)), 200, 200 * 100);
+ if (ret)
+ goto exit;
+
+ /* Disable EN_DNCLK, EN_DRCLK */
+ ret = regmap_update_bits(st->regmap, 0x1C, ADF4377_001C_EN_DNCLK_MSK |
+ ADF4377_001C_EN_DRCLK_MSK,
+ FIELD_PREP(ADF4377_001C_EN_DNCLK_MSK, 0) |
+ FIELD_PREP(ADF4377_001C_EN_DRCLK_MSK, 0));
+ if (ret)
+ goto exit;
+
+ /* Disable EN_ADC_CLK */
+ ret = regmap_update_bits(st->regmap, 0x20, ADF4377_0020_EN_ADC_CLK_MSK,
+ FIELD_PREP(ADF4377_0020_EN_ADC_CLK_MSK, 0));
+ if (ret)
+ goto exit;
+
+ /* Set output Amplitude */
+ ret = regmap_update_bits(st->regmap, 0x19, ADF4377_0019_CLKOUT2_OP_MSK |
+ ADF4377_0019_CLKOUT1_OP_MSK,
+ FIELD_PREP(ADF4377_0019_CLKOUT1_OP_MSK,
+ ADF4377_0019_CLKOUT_420MV) |
+ FIELD_PREP(ADF4377_0019_CLKOUT2_OP_MSK,
+ ADF4377_0019_CLKOUT_420MV));
+
+exit:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static void adf4377_gpio_init(struct adf4377_state *st)
+{
+ if (st->gpio_ce) {
+ gpiod_set_value(st->gpio_ce, 1);
+
+ /* Delay for SPI register bits to settle to their power-on reset state */
+ fsleep(200);
+ }
+
+ if (st->gpio_enclk1)
+ gpiod_set_value(st->gpio_enclk1, 1);
+
+ if (st->gpio_enclk2)
+ gpiod_set_value(st->gpio_enclk2, 1);
+}
+
+static int adf4377_init(struct adf4377_state *st)
+{
+ struct spi_device *spi = st->spi;
+ int ret;
+
+ adf4377_gpio_init(st);
+
+ ret = adf4377_soft_reset(st);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to soft reset.\n");
+ return ret;
+ }
+
+ ret = regmap_multi_reg_write(st->regmap, adf4377_reg_defaults,
+ ARRAY_SIZE(adf4377_reg_defaults));
+ if (ret) {
+ dev_err(&spi->dev, "Failed to set default registers.\n");
+ return ret;
+ }
+
+ ret = regmap_update_bits(st->regmap, 0x00,
+ ADF4377_0000_SDO_ACTIVE_MSK | ADF4377_0000_SDO_ACTIVE_R_MSK,
+ FIELD_PREP(ADF4377_0000_SDO_ACTIVE_MSK,
+ ADF4377_0000_SDO_ACTIVE_SPI_4W) |
+ FIELD_PREP(ADF4377_0000_SDO_ACTIVE_R_MSK,
+ ADF4377_0000_SDO_ACTIVE_SPI_4W));
+ if (ret) {
+ dev_err(&spi->dev, "Failed to set 4-Wire Operation.\n");
+ return ret;
+ }
+
+ st->clkin_freq = clk_get_rate(st->clkin);
+
+ /* Power Up */
+ ret = regmap_write(st->regmap, 0x1a,
+ FIELD_PREP(ADF4377_001A_PD_ALL_MSK, 0) |
+ FIELD_PREP(ADF4377_001A_PD_RDIV_MSK, 0) |
+ FIELD_PREP(ADF4377_001A_PD_NDIV_MSK, 0) |
+ FIELD_PREP(ADF4377_001A_PD_VCO_MSK, 0) |
+ FIELD_PREP(ADF4377_001A_PD_LD_MSK, 0) |
+ FIELD_PREP(ADF4377_001A_PD_PFDCP_MSK, 0) |
+ FIELD_PREP(ADF4377_001A_PD_CLKOUT1_MSK, 0) |
+ FIELD_PREP(ADF4377_001A_PD_CLKOUT2_MSK, 0));
+ if (ret) {
+ dev_err(&spi->dev, "Failed to set power down registers.\n");
+ return ret;
+ }
+
+ /* Set Mux Output */
+ ret = regmap_update_bits(st->regmap, 0x1D,
+ ADF4377_001D_MUXOUT_MSK,
+ FIELD_PREP(ADF4377_001D_MUXOUT_MSK, st->muxout_select));
+ if (ret)
+ return ret;
+
+ /* Compute PFD */
+ st->ref_div_factor = 0;
+ do {
+ st->ref_div_factor++;
+ st->f_pfd = st->clkin_freq / st->ref_div_factor;
+ } while (st->f_pfd > ADF4377_MAX_FREQ_PFD);
+
+ if (st->f_pfd > ADF4377_MAX_FREQ_PFD || st->f_pfd < ADF4377_MIN_FREQ_PFD)
+ return -EINVAL;
+
+ st->f_div_rclk = st->f_pfd;
+
+ if (st->f_pfd <= ADF4377_FREQ_PFD_80MHZ) {
+ st->dclk_div1 = ADF4377_002F_DCLK_DIV1_1;
+ st->dclk_div2 = ADF4377_0011_DCLK_DIV2_1;
+ st->dclk_mode = 0;
+ } else if (st->f_pfd <= ADF4377_FREQ_PFD_125MHZ) {
+ st->dclk_div1 = ADF4377_002F_DCLK_DIV1_1;
+ st->dclk_div2 = ADF4377_0011_DCLK_DIV2_1;
+ st->dclk_mode = 1;
+ } else if (st->f_pfd <= ADF4377_FREQ_PFD_160MHZ) {
+ st->dclk_div1 = ADF4377_002F_DCLK_DIV1_2;
+ st->dclk_div2 = ADF4377_0011_DCLK_DIV2_1;
+ st->dclk_mode = 0;
+ st->f_div_rclk /= 2;
+ } else if (st->f_pfd <= ADF4377_FREQ_PFD_250MHZ) {
+ st->dclk_div1 = ADF4377_002F_DCLK_DIV1_2;
+ st->dclk_div2 = ADF4377_0011_DCLK_DIV2_1;
+ st->dclk_mode = 1;
+ st->f_div_rclk /= 2;
+ } else if (st->f_pfd <= ADF4377_FREQ_PFD_320MHZ) {
+ st->dclk_div1 = ADF4377_002F_DCLK_DIV1_2;
+ st->dclk_div2 = ADF4377_0011_DCLK_DIV2_2;
+ st->dclk_mode = 0;
+ st->f_div_rclk /= 4;
+ } else {
+ st->dclk_div1 = ADF4377_002F_DCLK_DIV1_2;
+ st->dclk_div2 = ADF4377_0011_DCLK_DIV2_2;
+ st->dclk_mode = 1;
+ st->f_div_rclk /= 4;
+ }
+
+ st->synth_lock_timeout = DIV_ROUND_UP(st->f_div_rclk, 50000);
+ st->vco_alc_timeout = DIV_ROUND_UP(st->f_div_rclk, 20000);
+ st->vco_band_div = DIV_ROUND_UP(st->f_div_rclk, 150000 * 16 * (1 << st->dclk_mode));
+ st->adc_clk_div = DIV_ROUND_UP((st->f_div_rclk / 400000 - 2), 4);
+
+ return 0;
+}
+
+static ssize_t adf4377_read(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan, char *buf)
+{
+ struct adf4377_state *st = iio_priv(indio_dev);
+ u64 val = 0;
+ int ret;
+
+ switch ((u32)private) {
+ case ADF4377_FREQ:
+ ret = adf4377_get_freq(st, &val);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%llu\n", val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t adf4377_write(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan, const char *buf,
+ size_t len)
+{
+ struct adf4377_state *st = iio_priv(indio_dev);
+ unsigned long long freq;
+ int ret;
+
+ switch ((u32)private) {
+ case ADF4377_FREQ:
+ ret = kstrtoull(buf, 10, &freq);
+ if (ret)
+ return ret;
+
+ ret = adf4377_set_freq(st, freq);
+ if (ret)
+ return ret;
+
+ return len;
+ default:
+ return -EINVAL;
+ }
+}
+
+#define _ADF4377_EXT_INFO(_name, _shared, _ident) { \
+ .name = _name, \
+ .read = adf4377_read, \
+ .write = adf4377_write, \
+ .private = _ident, \
+ .shared = _shared, \
+ }
+
+static const struct iio_chan_spec_ext_info adf4377_ext_info[] = {
+ /*
+ * Usually we use IIO_CHAN_INFO_FREQUENCY, but there are
+ * values > 2^32 in order to support the entire frequency range
+ * in Hz.
+ */
+ _ADF4377_EXT_INFO("frequency", IIO_SEPARATE, ADF4377_FREQ),
+ { }
+};
+
+static const struct iio_chan_spec adf4377_channels[] = {
+ {
+ .type = IIO_ALTVOLTAGE,
+ .indexed = 1,
+ .output = 1,
+ .channel = 0,
+ .ext_info = adf4377_ext_info,
+ },
+};
+
+static int adf4377_properties_parse(struct adf4377_state *st)
+{
+ struct spi_device *spi = st->spi;
+ const char *str;
+ int ret;
+
+ st->clkin = devm_clk_get_enabled(&spi->dev, "ref_in");
+ if (IS_ERR(st->clkin))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
+ "failed to get the reference input clock\n");
+
+ st->gpio_ce = devm_gpiod_get_optional(&st->spi->dev, "chip-enable",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(st->gpio_ce))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_ce),
+ "failed to get the CE GPIO\n");
+
+ st->gpio_enclk1 = devm_gpiod_get_optional(&st->spi->dev, "clk1-enable",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(st->gpio_enclk1))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_enclk1),
+ "failed to get the CE GPIO\n");
+
+ st->gpio_enclk2 = devm_gpiod_get_optional(&st->spi->dev, "clk2-enable",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(st->gpio_enclk2))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_enclk2),
+ "failed to get the CE GPIO\n");
+
+ ret = device_property_read_string(&spi->dev, "adi,muxout-select", &str);
+ if (ret) {
+ st->muxout_select = ADF4377_MUXOUT_HIGH_Z;
+ } else {
+ ret = match_string(adf4377_muxout_modes, ARRAY_SIZE(adf4377_muxout_modes), str);
+ if (ret < 0)
+ return ret;
+
+ st->muxout_select = ret;
+ }
+
+ return 0;
+}
+
+static int adf4377_freq_change(struct notifier_block *nb, unsigned long action, void *data)
+{
+ struct adf4377_state *st = container_of(nb, struct adf4377_state, nb);
+ int ret;
+
+ if (action == POST_RATE_CHANGE) {
+ mutex_lock(&st->lock);
+ ret = notifier_from_errno(adf4377_init(st));
+ mutex_unlock(&st->lock);
+ return ret;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int adf4377_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ struct adf4377_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_spi(spi, &adf4377_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ st = iio_priv(indio_dev);
+
+ indio_dev->info = &adf4377_info;
+ indio_dev->name = "adf4377";
+ indio_dev->channels = adf4377_channels;
+ indio_dev->num_channels = ARRAY_SIZE(adf4377_channels);
+
+ st->regmap = regmap;
+ st->spi = spi;
+ mutex_init(&st->lock);
+
+ ret = adf4377_properties_parse(st);
+ if (ret)
+ return ret;
+
+ st->nb.notifier_call = adf4377_freq_change;
+ ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb);
+ if (ret)
+ return ret;
+
+ ret = adf4377_init(st);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id adf4377_id[] = {
+ { "adf4377", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, adf4377_id);
+
+static const struct of_device_id adf4377_of_match[] = {
+ { .compatible = "adi,adf4377" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, adf4377_of_match);
+
+static struct spi_driver adf4377_driver = {
+ .driver = {
+ .name = "adf4377",
+ .of_match_table = adf4377_of_match,
+ },
+ .probe = adf4377_probe,
+ .id_table = adf4377_id,
+};
+module_spi_driver(adf4377_driver);
+
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADF4377");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c
index 71295709f2b9..c95cf41be34b 100644
--- a/drivers/iio/gyro/adis16136.c
+++ b/drivers/iio/gyro/adis16136.c
@@ -429,7 +429,7 @@ static int adis16136_initial_setup(struct iio_dev *indio_dev)
uint16_t prod_id;
int ret;
- ret = adis_initial_startup(&adis16136->adis);
+ ret = __adis_initial_startup(&adis16136->adis);
if (ret)
return ret;
diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c
index eaf57bd339ed..112d635b7dfd 100644
--- a/drivers/iio/gyro/adis16260.c
+++ b/drivers/iio/gyro/adis16260.c
@@ -395,7 +395,7 @@ static int adis16260_probe(struct spi_device *spi)
return ret;
/* Get the device into a sane initial state */
- ret = adis_initial_startup(&adis16260->adis);
+ ret = __adis_initial_startup(&adis16260->adis);
if (ret)
return ret;
diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
index cedd9f02ea21..0e2eb0e98235 100644
--- a/drivers/iio/gyro/bmg160_core.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -93,7 +93,6 @@
struct bmg160_data {
struct regmap *regmap;
- struct regulator_bulk_data regulators[2];
struct iio_trigger *dready_trig;
struct iio_trigger *motion_trig;
struct iio_mount_matrix orientation;
@@ -1067,16 +1066,10 @@ static const char *bmg160_match_acpi_device(struct device *dev)
return dev_name(dev);
}
-static void bmg160_disable_regulators(void *d)
-{
- struct bmg160_data *data = d;
-
- regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
-}
-
int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name)
{
+ static const char * const regulators[] = { "vdd", "vddio" };
struct bmg160_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -1090,22 +1083,11 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
data->irq = irq;
data->regmap = regmap;
- data->regulators[0].supply = "vdd";
- data->regulators[1].supply = "vddio";
- ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators),
- data->regulators);
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators),
+ regulators);
if (ret)
return dev_err_probe(dev, ret, "Failed to get regulators\n");
- ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
- data->regulators);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(dev, bmg160_disable_regulators, data);
- if (ret)
- return ret;
-
ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c
index 908ccc385254..2b019ee5b2eb 100644
--- a/drivers/iio/gyro/bmg160_i2c.c
+++ b/drivers/iio/gyro/bmg160_i2c.c
@@ -13,9 +13,9 @@ static const struct regmap_config bmg160_regmap_i2c_conf = {
.max_register = 0x3f
};
-static int bmg160_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bmg160_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct regmap *regmap;
const char *name = NULL;
@@ -70,7 +70,7 @@ static struct i2c_driver bmg160_i2c_driver = {
.of_match_table = bmg160_of_match,
.pm = &bmg160_pm_ops,
},
- .probe = bmg160_i2c_probe,
+ .probe_new = bmg160_i2c_probe,
.remove = bmg160_i2c_remove,
.id_table = bmg160_i2c_id,
};
diff --git a/drivers/iio/gyro/fxas21002c_core.c b/drivers/iio/gyro/fxas21002c_core.c
index a36d71d9e3ea..3ea1d4613080 100644
--- a/drivers/iio/gyro/fxas21002c_core.c
+++ b/drivers/iio/gyro/fxas21002c_core.c
@@ -998,7 +998,7 @@ pm_disable:
return ret;
}
-EXPORT_SYMBOL_GPL(fxas21002c_core_probe);
+EXPORT_SYMBOL_NS_GPL(fxas21002c_core_probe, IIO_FXAS21002C);
void fxas21002c_core_remove(struct device *dev)
{
@@ -1009,9 +1009,9 @@ void fxas21002c_core_remove(struct device *dev)
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
}
-EXPORT_SYMBOL_GPL(fxas21002c_core_remove);
+EXPORT_SYMBOL_NS_GPL(fxas21002c_core_remove, IIO_FXAS21002C);
-static int __maybe_unused fxas21002c_suspend(struct device *dev)
+static int fxas21002c_suspend(struct device *dev)
{
struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
@@ -1021,7 +1021,7 @@ static int __maybe_unused fxas21002c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused fxas21002c_resume(struct device *dev)
+static int fxas21002c_resume(struct device *dev)
{
struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
int ret;
@@ -1033,26 +1033,25 @@ static int __maybe_unused fxas21002c_resume(struct device *dev)
return fxas21002c_mode_set(data, data->prev_mode);
}
-static int __maybe_unused fxas21002c_runtime_suspend(struct device *dev)
+static int fxas21002c_runtime_suspend(struct device *dev)
{
struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
return fxas21002c_mode_set(data, FXAS21002C_MODE_READY);
}
-static int __maybe_unused fxas21002c_runtime_resume(struct device *dev)
+static int fxas21002c_runtime_resume(struct device *dev)
{
struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
return fxas21002c_mode_set(data, FXAS21002C_MODE_ACTIVE);
}
-const struct dev_pm_ops fxas21002c_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(fxas21002c_suspend, fxas21002c_resume)
- SET_RUNTIME_PM_OPS(fxas21002c_runtime_suspend,
- fxas21002c_runtime_resume, NULL)
+EXPORT_NS_GPL_DEV_PM_OPS(fxas21002c_pm_ops, IIO_FXAS21002C) = {
+ SYSTEM_SLEEP_PM_OPS(fxas21002c_suspend, fxas21002c_resume)
+ RUNTIME_PM_OPS(fxas21002c_runtime_suspend, fxas21002c_runtime_resume,
+ NULL)
};
-EXPORT_SYMBOL_GPL(fxas21002c_pm_ops);
MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/gyro/fxas21002c_i2c.c b/drivers/iio/gyro/fxas21002c_i2c.c
index 13bb52c594d1..9e2d0f34a672 100644
--- a/drivers/iio/gyro/fxas21002c_i2c.c
+++ b/drivers/iio/gyro/fxas21002c_i2c.c
@@ -53,7 +53,7 @@ MODULE_DEVICE_TABLE(of, fxas21002c_i2c_of_match);
static struct i2c_driver fxas21002c_i2c_driver = {
.driver = {
.name = "fxas21002c_i2c",
- .pm = &fxas21002c_pm_ops,
+ .pm = pm_ptr(&fxas21002c_pm_ops),
.of_match_table = fxas21002c_i2c_of_match,
},
.probe_new = fxas21002c_i2c_probe,
@@ -65,3 +65,4 @@ module_i2c_driver(fxas21002c_i2c_driver);
MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("FXAS21002C I2C Gyro driver");
+MODULE_IMPORT_NS(IIO_FXAS21002C);
diff --git a/drivers/iio/gyro/fxas21002c_spi.c b/drivers/iio/gyro/fxas21002c_spi.c
index c3ac169facf9..4f633826547c 100644
--- a/drivers/iio/gyro/fxas21002c_spi.c
+++ b/drivers/iio/gyro/fxas21002c_spi.c
@@ -54,7 +54,7 @@ MODULE_DEVICE_TABLE(of, fxas21002c_spi_of_match);
static struct spi_driver fxas21002c_spi_driver = {
.driver = {
.name = "fxas21002c_spi",
- .pm = &fxas21002c_pm_ops,
+ .pm = pm_ptr(&fxas21002c_pm_ops),
.of_match_table = fxas21002c_spi_of_match,
},
.probe = fxas21002c_spi_probe,
@@ -66,3 +66,4 @@ module_spi_driver(fxas21002c_spi_driver);
MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("FXAS21002C SPI Gyro driver");
+MODULE_IMPORT_NS(IIO_FXAS21002C);
diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c
index 421501584587..ceacd863d3ea 100644
--- a/drivers/iio/gyro/itg3200_core.c
+++ b/drivers/iio/gyro/itg3200_core.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
@@ -131,6 +132,7 @@ static int itg3200_write_raw(struct iio_dev *indio_dev,
int val2,
long mask)
{
+ struct itg3200 *st = iio_priv(indio_dev);
int ret;
u8 t;
@@ -139,11 +141,11 @@ static int itg3200_write_raw(struct iio_dev *indio_dev,
if (val == 0 || val2 != 0)
return -EINVAL;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &t);
if (ret) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
}
t = ((t & ITG3200_DLPF_CFG_MASK) ? 1000u : 8000u) / val - 1;
@@ -152,7 +154,7 @@ static int itg3200_write_raw(struct iio_dev *indio_dev,
ITG3200_REG_SAMPLE_RATE_DIV,
t);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
default:
@@ -293,8 +295,7 @@ static const struct iio_info itg3200_info = {
static const unsigned long itg3200_available_scan_masks[] = { 0xffffffff, 0x0 };
-static int itg3200_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int itg3200_probe(struct i2c_client *client)
{
int ret;
struct itg3200 *st;
@@ -336,6 +337,8 @@ static int itg3200_probe(struct i2c_client *client,
if (ret)
goto error_remove_trigger;
+ mutex_init(&st->lock);
+
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
@@ -402,7 +405,7 @@ static struct i2c_driver itg3200_driver = {
.pm = pm_sleep_ptr(&itg3200_pm_ops),
},
.id_table = itg3200_id,
- .probe = itg3200_probe,
+ .probe_new = itg3200_probe,
.remove = itg3200_remove,
};
diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c
index 12e3afa9dd11..2116798226bf 100644
--- a/drivers/iio/gyro/mpu3050-i2c.c
+++ b/drivers/iio/gyro/mpu3050-i2c.c
@@ -32,9 +32,9 @@ static int mpu3050_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id)
return 0;
}
-static int mpu3050_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mpu3050_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct regmap *regmap;
const char *name;
struct mpu3050 *mpu3050;
@@ -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 = mpu3050_i2c_probe,
+ .probe_new = 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 8c7af42b6558..797a1c6a0402 100644
--- a/drivers/iio/gyro/st_gyro_i2c.c
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -58,8 +58,7 @@ static const struct of_device_id st_gyro_of_match[] = {
};
MODULE_DEVICE_TABLE(of, st_gyro_of_match);
-static int st_gyro_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int st_gyro_i2c_probe(struct i2c_client *client)
{
const struct st_sensor_settings *settings;
struct st_sensor_data *gdata;
@@ -112,7 +111,7 @@ static struct i2c_driver st_gyro_driver = {
.name = "st-gyro-i2c",
.of_match_table = st_gyro_of_match,
},
- .probe = st_gyro_i2c_probe,
+ .probe_new = 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 836da31b7e30..21a6378b7052 100644
--- a/drivers/iio/health/afe4404.c
+++ b/drivers/iio/health/afe4404.c
@@ -461,8 +461,7 @@ static int afe4404_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(afe4404_pm_ops, afe4404_suspend,
afe4404_resume);
-static int afe4404_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int afe4404_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct afe4404_data *afe;
@@ -610,7 +609,7 @@ static struct i2c_driver afe4404_i2c_driver = {
.of_match_table = afe4404_of_match,
.pm = pm_sleep_ptr(&afe4404_pm_ops),
},
- .probe = afe4404_probe,
+ .probe_new = afe4404_probe,
.remove = afe4404_remove,
.id_table = afe4404_ids,
};
diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c
index 2cca5e0519f8..a80fa9852c22 100644
--- a/drivers/iio/health/max30100.c
+++ b/drivers/iio/health/max30100.c
@@ -387,18 +387,21 @@ static int max30100_read_raw(struct iio_dev *indio_dev,
* Temperature reading can only be acquired while engine
* is running
*/
- mutex_lock(&indio_dev->mlock);
-
- if (!iio_buffer_enabled(indio_dev))
+ if (iio_device_claim_buffer_mode(indio_dev)) {
+ /*
+ * Replacing -EBUSY or other error code
+ * returned by iio_device_claim_buffer_mode()
+ * because user space may rely on the current
+ * one.
+ */
ret = -EAGAIN;
- else {
+ } else {
ret = max30100_get_temp(data, val);
if (!ret)
ret = IIO_VAL_INT;
+ iio_device_release_buffer_mode(indio_dev);
}
-
- mutex_unlock(&indio_dev->mlock);
break;
case IIO_CHAN_INFO_SCALE:
*val = 1; /* 0.0625 */
@@ -414,8 +417,7 @@ static const struct iio_info max30100_info = {
.read_raw = max30100_read_raw,
};
-static int max30100_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max30100_probe(struct i2c_client *client)
{
struct max30100_data *data;
struct iio_dev *indio_dev;
@@ -497,7 +499,7 @@ static struct i2c_driver max30100_driver = {
.name = MAX30100_DRV_NAME,
.of_match_table = max30100_dt_ids,
},
- .probe = max30100_probe,
+ .probe_new = max30100_probe,
.remove = max30100_remove,
.id_table = max30100_id,
};
diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 437298a29f2d..7edcf9e05687 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -477,12 +477,23 @@ static int max30102_read_raw(struct iio_dev *indio_dev,
* Temperature reading can only be acquired when not in
* shutdown; leave shutdown briefly when buffer not running
*/
- mutex_lock(&indio_dev->mlock);
- if (!iio_buffer_enabled(indio_dev))
+any_mode_retry:
+ if (iio_device_claim_buffer_mode(indio_dev)) {
+ /*
+ * This one is a *bit* hacky. If we cannot claim buffer
+ * mode, then try direct mode so that we make sure
+ * things cannot concurrently change. And we just keep
+ * trying until we get one of the modes...
+ */
+ if (iio_device_claim_direct_mode(indio_dev))
+ goto any_mode_retry;
+
ret = max30102_get_temp(data, val, true);
- else
+ iio_device_release_direct_mode(indio_dev);
+ } else {
ret = max30102_get_temp(data, val, false);
- mutex_unlock(&indio_dev->mlock);
+ iio_device_release_buffer_mode(indio_dev);
+ }
if (ret)
return ret;
@@ -502,9 +513,9 @@ static const struct iio_info max30102_info = {
.read_raw = max30102_read_raw,
};
-static int max30102_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max30102_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct max30102_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -620,7 +631,7 @@ static struct i2c_driver max30102_driver = {
.name = MAX30102_DRV_NAME,
.of_match_table = max30102_dt_ids,
},
- .probe = max30102_probe,
+ .probe_new = max30102_probe,
.remove = max30102_remove,
.id_table = max30102_id,
};
diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c
index 4a39f1019347..f246516bd45e 100644
--- a/drivers/iio/humidity/am2315.c
+++ b/drivers/iio/humidity/am2315.c
@@ -218,8 +218,7 @@ static const struct iio_info am2315_info = {
.read_raw = am2315_read_raw,
};
-static int am2315_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int am2315_probe(struct i2c_client *client)
{
int ret;
struct iio_dev *indio_dev;
@@ -263,7 +262,7 @@ static struct i2c_driver am2315_driver = {
.driver = {
.name = "am2315",
},
- .probe = am2315_probe,
+ .probe_new = am2315_probe,
.id_table = am2315_i2c_id,
};
diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c
index 47f8e8ef56d6..49a950d739e4 100644
--- a/drivers/iio/humidity/hdc100x.c
+++ b/drivers/iio/humidity/hdc100x.c
@@ -351,8 +351,7 @@ static const struct iio_info hdc100x_info = {
.attrs = &hdc100x_attribute_group,
};
-static int hdc100x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int hdc100x_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct hdc100x_data *data;
@@ -429,7 +428,7 @@ static struct i2c_driver hdc100x_driver = {
.of_match_table = hdc100x_dt_ids,
.acpi_match_table = hdc100x_acpi_match,
},
- .probe = hdc100x_probe,
+ .probe_new = 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 d6858ccb056e..c8fddd612e06 100644
--- a/drivers/iio/humidity/hdc2010.c
+++ b/drivers/iio/humidity/hdc2010.c
@@ -251,8 +251,7 @@ static const struct iio_info hdc2010_info = {
.attrs = &hdc2010_attribute_group,
};
-static int hdc2010_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int hdc2010_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct hdc2010_data *data;
@@ -339,7 +338,7 @@ static struct i2c_driver hdc2010_driver = {
.name = "hdc2010",
.of_match_table = hdc2010_dt_ids,
},
- .probe = hdc2010_probe,
+ .probe_new = hdc2010_probe,
.remove = hdc2010_remove,
.id_table = hdc2010_id,
};
diff --git a/drivers/iio/humidity/hts221.h b/drivers/iio/humidity/hts221.h
index cf3d8d2dccd6..721359e226cb 100644
--- a/drivers/iio/humidity/hts221.h
+++ b/drivers/iio/humidity/hts221.h
@@ -13,7 +13,6 @@
#define HTS221_DEV_NAME "hts221"
#include <linux/iio/iio.h>
-#include <linux/regulator/consumer.h>
enum hts221_sensor_type {
HTS221_SENSOR_H,
@@ -30,7 +29,6 @@ struct hts221_hw {
const char *name;
struct device *dev;
struct regmap *regmap;
- struct regulator *vdd;
struct iio_trigger *trig;
int irq;
diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c
index 517158307d8c..2a413da87b76 100644
--- a/drivers/iio/humidity/hts221_core.c
+++ b/drivers/iio/humidity/hts221_core.c
@@ -14,6 +14,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <linux/bitfield.h>
#include "hts221.h"
@@ -549,33 +550,17 @@ static const unsigned long hts221_scan_masks[] = {0x3, 0x0};
static int hts221_init_regulators(struct device *dev)
{
- struct iio_dev *iio_dev = dev_get_drvdata(dev);
- struct hts221_hw *hw = iio_priv(iio_dev);
int err;
- hw->vdd = devm_regulator_get(dev, "vdd");
- if (IS_ERR(hw->vdd))
- return dev_err_probe(dev, PTR_ERR(hw->vdd),
- "failed to get vdd regulator\n");
-
- err = regulator_enable(hw->vdd);
- if (err) {
- dev_err(dev, "failed to enable vdd regulator: %d\n", err);
- return err;
- }
+ err = devm_regulator_get_enable(dev, "vdd");
+ if (err)
+ return dev_err_probe(dev, err, "failed to get vdd regulator\n");
msleep(50);
return 0;
}
-static void hts221_chip_uninit(void *data)
-{
- struct hts221_hw *hw = data;
-
- regulator_disable(hw->vdd);
-}
-
int hts221_probe(struct device *dev, int irq, const char *name,
struct regmap *regmap)
{
@@ -600,10 +585,6 @@ int hts221_probe(struct device *dev, int irq, const char *name,
if (err)
return err;
- err = devm_add_action_or_reset(dev, hts221_chip_uninit, hw);
- if (err)
- return err;
-
err = hts221_check_whoami(hw);
if (err < 0)
return err;
diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c
index afbc611f7712..d81869423cf0 100644
--- a/drivers/iio/humidity/hts221_i2c.c
+++ b/drivers/iio/humidity/hts221_i2c.c
@@ -25,8 +25,7 @@ static const struct regmap_config hts221_i2c_regmap_config = {
.read_flag_mask = HTS221_I2C_AUTO_INCREMENT,
};
-static int hts221_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int hts221_i2c_probe(struct i2c_client *client)
{
struct regmap *regmap;
@@ -66,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 = hts221_i2c_probe,
+ .probe_new = 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 fd9e2565f8a2..8411a9f3e828 100644
--- a/drivers/iio/humidity/htu21.c
+++ b/drivers/iio/humidity/htu21.c
@@ -177,9 +177,9 @@ static const struct iio_info htu21_info = {
.attrs = &htu21_attribute_group,
};
-static int htu21_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int htu21_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ms_ht_dev *dev_data;
struct iio_dev *indio_dev;
int ret;
@@ -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 = htu21_probe,
+ .probe_new = htu21_probe,
.id_table = htu21_id,
.driver = {
.name = "htu21",
diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c
index 160b3d92df61..fa1faf168c8d 100644
--- a/drivers/iio/humidity/si7005.c
+++ b/drivers/iio/humidity/si7005.c
@@ -123,8 +123,7 @@ static const struct iio_info si7005_info = {
.read_raw = si7005_read_raw,
};
-static int si7005_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int si7005_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct si7005_data *data;
@@ -174,7 +173,7 @@ static struct i2c_driver si7005_driver = {
.driver = {
.name = "si7005",
},
- .probe = si7005_probe,
+ .probe_new = 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 ab6537f136ba..3e50592e8e68 100644
--- a/drivers/iio/humidity/si7020.c
+++ b/drivers/iio/humidity/si7020.c
@@ -103,8 +103,7 @@ static const struct iio_info si7020_info = {
.read_raw = si7020_read_raw,
};
-static int si7020_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int si7020_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct i2c_client **data;
@@ -156,7 +155,7 @@ static struct i2c_driver si7020_driver = {
.name = "si7020",
.of_match_table = si7020_dt_ids,
},
- .probe = si7020_probe,
+ .probe_new = si7020_probe,
.id_table = si7020_id,
};
diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index f7fcfd04f659..bc40240b29e2 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -270,23 +270,19 @@ EXPORT_SYMBOL_NS(adis_debugfs_reg_access, IIO_ADISLIB);
#endif
/**
- * adis_enable_irq() - Enable or disable data ready IRQ
+ * __adis_enable_irq() - Enable or disable data ready IRQ (unlocked)
* @adis: The adis device
* @enable: Whether to enable the IRQ
*
* Returns 0 on success, negative error code otherwise
*/
-int adis_enable_irq(struct adis *adis, bool enable)
+int __adis_enable_irq(struct adis *adis, bool enable)
{
- int ret = 0;
+ int ret;
u16 msc;
- mutex_lock(&adis->state_lock);
-
- if (adis->data->enable_irq) {
- ret = adis->data->enable_irq(adis, enable);
- goto out_unlock;
- }
+ if (adis->data->enable_irq)
+ return adis->data->enable_irq(adis, enable);
if (adis->data->unmasked_drdy) {
if (enable)
@@ -294,12 +290,12 @@ int adis_enable_irq(struct adis *adis, bool enable)
else
disable_irq(adis->spi->irq);
- goto out_unlock;
+ return 0;
}
ret = __adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
if (ret)
- goto out_unlock;
+ return ret;
msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;
msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;
@@ -308,13 +304,9 @@ int adis_enable_irq(struct adis *adis, bool enable)
else
msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;
- ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
-
-out_unlock:
- mutex_unlock(&adis->state_lock);
- return ret;
+ return __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
}
-EXPORT_SYMBOL_NS(adis_enable_irq, IIO_ADISLIB);
+EXPORT_SYMBOL_NS(__adis_enable_irq, IIO_ADISLIB);
/**
* __adis_check_status() - Check the device for error conditions (unlocked)
@@ -445,7 +437,7 @@ int __adis_initial_startup(struct adis *adis)
* with 'IRQF_NO_AUTOEN' anyways.
*/
if (!adis->data->unmasked_drdy)
- adis_enable_irq(adis, false);
+ __adis_enable_irq(adis, false);
if (!adis->data->prod_id_reg)
return 0;
diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c
index 17bb0c40a149..c02fc35dceb4 100644
--- a/drivers/iio/imu/adis16400.c
+++ b/drivers/iio/imu/adis16400.c
@@ -445,7 +445,7 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev)
st->adis.spi->mode = SPI_MODE_3;
spi_setup(st->adis.spi);
- ret = adis_initial_startup(&st->adis);
+ ret = __adis_initial_startup(&st->adis);
if (ret)
return ret;
diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c
index d93f4fa2ad55..2ca907d396a0 100644
--- a/drivers/iio/imu/bmi160/bmi160_i2c.c
+++ b/drivers/iio/imu/bmi160/bmi160_i2c.c
@@ -15,9 +15,9 @@
#include "bmi160.h"
-static int bmi160_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bmi160_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct regmap *regmap;
const char *name;
@@ -60,7 +60,7 @@ static struct i2c_driver bmi160_i2c_driver = {
.acpi_match_table = bmi160_acpi_match,
.of_match_table = bmi160_of_match,
},
- .probe = bmi160_i2c_probe,
+ .probe_new = bmi160_i2c_probe,
.id_table = bmi160_i2c_id,
};
module_i2c_driver(bmi160_i2c_driver);
diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c
index 40a570325b0a..a74a15fda8cb 100644
--- a/drivers/iio/imu/fxos8700_i2c.c
+++ b/drivers/iio/imu/fxos8700_i2c.c
@@ -18,9 +18,9 @@
#include "fxos8700.h"
-static int fxos8700_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int fxos8700_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct regmap *regmap;
const char *name = NULL;
@@ -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 = fxos8700_i2c_probe,
+ .probe_new = fxos8700_i2c_probe,
.id_table = fxos8700_i2c_id,
};
module_i2c_driver(fxos8700_i2c_driver);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
index 3d91469beccb..0e290c807b0f 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -22,6 +22,7 @@ enum inv_icm42600_chip {
INV_CHIP_ICM42602,
INV_CHIP_ICM42605,
INV_CHIP_ICM42622,
+ INV_CHIP_ICM42631,
INV_CHIP_NB,
};
@@ -303,6 +304,7 @@ struct inv_icm42600_state {
#define INV_ICM42600_WHOAMI_ICM42602 0x41
#define INV_ICM42600_WHOAMI_ICM42605 0x42
#define INV_ICM42600_WHOAMI_ICM42622 0x46
+#define INV_ICM42600_WHOAMI_ICM42631 0x5C
/* User bank 1 (MSB 0x10) */
#define INV_ICM42600_REG_SENSOR_CONFIG0 0x1003
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index ca85fccc9839..7b3a2a0dc2cb 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -41,7 +41,7 @@ const struct regmap_config inv_icm42600_regmap_config = {
.ranges = inv_icm42600_regmap_ranges,
.num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges),
};
-EXPORT_SYMBOL_GPL(inv_icm42600_regmap_config);
+EXPORT_SYMBOL_NS_GPL(inv_icm42600_regmap_config, IIO_ICM42600);
struct inv_icm42600_hw {
uint8_t whoami;
@@ -87,6 +87,11 @@ static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = {
.name = "icm42622",
.conf = &inv_icm42600_default_conf,
},
+ [INV_CHIP_ICM42631] = {
+ .whoami = INV_ICM42600_WHOAMI_ICM42631,
+ .name = "icm42631",
+ .conf = &inv_icm42600_default_conf,
+ },
};
const struct iio_mount_matrix *
@@ -660,13 +665,13 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
return devm_add_action_or_reset(dev, inv_icm42600_disable_pm, dev);
}
-EXPORT_SYMBOL_GPL(inv_icm42600_core_probe);
+EXPORT_SYMBOL_NS_GPL(inv_icm42600_core_probe, IIO_ICM42600);
/*
* Suspend saves sensors state and turns everything off.
* Check first if runtime suspend has not already done the job.
*/
-static int __maybe_unused inv_icm42600_suspend(struct device *dev)
+static int inv_icm42600_suspend(struct device *dev)
{
struct inv_icm42600_state *st = dev_get_drvdata(dev);
int ret;
@@ -706,7 +711,7 @@ out_unlock:
* System resume gets the system back on and restores the sensors state.
* Manually put runtime power management in system active state.
*/
-static int __maybe_unused inv_icm42600_resume(struct device *dev)
+static int inv_icm42600_resume(struct device *dev)
{
struct inv_icm42600_state *st = dev_get_drvdata(dev);
int ret;
@@ -739,7 +744,7 @@ out_unlock:
}
/* Runtime suspend will turn off sensors that are enabled by iio devices. */
-static int __maybe_unused inv_icm42600_runtime_suspend(struct device *dev)
+static int inv_icm42600_runtime_suspend(struct device *dev)
{
struct inv_icm42600_state *st = dev_get_drvdata(dev);
int ret;
@@ -761,7 +766,7 @@ error_unlock:
}
/* Sensors are enabled by iio devices, no need to turn them back on here. */
-static int __maybe_unused inv_icm42600_runtime_resume(struct device *dev)
+static int inv_icm42600_runtime_resume(struct device *dev)
{
struct inv_icm42600_state *st = dev_get_drvdata(dev);
int ret;
@@ -774,12 +779,11 @@ static int __maybe_unused inv_icm42600_runtime_resume(struct device *dev)
return ret;
}
-const struct dev_pm_ops inv_icm42600_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume)
- SET_RUNTIME_PM_OPS(inv_icm42600_runtime_suspend,
- inv_icm42600_runtime_resume, NULL)
+EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42600_pm_ops, IIO_ICM42600) = {
+ SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume)
+ RUNTIME_PM_OPS(inv_icm42600_runtime_suspend,
+ inv_icm42600_runtime_resume, NULL)
};
-EXPORT_SYMBOL_GPL(inv_icm42600_pm_ops);
MODULE_AUTHOR("InvenSense, Inc.");
MODULE_DESCRIPTION("InvenSense ICM-426xx device driver");
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
index d4a692b838d0..eb2681ad375f 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
@@ -84,6 +84,9 @@ static const struct of_device_id inv_icm42600_of_matches[] = {
}, {
.compatible = "invensense,icm42622",
.data = (void *)INV_CHIP_ICM42622,
+ }, {
+ .compatible = "invensense,icm42631",
+ .data = (void *)INV_CHIP_ICM42631,
},
{}
};
@@ -93,7 +96,7 @@ static struct i2c_driver inv_icm42600_driver = {
.driver = {
.name = "inv-icm42600-i2c",
.of_match_table = inv_icm42600_of_matches,
- .pm = &inv_icm42600_pm_ops,
+ .pm = pm_ptr(&inv_icm42600_pm_ops),
},
.probe_new = inv_icm42600_probe,
};
@@ -102,3 +105,4 @@ module_i2c_driver(inv_icm42600_driver);
MODULE_AUTHOR("InvenSense, Inc.");
MODULE_DESCRIPTION("InvenSense ICM-426xx I2C driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_ICM42600);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
index e6305e5fa975..6be4ac794937 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
@@ -80,6 +80,9 @@ static const struct of_device_id inv_icm42600_of_matches[] = {
}, {
.compatible = "invensense,icm42622",
.data = (void *)INV_CHIP_ICM42622,
+ }, {
+ .compatible = "invensense,icm42631",
+ .data = (void *)INV_CHIP_ICM42631,
},
{}
};
@@ -89,7 +92,7 @@ static struct spi_driver inv_icm42600_driver = {
.driver = {
.name = "inv-icm42600-spi",
.of_match_table = inv_icm42600_of_matches,
- .pm = &inv_icm42600_pm_ops,
+ .pm = pm_ptr(&inv_icm42600_pm_ops),
},
.probe = inv_icm42600_probe,
};
@@ -98,3 +101,4 @@ module_spi_driver(inv_icm42600_driver);
MODULE_AUTHOR("InvenSense, Inc.");
MODULE_DESCRIPTION("InvenSense ICM-426xx SPI driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_ICM42600);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 86fbbe904050..8a129120b73d 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -1653,9 +1653,9 @@ error_power_off:
inv_mpu6050_set_power_itg(st, false);
return result;
}
-EXPORT_SYMBOL_GPL(inv_mpu_core_probe);
+EXPORT_SYMBOL_NS_GPL(inv_mpu_core_probe, IIO_MPU6050);
-static int __maybe_unused inv_mpu_resume(struct device *dev)
+static int inv_mpu_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
@@ -1687,7 +1687,7 @@ out_unlock:
return result;
}
-static int __maybe_unused inv_mpu_suspend(struct device *dev)
+static int inv_mpu_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
@@ -1730,7 +1730,7 @@ out_unlock:
return result;
}
-static int __maybe_unused inv_mpu_runtime_suspend(struct device *dev)
+static int inv_mpu_runtime_suspend(struct device *dev)
{
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
unsigned int sensors;
@@ -1755,7 +1755,7 @@ out_unlock:
return ret;
}
-static int __maybe_unused inv_mpu_runtime_resume(struct device *dev)
+static int inv_mpu_runtime_resume(struct device *dev)
{
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
int ret;
@@ -1767,11 +1767,10 @@ static int __maybe_unused inv_mpu_runtime_resume(struct device *dev)
return inv_mpu6050_set_power_itg(st, true);
}
-const struct dev_pm_ops inv_mpu_pmops = {
- SET_SYSTEM_SLEEP_PM_OPS(inv_mpu_suspend, inv_mpu_resume)
- SET_RUNTIME_PM_OPS(inv_mpu_runtime_suspend, inv_mpu_runtime_resume, NULL)
+EXPORT_NS_GPL_DEV_PM_OPS(inv_mpu_pmops, IIO_MPU6050) = {
+ SYSTEM_SLEEP_PM_OPS(inv_mpu_suspend, inv_mpu_resume)
+ RUNTIME_PM_OPS(inv_mpu_runtime_suspend, inv_mpu_runtime_resume, NULL)
};
-EXPORT_SYMBOL_GPL(inv_mpu_pmops);
MODULE_AUTHOR("Invensense Corporation");
MODULE_DESCRIPTION("Invensense device MPU6050 driver");
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
index 14255a918eb1..2f2da4cb7321 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
@@ -91,13 +91,12 @@ static int inv_mpu_i2c_aux_setup(struct iio_dev *indio_dev)
/**
* inv_mpu_probe() - probe function.
* @client: i2c client.
- * @id: i2c device id.
*
* Returns 0 on success, a negative error code otherwise.
*/
-static int inv_mpu_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int inv_mpu_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
const void *match;
struct inv_mpu6050_state *st;
int result;
@@ -260,14 +259,14 @@ static const struct acpi_device_id inv_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
static struct i2c_driver inv_mpu_driver = {
- .probe = inv_mpu_probe,
+ .probe_new = inv_mpu_probe,
.remove = inv_mpu_remove,
.id_table = inv_mpu_id,
.driver = {
.of_match_table = inv_of_match,
.acpi_match_table = inv_acpi_match,
.name = "inv-mpu6050-i2c",
- .pm = &inv_mpu_pmops,
+ .pm = pm_ptr(&inv_mpu_pmops),
},
};
@@ -276,3 +275,4 @@ module_i2c_driver(inv_mpu_driver);
MODULE_AUTHOR("Invensense Corporation");
MODULE_DESCRIPTION("Invensense device MPU6050 driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_MPU6050);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
index e6107b0cc38f..89f46c2f213d 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
@@ -154,7 +154,7 @@ static struct spi_driver inv_mpu_driver = {
.of_match_table = inv_of_match,
.acpi_match_table = inv_acpi_match,
.name = "inv-mpu6000-spi",
- .pm = &inv_mpu_pmops,
+ .pm = pm_ptr(&inv_mpu_pmops),
},
};
@@ -163,3 +163,4 @@ module_spi_driver(inv_mpu_driver);
MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
MODULE_DESCRIPTION("Invensense device MPU6000 driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_MPU6050);
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index b10c0dcac0bb..e692dfeeda44 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -1276,9 +1276,9 @@ static struct iio_trigger *kmx61_trigger_setup(struct kmx61_data *data,
return trig;
}
-static int kmx61_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int kmx61_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
struct kmx61_data *data;
const char *name = NULL;
@@ -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 = kmx61_probe,
+ .probe_new = kmx61_probe,
.remove = kmx61_remove,
.id_table = kmx61_id,
};
diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig
index 2ed2b3f40c0b..f6660847fb58 100644
--- a/drivers/iio/imu/st_lsm6dsx/Kconfig
+++ b/drivers/iio/imu/st_lsm6dsx/Kconfig
@@ -13,7 +13,8 @@ config IIO_ST_LSM6DSX
sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
ism330dlc, lsm6dso, lsm6dsox, asm330lhh, asm330lhhx, lsm6dsr,
lsm6ds3tr-c, ism330dhcx, lsm6dsrx, lsm6ds0, lsm6dsop, lsm6dstx,
- the accelerometer/gyroscope of lsm9ds1 and lsm6dst.
+ lsm6dsv, lsm6dsv16x, lsm6dso16is, ism330is, lsm6dst and the
+ accelerometer/gyroscope of lsm9ds1.
To compile this driver as a module, choose M here: the module
will be called st_lsm6dsx.
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index 6b57d47be69e..5b6f195748fc 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -33,6 +33,10 @@
#define ST_LSM6DSOP_DEV_NAME "lsm6dsop"
#define ST_ASM330LHHX_DEV_NAME "asm330lhhx"
#define ST_LSM6DSTX_DEV_NAME "lsm6dstx"
+#define ST_LSM6DSV_DEV_NAME "lsm6dsv"
+#define ST_LSM6DSV16X_DEV_NAME "lsm6dsv16x"
+#define ST_LSM6DSO16IS_DEV_NAME "lsm6dso16is"
+#define ST_ISM330IS_DEV_NAME "ism330is"
enum st_lsm6dsx_hw_id {
ST_LSM6DS3_ID,
@@ -53,6 +57,10 @@ enum st_lsm6dsx_hw_id {
ST_LSM6DSOP_ID,
ST_ASM330LHHX_ID,
ST_LSM6DSTX_ID,
+ ST_LSM6DSV_ID,
+ ST_LSM6DSV16X_ID,
+ ST_LSM6DSO16IS_ID,
+ ST_ISM330IS_ID,
ST_LSM6DSX_MAX_ID,
};
@@ -374,7 +382,6 @@ struct st_lsm6dsx_sensor {
* struct st_lsm6dsx_hw - ST IMU MEMS hw instance
* @dev: Pointer to instance of struct device (I2C or SPI).
* @regmap: Register map of the device.
- * @regulators: VDD/VDDIO voltage regulators.
* @irq: Device interrupt line (I2C or SPI).
* @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.
* @conf_lock: Mutex to prevent concurrent FIFO configuration update.
@@ -397,7 +404,6 @@ struct st_lsm6dsx_sensor {
struct st_lsm6dsx_hw {
struct device *dev;
struct regmap *regmap;
- struct regulator_bulk_data regulators[2];
int irq;
struct mutex fifo_lock;
@@ -426,7 +432,7 @@ struct st_lsm6dsx_hw {
struct {
__le16 channels[3];
s64 ts __aligned(8);
- } scan[3];
+ } scan[ST_LSM6DSX_ID_MAX];
};
static __maybe_unused const struct iio_event_spec st_lsm6dsx_event = {
@@ -458,6 +464,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val);
int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name);
int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable);
+int st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data, int len);
int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable);
static inline int
@@ -509,6 +516,17 @@ st_lsm6dsx_get_mount_matrix(const struct iio_dev *iio_dev,
return &hw->orientation;
}
+static inline int
+st_lsm6dsx_device_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable)
+{
+ if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
+ sensor->id == ST_LSM6DSX_ID_EXT1 ||
+ sensor->id == ST_LSM6DSX_ID_EXT2)
+ return st_lsm6dsx_shub_set_enable(sensor, enable);
+
+ return st_lsm6dsx_sensor_set_enable(sensor, enable);
+}
+
static const
struct iio_chan_spec_ext_info __maybe_unused st_lsm6dsx_accel_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_lsm6dsx_get_mount_matrix),
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
index e49f2d120ed3..7dd5205aea5b 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -15,7 +15,7 @@
* value of the decimation factor and ODR set for each FIFO data set.
*
* LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/LSM6DSRX/ISM330DHCX/
- * LSM6DST/LSM6DSOP/LSM6DSTX:
+ * LSM6DST/LSM6DSOP/LSM6DSTX/LSM6DSV:
* The FIFO buffer can be configured to store data from gyroscope and
* accelerometer. Each sample is queued with a tag (1B) indicating data
* source (gyroscope, accelerometer, hw timer).
@@ -673,17 +673,9 @@ int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable)
goto out;
}
- if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
- sensor->id == ST_LSM6DSX_ID_EXT1 ||
- sensor->id == ST_LSM6DSX_ID_EXT2) {
- err = st_lsm6dsx_shub_set_enable(sensor, enable);
- if (err < 0)
- goto out;
- } else {
- err = st_lsm6dsx_sensor_set_enable(sensor, enable);
- if (err < 0)
- goto out;
- }
+ err = st_lsm6dsx_device_set_enable(sensor, enable);
+ if (err < 0)
+ goto out;
err = st_lsm6dsx_set_fifo_odr(sensor, enable);
if (err < 0)
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index f8bbb005718e..3f6060c64f32 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -27,13 +27,20 @@
* - FIFO size: 4KB
*
* - LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/ISM330DHCX/LSM6DST/LSM6DSOP/
- * LSM6DSTX:
+ * LSM6DSTX/LSM6DSO16IS/ISM330IS:
* - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416,
* 833
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 3KB
*
+ * - LSM6DSV/LSM6DSV16X:
+ * - Accelerometer/Gyroscope supported ODR [Hz]: 7.5, 15, 30, 60, 120, 240,
+ * 480, 960
+ * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
+ * - Gyroscope supported full-scale [dps]: +-125/+-250/+-500/+-1000/+-2000
+ * - FIFO size: 3KB
+ *
* - LSM9DS1/LSM6DS0:
* - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
@@ -53,6 +60,8 @@
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/minmax.h>
@@ -1160,6 +1169,342 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.wakeup_src_x_mask = BIT(2),
},
},
+ {
+ .reset = {
+ .addr = 0x12,
+ .mask = BIT(0),
+ },
+ .boot = {
+ .addr = 0x12,
+ .mask = BIT(7),
+ },
+ .bdu = {
+ .addr = 0x12,
+ .mask = BIT(6),
+ },
+ .id = {
+ {
+ .hw_id = ST_LSM6DSV_ID,
+ .name = ST_LSM6DSV_DEV_NAME,
+ .wai = 0x70,
+ }, {
+ .hw_id = ST_LSM6DSV16X_ID,
+ .name = ST_LSM6DSV16X_DEV_NAME,
+ .wai = 0x70,
+ },
+ },
+ .channels = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .chan = st_lsm6dsx_acc_channels,
+ .len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .chan = st_lsm6dsx_gyro_channels,
+ .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
+ },
+ },
+ .drdy_mask = {
+ .addr = 0x13,
+ .mask = BIT(3),
+ },
+ .odr_table = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .reg = {
+ .addr = 0x10,
+ .mask = GENMASK(3, 0),
+ },
+ .odr_avl[0] = { 7500, 0x02 },
+ .odr_avl[1] = { 15000, 0x03 },
+ .odr_avl[2] = { 30000, 0x04 },
+ .odr_avl[3] = { 60000, 0x05 },
+ .odr_avl[4] = { 120000, 0x06 },
+ .odr_avl[5] = { 240000, 0x07 },
+ .odr_avl[6] = { 480000, 0x08 },
+ .odr_avl[7] = { 960000, 0x09 },
+ .odr_len = 8,
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .reg = {
+ .addr = 0x11,
+ .mask = GENMASK(3, 0),
+ },
+ .odr_avl[0] = { 7500, 0x02 },
+ .odr_avl[1] = { 15000, 0x03 },
+ .odr_avl[2] = { 30000, 0x04 },
+ .odr_avl[3] = { 60000, 0x05 },
+ .odr_avl[4] = { 120000, 0x06 },
+ .odr_avl[5] = { 240000, 0x07 },
+ .odr_avl[6] = { 480000, 0x08 },
+ .odr_avl[7] = { 960000, 0x09 },
+ .odr_len = 8,
+ },
+ },
+ .fs_table = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .reg = {
+ .addr = 0x17,
+ .mask = GENMASK(1, 0),
+ },
+ .fs_avl[0] = { IIO_G_TO_M_S_2(61000), 0x0 },
+ .fs_avl[1] = { IIO_G_TO_M_S_2(122000), 0x1 },
+ .fs_avl[2] = { IIO_G_TO_M_S_2(244000), 0x2 },
+ .fs_avl[3] = { IIO_G_TO_M_S_2(488000), 0x3 },
+ .fs_len = 4,
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .reg = {
+ .addr = 0x15,
+ .mask = GENMASK(3, 0),
+ },
+ .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750000), 0x1 },
+ .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500000), 0x2 },
+ .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000000), 0x3 },
+ .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000000), 0x4 },
+ .fs_len = 4,
+ },
+ },
+ .irq_config = {
+ .irq1 = {
+ .addr = 0x0d,
+ .mask = BIT(3),
+ },
+ .irq2 = {
+ .addr = 0x0e,
+ .mask = BIT(3),
+ },
+ .lir = {
+ .addr = 0x56,
+ .mask = BIT(0),
+ },
+ .irq1_func = {
+ .addr = 0x5e,
+ .mask = BIT(5),
+ },
+ .irq2_func = {
+ .addr = 0x5f,
+ .mask = BIT(5),
+ },
+ .hla = {
+ .addr = 0x03,
+ .mask = BIT(4),
+ },
+ .od = {
+ .addr = 0x03,
+ .mask = BIT(3),
+ },
+ },
+ .batch = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .addr = 0x09,
+ .mask = GENMASK(3, 0),
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .addr = 0x09,
+ .mask = GENMASK(7, 4),
+ },
+ },
+ .fifo_ops = {
+ .update_fifo = st_lsm6dsx_update_fifo,
+ .read_fifo = st_lsm6dsx_read_tagged_fifo,
+ .fifo_th = {
+ .addr = 0x07,
+ .mask = GENMASK(7, 0),
+ },
+ .fifo_diff = {
+ .addr = 0x1b,
+ .mask = GENMASK(8, 0),
+ },
+ .max_size = 512,
+ .th_wl = 1,
+ },
+ .ts_settings = {
+ .timer_en = {
+ .addr = 0x50,
+ .mask = BIT(6),
+ },
+ .decimator = {
+ .addr = 0x0a,
+ .mask = GENMASK(7, 6),
+ },
+ .freq_fine = 0x4f,
+ },
+ .shub_settings = {
+ .page_mux = {
+ .addr = 0x01,
+ .mask = BIT(6),
+ },
+ .master_en = {
+ .sec_page = true,
+ .addr = 0x14,
+ .mask = BIT(2),
+ },
+ .pullup_en = {
+ .addr = 0x03,
+ .mask = BIT(6),
+ },
+ .aux_sens = {
+ .addr = 0x14,
+ .mask = GENMASK(1, 0),
+ },
+ .wr_once = {
+ .addr = 0x14,
+ .mask = BIT(6),
+ },
+ .num_ext_dev = 3,
+ .shub_out = {
+ .sec_page = true,
+ .addr = 0x02,
+ },
+ .slv0_addr = 0x15,
+ .dw_slv0_addr = 0x21,
+ .batch_en = BIT(3),
+ },
+ .event_settings = {
+ .enable_reg = {
+ .addr = 0x50,
+ .mask = BIT(7),
+ },
+ .wakeup_reg = {
+ .addr = 0x5b,
+ .mask = GENMASK(5, 0),
+ },
+ .wakeup_src_reg = 0x45,
+ .wakeup_src_status_mask = BIT(3),
+ .wakeup_src_z_mask = BIT(0),
+ .wakeup_src_y_mask = BIT(1),
+ .wakeup_src_x_mask = BIT(2),
+ },
+ },
+ {
+ .reset = {
+ .addr = 0x12,
+ .mask = BIT(0),
+ },
+ .boot = {
+ .addr = 0x12,
+ .mask = BIT(7),
+ },
+ .bdu = {
+ .addr = 0x12,
+ .mask = BIT(6),
+ },
+ .id = {
+ {
+ .hw_id = ST_LSM6DSO16IS_ID,
+ .name = ST_LSM6DSO16IS_DEV_NAME,
+ .wai = 0x22,
+ }, {
+ .hw_id = ST_ISM330IS_ID,
+ .name = ST_ISM330IS_DEV_NAME,
+ .wai = 0x22,
+ }
+ },
+ .channels = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .chan = st_lsm6dsx_acc_channels,
+ .len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .chan = st_lsm6dsx_gyro_channels,
+ .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
+ },
+ },
+ .odr_table = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .reg = {
+ .addr = 0x10,
+ .mask = GENMASK(7, 4),
+ },
+ .odr_avl[0] = { 12500, 0x01 },
+ .odr_avl[1] = { 26000, 0x02 },
+ .odr_avl[2] = { 52000, 0x03 },
+ .odr_avl[3] = { 104000, 0x04 },
+ .odr_avl[4] = { 208000, 0x05 },
+ .odr_avl[5] = { 416000, 0x06 },
+ .odr_avl[6] = { 833000, 0x07 },
+ .odr_len = 7,
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .reg = {
+ .addr = 0x11,
+ .mask = GENMASK(7, 4),
+ },
+ .odr_avl[0] = { 12500, 0x01 },
+ .odr_avl[1] = { 26000, 0x02 },
+ .odr_avl[2] = { 52000, 0x03 },
+ .odr_avl[3] = { 104000, 0x04 },
+ .odr_avl[4] = { 208000, 0x05 },
+ .odr_avl[5] = { 416000, 0x06 },
+ .odr_avl[6] = { 833000, 0x07 },
+ .odr_len = 7,
+ },
+ },
+ .fs_table = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .reg = {
+ .addr = 0x10,
+ .mask = GENMASK(3, 2),
+ },
+ .fs_avl[0] = { IIO_G_TO_M_S_2(61000), 0x0 },
+ .fs_avl[1] = { IIO_G_TO_M_S_2(122000), 0x2 },
+ .fs_avl[2] = { IIO_G_TO_M_S_2(244000), 0x3 },
+ .fs_avl[3] = { IIO_G_TO_M_S_2(488000), 0x1 },
+ .fs_len = 4,
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .reg = {
+ .addr = 0x11,
+ .mask = GENMASK(3, 2),
+ },
+ .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750000), 0x0 },
+ .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500000), 0x1 },
+ .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000000), 0x2 },
+ .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000000), 0x3 },
+ .fs_len = 4,
+ },
+ },
+ .irq_config = {
+ .hla = {
+ .addr = 0x12,
+ .mask = BIT(5),
+ },
+ .od = {
+ .addr = 0x12,
+ .mask = BIT(4),
+ },
+ },
+ .shub_settings = {
+ .page_mux = {
+ .addr = 0x01,
+ .mask = BIT(6),
+ },
+ .master_en = {
+ .sec_page = true,
+ .addr = 0x14,
+ .mask = BIT(2),
+ },
+ .pullup_en = {
+ .sec_page = true,
+ .addr = 0x14,
+ .mask = BIT(3),
+ },
+ .aux_sens = {
+ .addr = 0x14,
+ .mask = GENMASK(1, 0),
+ },
+ .wr_once = {
+ .addr = 0x14,
+ .mask = BIT(6),
+ },
+ .num_ext_dev = 3,
+ .shub_out = {
+ .sec_page = true,
+ .addr = 0x02,
+ },
+ .slv0_addr = 0x15,
+ .dw_slv0_addr = 0x21,
+ },
+ },
};
int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable)
@@ -2117,6 +2462,32 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
return fifo_len || event ? IRQ_HANDLED : IRQ_NONE;
}
+static irqreturn_t st_lsm6dsx_sw_trigger_handler_thread(int irq,
+ void *private)
+{
+ struct iio_poll_func *pf = private;
+ struct iio_dev *iio_dev = pf->indio_dev;
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+ struct st_lsm6dsx_hw *hw = sensor->hw;
+
+ if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
+ sensor->id == ST_LSM6DSX_ID_EXT1 ||
+ sensor->id == ST_LSM6DSX_ID_EXT2)
+ st_lsm6dsx_shub_read_output(hw,
+ (u8 *)hw->scan[sensor->id].channels,
+ sizeof(hw->scan[sensor->id].channels));
+ else
+ st_lsm6dsx_read_locked(hw, iio_dev->channels[0].address,
+ hw->scan[sensor->id].channels,
+ sizeof(hw->scan[sensor->id].channels));
+
+ iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan[sensor->id],
+ iio_get_time_ns(iio_dev));
+ iio_trigger_notify_done(iio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
{
struct st_sensors_platform_data *pdata;
@@ -2175,36 +2546,60 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
return 0;
}
-static int st_lsm6dsx_init_regulators(struct device *dev)
+static int st_lsm6dsx_sw_buffer_preenable(struct iio_dev *iio_dev)
{
- struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
- int err;
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
- /* vdd-vddio power regulators */
- hw->regulators[0].supply = "vdd";
- hw->regulators[1].supply = "vddio";
- err = devm_regulator_bulk_get(dev, ARRAY_SIZE(hw->regulators),
- hw->regulators);
- if (err)
- return dev_err_probe(dev, err, "failed to get regulators\n");
+ return st_lsm6dsx_device_set_enable(sensor, true);
+}
- err = regulator_bulk_enable(ARRAY_SIZE(hw->regulators),
- hw->regulators);
- if (err) {
- dev_err(dev, "failed to enable regulators: %d\n", err);
- return err;
- }
+static int st_lsm6dsx_sw_buffer_postdisable(struct iio_dev *iio_dev)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
- msleep(50);
+ return st_lsm6dsx_device_set_enable(sensor, false);
+}
+
+static const struct iio_buffer_setup_ops st_lsm6dsx_sw_buffer_ops = {
+ .preenable = st_lsm6dsx_sw_buffer_preenable,
+ .postdisable = st_lsm6dsx_sw_buffer_postdisable,
+};
+
+static int st_lsm6dsx_sw_buffers_setup(struct st_lsm6dsx_hw *hw)
+{
+ int i;
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ int err;
+
+ if (!hw->iio_devs[i])
+ continue;
+
+ err = devm_iio_triggered_buffer_setup(hw->dev,
+ hw->iio_devs[i], NULL,
+ st_lsm6dsx_sw_trigger_handler_thread,
+ &st_lsm6dsx_sw_buffer_ops);
+ if (err)
+ return err;
+ }
return 0;
}
-static void st_lsm6dsx_chip_uninit(void *data)
+static int st_lsm6dsx_init_regulators(struct device *dev)
{
- struct st_lsm6dsx_hw *hw = data;
+ /* vdd-vddio power regulators */
+ static const char * const regulators[] = { "vdd", "vddio" };
+ int err;
- regulator_bulk_disable(ARRAY_SIZE(hw->regulators), hw->regulators);
+ err = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators),
+ regulators);
+ if (err)
+ return dev_err_probe(dev, err, "failed to enable regulators\n");
+
+ msleep(50);
+
+ return 0;
}
int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
@@ -2230,10 +2625,6 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
if (err)
return err;
- err = devm_add_action_or_reset(dev, st_lsm6dsx_chip_uninit, hw);
- if (err)
- return err;
-
hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL);
if (!hw->buff)
return -ENOMEM;
@@ -2275,6 +2666,16 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
return err;
}
+ if (!hw->irq || !hw->settings->fifo_ops.read_fifo) {
+ /*
+ * Rely on sw triggers (e.g. hr-timers) if irq pin is not
+ * connected of if the device does not support HW FIFO
+ */
+ err = st_lsm6dsx_sw_buffers_setup(hw);
+ if (err)
+ return err;
+ }
+
err = iio_read_mount_matrix(hw->dev, &hw->orientation);
if (err)
return err;
@@ -2317,12 +2718,7 @@ static int st_lsm6dsx_suspend(struct device *dev)
continue;
}
- if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
- sensor->id == ST_LSM6DSX_ID_EXT1 ||
- sensor->id == ST_LSM6DSX_ID_EXT2)
- err = st_lsm6dsx_shub_set_enable(sensor, false);
- else
- err = st_lsm6dsx_sensor_set_enable(sensor, false);
+ err = st_lsm6dsx_device_set_enable(sensor, false);
if (err < 0)
return err;
@@ -2353,12 +2749,7 @@ static int st_lsm6dsx_resume(struct device *dev)
if (!(hw->suspend_mask & BIT(sensor->id)))
continue;
- if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
- sensor->id == ST_LSM6DSX_ID_EXT1 ||
- sensor->id == ST_LSM6DSX_ID_EXT2)
- err = st_lsm6dsx_shub_set_enable(sensor, true);
- else
- err = st_lsm6dsx_sensor_set_enable(sensor, true);
+ err = st_lsm6dsx_device_set_enable(sensor, true);
if (err < 0)
return err;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
index 307c8c436862..df5f60925260 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
@@ -21,9 +21,9 @@ static const struct regmap_config st_lsm6dsx_i2c_regmap_config = {
.val_bits = 8,
};
-static int st_lsm6dsx_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int st_lsm6dsx_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int hw_id = id->driver_data;
struct regmap *regmap;
@@ -109,6 +109,22 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
.compatible = "st,lsm6dstx",
.data = (void *)ST_LSM6DSTX_ID,
},
+ {
+ .compatible = "st,lsm6dsv",
+ .data = (void *)ST_LSM6DSV_ID,
+ },
+ {
+ .compatible = "st,lsm6dsv16x",
+ .data = (void *)ST_LSM6DSV16X_ID,
+ },
+ {
+ .compatible = "st,lsm6dso16is",
+ .data = (void *)ST_LSM6DSO16IS_ID,
+ },
+ {
+ .compatible = "st,ism330is",
+ .data = (void *)ST_ISM330IS_ID,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
@@ -132,6 +148,10 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_LSM6DSOP_DEV_NAME, ST_LSM6DSOP_ID },
{ ST_ASM330LHHX_DEV_NAME, ST_ASM330LHHX_ID },
{ ST_LSM6DSTX_DEV_NAME, ST_LSM6DSTX_ID },
+ { ST_LSM6DSV_DEV_NAME, ST_LSM6DSV_ID },
+ { ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID },
+ { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID },
+ { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
{},
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
@@ -142,7 +162,7 @@ static struct i2c_driver st_lsm6dsx_driver = {
.pm = pm_sleep_ptr(&st_lsm6dsx_pm_ops),
.of_match_table = st_lsm6dsx_i2c_of_match,
},
- .probe = st_lsm6dsx_i2c_probe,
+ .probe_new = st_lsm6dsx_i2c_probe,
.id_table = st_lsm6dsx_i2c_id_table,
};
module_i2c_driver(st_lsm6dsx_driver);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
index 99562ba85ee4..f2b64b4956a3 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
@@ -170,9 +170,7 @@ static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw)
*
* Read st_lsm6dsx i2c controller register
*/
-static int
-st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data,
- int len)
+int st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data, int len)
{
const struct st_lsm6dsx_shub_settings *hub_settings;
int err;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
index 6a4eecf4bb05..974584bda875 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
@@ -109,6 +109,22 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
.compatible = "st,lsm6dstx",
.data = (void *)ST_LSM6DSTX_ID,
},
+ {
+ .compatible = "st,lsm6dsv",
+ .data = (void *)ST_LSM6DSV_ID,
+ },
+ {
+ .compatible = "st,lsm6dsv16x",
+ .data = (void *)ST_LSM6DSV16X_ID,
+ },
+ {
+ .compatible = "st,lsm6dso16is",
+ .data = (void *)ST_LSM6DSO16IS_ID,
+ },
+ {
+ .compatible = "st,ism330is",
+ .data = (void *)ST_ISM330IS_ID,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@@ -132,6 +148,10 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_LSM6DSOP_DEV_NAME, ST_LSM6DSOP_ID },
{ ST_ASM330LHHX_DEV_NAME, ST_ASM330LHHX_ID },
{ ST_LSM6DSTX_DEV_NAME, ST_LSM6DSTX_ID },
+ { ST_LSM6DSV_DEV_NAME, ST_LSM6DSV_ID },
+ { ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID },
+ { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID },
+ { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
{},
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
index ae7bc815382f..e887b45cdbcd 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
@@ -18,58 +18,6 @@
#include "st_lsm9ds0.h"
-static int st_lsm9ds0_power_enable(struct device *dev, struct st_lsm9ds0 *lsm9ds0)
-{
- int ret;
-
- /* Regulators not mandatory, but if requested we should enable them. */
- lsm9ds0->vdd = devm_regulator_get(dev, "vdd");
- if (IS_ERR(lsm9ds0->vdd))
- return dev_err_probe(dev, PTR_ERR(lsm9ds0->vdd),
- "unable to get Vdd supply\n");
-
- ret = regulator_enable(lsm9ds0->vdd);
- if (ret) {
- dev_warn(dev, "Failed to enable specified Vdd supply\n");
- return ret;
- }
-
- lsm9ds0->vdd_io = devm_regulator_get(dev, "vddio");
- if (IS_ERR(lsm9ds0->vdd_io)) {
- regulator_disable(lsm9ds0->vdd);
- return dev_err_probe(dev, PTR_ERR(lsm9ds0->vdd_io),
- "unable to get Vdd_IO supply\n");
- }
- ret = regulator_enable(lsm9ds0->vdd_io);
- if (ret) {
- dev_warn(dev, "Failed to enable specified Vdd_IO supply\n");
- regulator_disable(lsm9ds0->vdd);
- return ret;
- }
-
- return 0;
-}
-
-static void st_lsm9ds0_power_disable(void *data)
-{
- struct st_lsm9ds0 *lsm9ds0 = data;
-
- regulator_disable(lsm9ds0->vdd_io);
- regulator_disable(lsm9ds0->vdd);
-}
-
-static int devm_st_lsm9ds0_power_enable(struct st_lsm9ds0 *lsm9ds0)
-{
- struct device *dev = lsm9ds0->dev;
- int ret;
-
- ret = st_lsm9ds0_power_enable(dev, lsm9ds0);
- if (ret)
- return ret;
-
- return devm_add_action_or_reset(dev, st_lsm9ds0_power_disable, lsm9ds0);
-}
-
static int st_lsm9ds0_probe_accel(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap)
{
const struct st_sensor_settings *settings;
@@ -92,8 +40,6 @@ static int st_lsm9ds0_probe_accel(struct st_lsm9ds0 *lsm9ds0, struct regmap *reg
data->sensor_settings = (struct st_sensor_settings *)settings;
data->irq = lsm9ds0->irq;
data->regmap = regmap;
- data->vdd = lsm9ds0->vdd;
- data->vdd_io = lsm9ds0->vdd_io;
return st_accel_common_probe(lsm9ds0->accel);
}
@@ -120,19 +66,22 @@ static int st_lsm9ds0_probe_magn(struct st_lsm9ds0 *lsm9ds0, struct regmap *regm
data->sensor_settings = (struct st_sensor_settings *)settings;
data->irq = lsm9ds0->irq;
data->regmap = regmap;
- data->vdd = lsm9ds0->vdd;
- data->vdd_io = lsm9ds0->vdd_io;
return st_magn_common_probe(lsm9ds0->magn);
}
int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap)
{
+ struct device *dev = lsm9ds0->dev;
+ static const char * const regulator_names[] = { "vdd", "vddio" };
int ret;
- ret = devm_st_lsm9ds0_power_enable(lsm9ds0);
+ /* Regulators not mandatory, but if requested we should enable them. */
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
+ regulator_names);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret,
+ "unable to enable Vdd supply\n");
/* Setup accelerometer device */
ret = st_lsm9ds0_probe_accel(lsm9ds0, regmap);
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 228598b82a2f..80c78bd6bbef 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -507,13 +507,14 @@ static ssize_t iio_scan_el_store(struct device *dev,
int ret;
bool state;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_buffer *buffer = this_attr->buffer;
ret = kstrtobool(buf, &state);
if (ret < 0)
return ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&iio_dev_opaque->mlock);
if (iio_buffer_is_active(buffer)) {
ret = -EBUSY;
goto error_ret;
@@ -532,7 +533,7 @@ static ssize_t iio_scan_el_store(struct device *dev,
}
error_ret:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return ret < 0 ? ret : len;
@@ -554,6 +555,7 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
bool state;
@@ -561,14 +563,14 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
if (ret < 0)
return ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&iio_dev_opaque->mlock);
if (iio_buffer_is_active(buffer)) {
ret = -EBUSY;
goto error_ret;
}
buffer->scan_timestamp = state;
error_ret:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return ret ? ret : len;
}
@@ -642,6 +644,7 @@ static ssize_t length_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
unsigned int val;
int ret;
@@ -653,7 +656,7 @@ static ssize_t length_store(struct device *dev, struct device_attribute *attr,
if (val == buffer->length)
return len;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&iio_dev_opaque->mlock);
if (iio_buffer_is_active(buffer)) {
ret = -EBUSY;
} else {
@@ -665,7 +668,7 @@ static ssize_t length_store(struct device *dev, struct device_attribute *attr,
if (buffer->length && buffer->length < buffer->watermark)
buffer->watermark = buffer->length;
out:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return ret ? ret : len;
}
@@ -1256,7 +1259,7 @@ int iio_update_buffers(struct iio_dev *indio_dev,
return -EINVAL;
mutex_lock(&iio_dev_opaque->info_exist_lock);
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&iio_dev_opaque->mlock);
if (insert_buffer && iio_buffer_is_active(insert_buffer))
insert_buffer = NULL;
@@ -1277,7 +1280,7 @@ int iio_update_buffers(struct iio_dev *indio_dev,
ret = __iio_update_buffers(indio_dev, insert_buffer, remove_buffer);
out_unlock:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
@@ -1296,6 +1299,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
int ret;
bool requested_state;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
bool inlist;
@@ -1303,7 +1307,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
if (ret < 0)
return ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&iio_dev_opaque->mlock);
/* Find out if it is in the list */
inlist = iio_buffer_is_active(buffer);
@@ -1317,7 +1321,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
ret = __iio_update_buffers(indio_dev, NULL, buffer);
done:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return (ret < 0) ? ret : len;
}
@@ -1334,6 +1338,7 @@ static ssize_t watermark_store(struct device *dev,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
unsigned int val;
int ret;
@@ -1344,7 +1349,7 @@ static ssize_t watermark_store(struct device *dev,
if (!val)
return -EINVAL;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&iio_dev_opaque->mlock);
if (val > buffer->length) {
ret = -EINVAL;
@@ -1358,7 +1363,7 @@ static ssize_t watermark_store(struct device *dev,
buffer->watermark = val;
out:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return ret ? ret : len;
}
@@ -1600,6 +1605,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
{
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_dev_attr *p;
+ const struct iio_dev_attr *id_attr;
struct attribute **attr;
int ret, i, attrn, scan_el_attrcount, buffer_attrcount;
const struct iio_chan_spec *channels;
@@ -1609,6 +1615,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
while (buffer->attrs[buffer_attrcount] != NULL)
buffer_attrcount++;
}
+ buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs);
scan_el_attrcount = 0;
INIT_LIST_HEAD(&buffer->buffer_attr_list);
@@ -1651,7 +1658,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
}
}
- attrn = buffer_attrcount + scan_el_attrcount + ARRAY_SIZE(iio_buffer_attrs);
+ attrn = buffer_attrcount + scan_el_attrcount;
attr = kcalloc(attrn + 1, sizeof(*attr), GFP_KERNEL);
if (!attr) {
ret = -ENOMEM;
@@ -1666,10 +1673,11 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
attr[2] = &dev_attr_watermark_ro.attr;
if (buffer->attrs)
- memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs,
- sizeof(struct attribute *) * buffer_attrcount);
+ for (i = 0, id_attr = buffer->attrs[i];
+ (id_attr = buffer->attrs[i]); i++)
+ attr[ARRAY_SIZE(iio_buffer_attrs) + i] =
+ (struct attribute *)&id_attr->dev_attr.attr;
- buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs);
buffer->buffer_group.attrs = attr;
for (i = 0; i < buffer_attrcount; i++) {
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 151ff3993354..52e690f031cb 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -285,16 +285,16 @@ int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
const struct iio_event_interface *ev_int = iio_dev_opaque->event_interface;
- ret = mutex_lock_interruptible(&indio_dev->mlock);
+ ret = mutex_lock_interruptible(&iio_dev_opaque->mlock);
if (ret)
return ret;
if ((ev_int && iio_event_enabled(ev_int)) ||
iio_buffer_enabled(indio_dev)) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return -EBUSY;
}
iio_dev_opaque->clock_id = clock_id;
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return 0;
}
@@ -1674,7 +1674,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
indio_dev->dev.type = &iio_device_type;
indio_dev->dev.bus = &iio_bus_type;
device_initialize(&indio_dev->dev);
- mutex_init(&indio_dev->mlock);
+ mutex_init(&iio_dev_opaque->mlock);
mutex_init(&iio_dev_opaque->info_exist_lock);
INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list);
@@ -1696,7 +1696,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers);
lockdep_register_key(&iio_dev_opaque->mlock_key);
- lockdep_set_class(&indio_dev->mlock, &iio_dev_opaque->mlock_key);
+ lockdep_set_class(&iio_dev_opaque->mlock, &iio_dev_opaque->mlock_key);
return indio_dev;
}
@@ -2058,10 +2058,12 @@ EXPORT_SYMBOL_GPL(__devm_iio_device_register);
*/
int iio_device_claim_direct_mode(struct iio_dev *indio_dev)
{
- mutex_lock(&indio_dev->mlock);
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+
+ mutex_lock(&iio_dev_opaque->mlock);
if (iio_buffer_enabled(indio_dev)) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return -EBUSY;
}
return 0;
@@ -2079,11 +2081,51 @@ EXPORT_SYMBOL_GPL(iio_device_claim_direct_mode);
*/
void iio_device_release_direct_mode(struct iio_dev *indio_dev)
{
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&to_iio_dev_opaque(indio_dev)->mlock);
}
EXPORT_SYMBOL_GPL(iio_device_release_direct_mode);
/**
+ * iio_device_claim_buffer_mode - Keep device in buffer mode
+ * @indio_dev: the iio_dev associated with the device
+ *
+ * If the device is in buffer mode it is guaranteed to stay
+ * that way until iio_device_release_buffer_mode() is called.
+ *
+ * Use with iio_device_release_buffer_mode().
+ *
+ * Returns: 0 on success, -EBUSY on failure.
+ */
+int iio_device_claim_buffer_mode(struct iio_dev *indio_dev)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+
+ mutex_lock(&iio_dev_opaque->mlock);
+
+ if (iio_buffer_enabled(indio_dev))
+ return 0;
+
+ mutex_unlock(&iio_dev_opaque->mlock);
+ return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(iio_device_claim_buffer_mode);
+
+/**
+ * iio_device_release_buffer_mode - releases claim on buffer mode
+ * @indio_dev: the iio_dev associated with the device
+ *
+ * Release the claim. Device is no longer guaranteed to stay
+ * in buffer mode.
+ *
+ * Use with iio_device_claim_buffer_mode().
+ */
+void iio_device_release_buffer_mode(struct iio_dev *indio_dev)
+{
+ mutex_unlock(&to_iio_dev_opaque(indio_dev)->mlock);
+}
+EXPORT_SYMBOL_GPL(iio_device_release_buffer_mode);
+
+/**
* iio_device_get_current_mode() - helper function providing read-only access to
* the opaque @currentmode variable
* @indio_dev: IIO device structure for device
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 3d78da2531a9..f77ce49d4c36 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -198,7 +198,7 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
if (ev_int == NULL)
return -ENODEV;
- fd = mutex_lock_interruptible(&indio_dev->mlock);
+ fd = mutex_lock_interruptible(&iio_dev_opaque->mlock);
if (fd)
return fd;
@@ -219,7 +219,7 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
}
unlock:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return fd;
}
@@ -556,7 +556,7 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
ret = iio_device_register_sysfs_group(indio_dev, &ev_int->group);
if (ret)
- goto error_free_setup_event_lines;
+ goto error_free_group_attrs;
ev_int->ioctl_handler.ioctl = iio_event_ioctl;
iio_device_ioctl_handler_register(&iio_dev_opaque->indio_dev,
@@ -564,6 +564,8 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
return 0;
+error_free_group_attrs:
+ kfree(ev_int->group.attrs);
error_free_setup_event_lines:
iio_free_chan_devattr_list(&ev_int->dev_attr_list);
kfree(ev_int);
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 6885a186fe27..a2f3cc2f65ef 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -120,12 +120,12 @@ int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *tri
return -EINVAL;
iio_dev_opaque = to_iio_dev_opaque(indio_dev);
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&iio_dev_opaque->mlock);
WARN_ON(iio_dev_opaque->trig_readonly);
indio_dev->trig = iio_trigger_get(trig);
iio_dev_opaque->trig_readonly = true;
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return 0;
}
@@ -438,16 +438,16 @@ static ssize_t current_trigger_store(struct device *dev,
struct iio_trigger *trig;
int ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&iio_dev_opaque->mlock);
if (iio_dev_opaque->currentmode == INDIO_BUFFER_TRIGGERED) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return -EBUSY;
}
if (iio_dev_opaque->trig_readonly) {
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
return -EPERM;
}
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&iio_dev_opaque->mlock);
trig = iio_trigger_acquire_by_name(buf);
if (oldtrig == trig) {
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index 6b33975c8d73..210a90f44c53 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -233,8 +233,7 @@ static const struct iio_info adjd_s311_info = {
.write_raw = adjd_s311_write_raw,
};
-static int adjd_s311_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adjd_s311_probe(struct i2c_client *client)
{
struct adjd_s311_data *data;
struct iio_dev *indio_dev;
@@ -271,7 +270,7 @@ static struct i2c_driver adjd_s311_driver = {
.driver = {
.name = ADJD_S311_DRV_NAME,
},
- .probe = adjd_s311_probe,
+ .probe_new = 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 9aa28695e6f1..606075350d01 100644
--- a/drivers/iio/light/adux1020.c
+++ b/drivers/iio/light/adux1020.c
@@ -774,8 +774,7 @@ static int adux1020_chip_init(struct adux1020_data *data)
ADUX1020_MODE_INT_MASK, ADUX1020_MODE_INT_DISABLE);
}
-static int adux1020_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adux1020_probe(struct i2c_client *client)
{
struct adux1020_data *data;
struct iio_dev *indio_dev;
@@ -838,7 +837,7 @@ static struct i2c_driver adux1020_driver = {
.name = ADUX1020_DRV_NAME,
.of_match_table = adux1020_of_match,
},
- .probe = adux1020_probe,
+ .probe_new = 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 ce5363845b22..69cc723e2ac4 100644
--- a/drivers/iio/light/al3010.c
+++ b/drivers/iio/light/al3010.c
@@ -164,8 +164,7 @@ static const struct iio_info al3010_info = {
.attrs = &al3010_attribute_group,
};
-static int al3010_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int al3010_probe(struct i2c_client *client)
{
struct al3010_data *data;
struct iio_dev *indio_dev;
@@ -230,7 +229,7 @@ static struct i2c_driver al3010_driver = {
.of_match_table = al3010_of_match,
.pm = pm_sleep_ptr(&al3010_pm_ops),
},
- .probe = al3010_probe,
+ .probe_new = 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 bc99179728ed..9ff28bbf34bb 100644
--- a/drivers/iio/light/al3320a.c
+++ b/drivers/iio/light/al3320a.c
@@ -187,8 +187,7 @@ static const struct iio_info al3320a_info = {
.attrs = &al3320a_attribute_group,
};
-static int al3320a_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int al3320a_probe(struct i2c_client *client)
{
struct al3320a_data *data;
struct iio_dev *indio_dev;
@@ -254,7 +253,7 @@ static struct i2c_driver al3320a_driver = {
.of_match_table = al3320a_of_match,
.pm = pm_sleep_ptr(&al3320a_pm_ops),
},
- .probe = al3320a_probe,
+ .probe_new = al3320a_probe,
.id_table = al3320a_id,
};
diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c
index b70f2681bcb3..15dfb753734f 100644
--- a/drivers/iio/light/apds9300.c
+++ b/drivers/iio/light/apds9300.c
@@ -398,8 +398,7 @@ static irqreturn_t apds9300_interrupt_handler(int irq, void *private)
return IRQ_HANDLED;
}
-static int apds9300_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int apds9300_probe(struct i2c_client *client)
{
struct apds9300_data *data;
struct iio_dev *indio_dev;
@@ -505,7 +504,7 @@ static struct i2c_driver apds9300_driver = {
.name = APDS9300_DRV_NAME,
.pm = pm_sleep_ptr(&apds9300_pm_ops),
},
- .probe = apds9300_probe,
+ .probe_new = apds9300_probe,
.remove = apds9300_remove,
.id_table = apds9300_id,
};
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index 38d4c7644bef..cc5974a95bd3 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -223,14 +223,16 @@ static const struct iio_event_spec apds9960_pxs_event_spec[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
- .mask_separate = BIT(IIO_EV_INFO_VALUE) |
- BIT(IIO_EV_INFO_ENABLE),
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
- .mask_separate = BIT(IIO_EV_INFO_VALUE) |
- BIT(IIO_EV_INFO_ENABLE),
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
},
};
@@ -238,14 +240,16 @@ static const struct iio_event_spec apds9960_als_event_spec[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
- .mask_separate = BIT(IIO_EV_INFO_VALUE) |
- BIT(IIO_EV_INFO_ENABLE),
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
- .mask_separate = BIT(IIO_EV_INFO_VALUE) |
- BIT(IIO_EV_INFO_ENABLE),
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
},
};
@@ -984,8 +988,7 @@ static int apds9960_chip_init(struct apds9960_data *data)
return apds9960_set_powermode(data, 1);
}
-static int apds9960_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int apds9960_probe(struct i2c_client *client)
{
struct apds9960_data *data;
struct iio_dev *indio_dev;
@@ -1128,7 +1131,7 @@ static struct i2c_driver apds9960_driver = {
.pm = &apds9960_pm_ops,
.acpi_match_table = apds9960_acpi_match,
},
- .probe = apds9960_probe,
+ .probe_new = apds9960_probe,
.remove = apds9960_remove,
.id_table = apds9960_id,
};
diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c
index 3e92820bc820..390c5b3ad4f6 100644
--- a/drivers/iio/light/bh1750.c
+++ b/drivers/iio/light/bh1750.c
@@ -228,9 +228,9 @@ static const struct iio_chan_spec bh1750_channels[] = {
}
};
-static int bh1750_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bh1750_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret, usec;
struct bh1750_data *data;
struct iio_dev *indio_dev;
@@ -320,7 +320,7 @@ static struct i2c_driver bh1750_driver = {
.of_match_table = bh1750_of_match,
.pm = pm_sleep_ptr(&bh1750_pm_ops),
},
- .probe = bh1750_probe,
+ .probe_new = bh1750_probe,
.remove = bh1750_remove,
.id_table = bh1750_id,
diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c
index 90bca392b262..da9039e5a839 100644
--- a/drivers/iio/light/bh1780.c
+++ b/drivers/iio/light/bh1780.c
@@ -141,8 +141,7 @@ static const struct iio_chan_spec bh1780_channels[] = {
}
};
-static int bh1780_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bh1780_probe(struct i2c_client *client)
{
int ret;
struct bh1780_data *bh1780;
@@ -270,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 = bh1780_probe,
+ .probe_new = bh1780_probe,
.remove = bh1780_remove,
.id_table = bh1780_id,
.driver = {
diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c
index 5214cd014cf8..43e492f5051d 100644
--- a/drivers/iio/light/cm3232.c
+++ b/drivers/iio/light/cm3232.c
@@ -325,9 +325,9 @@ static const struct iio_info cm3232_info = {
.attrs = &cm3232_attribute_group,
};
-static int cm3232_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int cm3232_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct cm3232_chip *chip;
struct iio_dev *indio_dev;
int ret;
@@ -417,7 +417,7 @@ static struct i2c_driver cm3232_driver = {
.pm = pm_sleep_ptr(&cm3232_pm_ops),
},
.id_table = cm3232_id,
- .probe = cm3232_probe,
+ .probe_new = cm3232_probe,
.remove = cm3232_remove,
};
diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c
index fd9a8c27de2e..e5ce7d0fd272 100644
--- a/drivers/iio/light/cm3323.c
+++ b/drivers/iio/light/cm3323.c
@@ -214,8 +214,7 @@ static const struct iio_info cm3323_info = {
.attrs = &cm3323_attribute_group,
};
-static int cm3323_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int cm3323_probe(struct i2c_client *client)
{
struct cm3323_data *data;
struct iio_dev *indio_dev;
@@ -267,7 +266,7 @@ static struct i2c_driver cm3323_driver = {
.name = CM3323_DRV_NAME,
.of_match_table = cm3323_of_match,
},
- .probe = cm3323_probe,
+ .probe_new = cm3323_probe,
.id_table = cm3323_id,
};
diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c
index 6615c98b601c..1707dbf2ce26 100644
--- a/drivers/iio/light/cm36651.c
+++ b/drivers/iio/light/cm36651.c
@@ -618,9 +618,9 @@ static const struct iio_info cm36651_info = {
.attrs = &cm36651_attribute_group,
};
-static int cm36651_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int cm36651_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct cm36651_data *cm36651;
struct iio_dev *indio_dev;
int ret;
@@ -730,7 +730,7 @@ static struct i2c_driver cm36651_driver = {
.name = "cm36651",
.of_match_table = cm36651_of_match,
},
- .probe = cm36651_probe,
+ .probe_new = cm36651_probe,
.remove = cm36651_remove,
.id_table = cm36651_id,
};
diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c
index 8000fa347344..c0430db0038a 100644
--- a/drivers/iio/light/gp2ap002.c
+++ b/drivers/iio/light/gp2ap002.c
@@ -425,8 +425,7 @@ static struct regmap_bus gp2ap002_regmap_bus = {
.reg_write = gp2ap002_regmap_i2c_write,
};
-static int gp2ap002_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int gp2ap002_probe(struct i2c_client *client)
{
struct gp2ap002 *gp2ap002;
struct iio_dev *indio_dev;
@@ -711,7 +710,7 @@ static struct i2c_driver gp2ap002_driver = {
.of_match_table = gp2ap002_of_match,
.pm = pm_ptr(&gp2ap002_dev_pm_ops),
},
- .probe = gp2ap002_probe,
+ .probe_new = 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 826439299e8b..a5bf9da0d2f3 100644
--- a/drivers/iio/light/gp2ap020a00f.c
+++ b/drivers/iio/light/gp2ap020a00f.c
@@ -1467,9 +1467,9 @@ static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = {
.predisable = &gp2ap020a00f_buffer_predisable,
};
-static int gp2ap020a00f_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int gp2ap020a00f_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct gp2ap020a00f_data *data;
struct iio_dev *indio_dev;
struct regmap *regmap;
@@ -1609,7 +1609,7 @@ static struct i2c_driver gp2ap020a00f_driver = {
.name = GP2A_I2C_NAME,
.of_match_table = gp2ap020a00f_of_match,
},
- .probe = gp2ap020a00f_probe,
+ .probe_new = gp2ap020a00f_probe,
.remove = gp2ap020a00f_remove,
.id_table = gp2ap020a00f_id,
};
diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c
index b36f8b7ca68e..141845fb47f9 100644
--- a/drivers/iio/light/isl29018.c
+++ b/drivers/iio/light/isl29018.c
@@ -711,9 +711,9 @@ static void isl29018_disable_regulator_action(void *_data)
pr_err("failed to disable isl29018's VCC regulator!\n");
}
-static int isl29018_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int isl29018_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct isl29018_chip *chip;
struct iio_dev *indio_dev;
int err;
@@ -865,7 +865,7 @@ static struct i2c_driver isl29018_driver = {
.pm = pm_sleep_ptr(&isl29018_pm_ops),
.of_match_table = isl29018_of_match,
},
- .probe = isl29018_probe,
+ .probe_new = 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 32d58e18f26d..bcf3a556e41a 100644
--- a/drivers/iio/light/isl29028.c
+++ b/drivers/iio/light/isl29028.c
@@ -565,9 +565,9 @@ static const struct regmap_config isl29028_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
-static int isl29028_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int isl29028_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct isl29028_chip *chip;
struct iio_dev *indio_dev;
int ret;
@@ -698,7 +698,7 @@ static struct i2c_driver isl29028_driver = {
.pm = pm_ptr(&isl29028_pm_ops),
.of_match_table = isl29028_of_match,
},
- .probe = isl29028_probe,
+ .probe_new = isl29028_probe,
.remove = isl29028_remove,
.id_table = isl29028_id,
};
diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c
index c199e63cce82..b4bd656ca169 100644
--- a/drivers/iio/light/isl29125.c
+++ b/drivers/iio/light/isl29125.c
@@ -241,8 +241,7 @@ static const struct iio_buffer_setup_ops isl29125_buffer_setup_ops = {
.predisable = isl29125_buffer_predisable,
};
-static int isl29125_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int isl29125_probe(struct i2c_client *client)
{
struct isl29125_data *data;
struct iio_dev *indio_dev;
@@ -338,7 +337,7 @@ static struct i2c_driver isl29125_driver = {
.name = ISL29125_DRV_NAME,
.pm = pm_sleep_ptr(&isl29125_pm_ops),
},
- .probe = isl29125_probe,
+ .probe_new = isl29125_probe,
.remove = isl29125_remove,
.id_table = isl29125_id,
};
diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c
index 57ce6d75966c..d3834d0a0635 100644
--- a/drivers/iio/light/jsa1212.c
+++ b/drivers/iio/light/jsa1212.c
@@ -308,8 +308,7 @@ static const struct regmap_config jsa1212_regmap_config = {
.volatile_reg = jsa1212_is_volatile_reg,
};
-static int jsa1212_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int jsa1212_probe(struct i2c_client *client)
{
struct jsa1212_data *data;
struct iio_dev *indio_dev;
@@ -441,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 = jsa1212_probe,
+ .probe_new = jsa1212_probe,
.remove = jsa1212_remove,
.id_table = jsa1212_id,
};
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
index 74a1ccda8b9c..bdbd918213e4 100644
--- a/drivers/iio/light/ltr501.c
+++ b/drivers/iio/light/ltr501.c
@@ -153,7 +153,6 @@ struct ltr501_chip_info {
struct ltr501_data {
struct i2c_client *client;
- struct regulator_bulk_data regulators[2];
struct mutex lock_als, lock_ps;
const struct ltr501_chip_info *chip_info;
u8 als_contr, ps_contr;
@@ -1415,13 +1414,6 @@ static const struct regmap_config ltr501_regmap_config = {
.volatile_reg = ltr501_is_volatile_reg,
};
-static void ltr501_disable_regulators(void *d)
-{
- struct ltr501_data *data = d;
-
- regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
-}
-
static int ltr501_powerdown(struct ltr501_data *data)
{
return ltr501_write_contr(data, data->als_contr &
@@ -1440,9 +1432,10 @@ static const char *ltr501_match_acpi_device(struct device *dev, int *chip_idx)
return dev_name(dev);
}
-static int ltr501_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ltr501_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ static const char * const regulator_names[] = { "vdd", "vddio" };
struct ltr501_data *data;
struct iio_dev *indio_dev;
struct regmap *regmap;
@@ -1466,25 +1459,13 @@ static int ltr501_probe(struct i2c_client *client,
mutex_init(&data->lock_als);
mutex_init(&data->lock_ps);
- data->regulators[0].supply = "vdd";
- data->regulators[1].supply = "vddio";
- ret = devm_regulator_bulk_get(&client->dev,
- ARRAY_SIZE(data->regulators),
- data->regulators);
+ ret = devm_regulator_bulk_get_enable(&client->dev,
+ ARRAY_SIZE(regulator_names),
+ regulator_names);
if (ret)
return dev_err_probe(&client->dev, ret,
"Failed to get regulators\n");
- ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
- data->regulators);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&client->dev,
- ltr501_disable_regulators, data);
- if (ret)
- return ret;
-
data->reg_it = devm_regmap_field_alloc(&client->dev, regmap,
reg_field_it);
if (IS_ERR(data->reg_it)) {
@@ -1660,7 +1641,7 @@ static struct i2c_driver ltr501_driver = {
.pm = pm_sleep_ptr(&ltr501_pm_ops),
.acpi_match_table = ACPI_PTR(ltr_acpi_match),
},
- .probe = ltr501_probe,
+ .probe_new = ltr501_probe,
.remove = ltr501_remove,
.id_table = ltr501_id,
};
diff --git a/drivers/iio/light/lv0104cs.c b/drivers/iio/light/lv0104cs.c
index c2aef88f4e63..c041fa0faa5d 100644
--- a/drivers/iio/light/lv0104cs.c
+++ b/drivers/iio/light/lv0104cs.c
@@ -474,8 +474,7 @@ static const struct iio_chan_spec lv0104cs_channels[] = {
},
};
-static int lv0104cs_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lv0104cs_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct lv0104cs_private *lv0104cs;
@@ -521,7 +520,7 @@ static struct i2c_driver lv0104cs_i2c_driver = {
.name = "lv0104cs",
},
.id_table = lv0104cs_id,
- .probe = lv0104cs_probe,
+ .probe_new = lv0104cs_probe,
};
module_i2c_driver(lv0104cs_i2c_driver);
diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c
index 85689dffbcbf..5dcabc43a30e 100644
--- a/drivers/iio/light/max44000.c
+++ b/drivers/iio/light/max44000.c
@@ -523,8 +523,7 @@ out_unlock:
return IRQ_HANDLED;
}
-static int max44000_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max44000_probe(struct i2c_client *client)
{
struct max44000_data *data;
struct iio_dev *indio_dev;
@@ -617,7 +616,7 @@ static struct i2c_driver max44000_driver = {
.name = MAX44000_DRV_NAME,
.acpi_match_table = ACPI_PTR(max44000_acpi_match),
},
- .probe = max44000_probe,
+ .probe_new = max44000_probe,
.id_table = max44000_id,
};
diff --git a/drivers/iio/light/noa1305.c b/drivers/iio/light/noa1305.c
index ee81fe083e4c..eaf548d4649e 100644
--- a/drivers/iio/light/noa1305.c
+++ b/drivers/iio/light/noa1305.c
@@ -46,7 +46,6 @@
struct noa1305_priv {
struct i2c_client *client;
struct regmap *regmap;
- struct regulator *vin_reg;
};
static int noa1305_measure(struct noa1305_priv *priv)
@@ -187,15 +186,7 @@ static const struct regmap_config noa1305_regmap_config = {
.writeable_reg = noa1305_writable_reg,
};
-static void noa1305_reg_remove(void *data)
-{
- struct noa1305_priv *priv = data;
-
- regulator_disable(priv->vin_reg);
-}
-
-static int noa1305_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int noa1305_probe(struct i2c_client *client)
{
struct noa1305_priv *priv;
struct iio_dev *indio_dev;
@@ -216,23 +207,11 @@ static int noa1305_probe(struct i2c_client *client,
priv = iio_priv(indio_dev);
- priv->vin_reg = devm_regulator_get(&client->dev, "vin");
- if (IS_ERR(priv->vin_reg))
- return dev_err_probe(&client->dev, PTR_ERR(priv->vin_reg),
+ ret = devm_regulator_get_enable(&client->dev, "vin");
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
"get regulator vin failed\n");
- ret = regulator_enable(priv->vin_reg);
- if (ret) {
- dev_err(&client->dev, "enable regulator vin failed\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(&client->dev, noa1305_reg_remove, priv);
- if (ret) {
- dev_err(&client->dev, "addition of devm action failed\n");
- return ret;
- }
-
i2c_set_clientdata(client, indio_dev);
priv->client = client;
priv->regmap = regmap;
@@ -299,7 +278,7 @@ static struct i2c_driver noa1305_driver = {
.name = NOA1305_DRIVER_NAME,
.of_match_table = noa1305_of_match,
},
- .probe = noa1305_probe,
+ .probe_new = noa1305_probe,
.id_table = noa1305_ids,
};
diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c
index a26d1c3f9543..ec4f5c2369c4 100644
--- a/drivers/iio/light/opt3001.c
+++ b/drivers/iio/light/opt3001.c
@@ -735,8 +735,7 @@ out:
return IRQ_HANDLED;
}
-static int opt3001_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int opt3001_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -835,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 = opt3001_probe,
+ .probe_new = opt3001_probe,
.remove = opt3001_remove,
.id_table = opt3001_id,
diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c
index 3cb2de51f4aa..15a666f15c27 100644
--- a/drivers/iio/light/pa12203001.c
+++ b/drivers/iio/light/pa12203001.c
@@ -338,8 +338,7 @@ out:
return ret;
}
-static int pa12203001_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int pa12203001_probe(struct i2c_client *client)
{
struct pa12203001_data *data;
struct iio_dev *indio_dev;
@@ -475,7 +474,7 @@ static struct i2c_driver pa12203001_driver = {
.pm = &pa12203001_pm_ops,
.acpi_match_table = ACPI_PTR(pa12203001_acpi_match),
},
- .probe = pa12203001_probe,
+ .probe_new = pa12203001_probe,
.remove = pa12203001_remove,
.id_table = pa12203001_id,
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index d1c16dd76058..668e444f6049 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -927,8 +927,7 @@ static const struct regmap_config rpr0521_regmap_config = {
.volatile_reg = rpr0521_is_volatile_reg,
};
-static int rpr0521_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int rpr0521_probe(struct i2c_client *client)
{
struct rpr0521_data *data;
struct iio_dev *indio_dev;
@@ -1122,7 +1121,7 @@ static struct i2c_driver rpr0521_driver = {
.pm = pm_ptr(&rpr0521_pm_ops),
.acpi_match_table = ACPI_PTR(rpr0521_acpi_match),
},
- .probe = rpr0521_probe,
+ .probe_new = rpr0521_probe,
.remove = rpr0521_remove,
.id_table = rpr0521_id,
};
diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c
index f8c9b2cc322e..a08fbc8f5adb 100644
--- a/drivers/iio/light/si1133.c
+++ b/drivers/iio/light/si1133.c
@@ -990,9 +990,9 @@ static int si1133_validate_ids(struct iio_dev *iio_dev)
return 0;
}
-static int si1133_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int si1133_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct si1133_data *data;
struct iio_dev *iio_dev;
int err;
@@ -1064,7 +1064,7 @@ static struct i2c_driver si1133_driver = {
.driver = {
.name = "si1133",
},
- .probe = si1133_probe,
+ .probe_new = si1133_probe,
.id_table = si1133_ids,
};
diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c
index e8f6cdf26f22..f7126235f94c 100644
--- a/drivers/iio/light/si1145.c
+++ b/drivers/iio/light/si1145.c
@@ -1269,9 +1269,9 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev)
return 0;
}
-static int si1145_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int si1145_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct si1145_data *data;
struct iio_dev *indio_dev;
u8 part_id, rev_id, seq_id;
@@ -1352,7 +1352,7 @@ static struct i2c_driver si1145_driver = {
.driver = {
.name = "si1145",
},
- .probe = si1145_probe,
+ .probe_new = 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 c982b0b255cf..2160e87bb498 100644
--- a/drivers/iio/light/st_uvis25_i2c.c
+++ b/drivers/iio/light/st_uvis25_i2c.c
@@ -25,8 +25,7 @@ static const struct regmap_config st_uvis25_i2c_regmap_config = {
.read_flag_mask = UVIS25_I2C_AUTO_INCREMENT,
};
-static int st_uvis25_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int st_uvis25_i2c_probe(struct i2c_client *client)
{
struct regmap *regmap;
@@ -58,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 = st_uvis25_i2c_probe,
+ .probe_new = 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 7b8e0da6aabc..48ae6ff0015e 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -586,8 +586,7 @@ out:
return IRQ_HANDLED;
}
-static int stk3310_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int stk3310_probe(struct i2c_client *client)
{
int ret;
struct iio_dev *indio_dev;
@@ -715,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 = stk3310_probe,
+ .probe_new = 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 3951536022b3..5100732fbaf0 100644
--- a/drivers/iio/light/tcs3414.c
+++ b/drivers/iio/light/tcs3414.c
@@ -279,8 +279,7 @@ static void tcs3414_powerdown_cleanup(void *data)
tcs3414_powerdown(data);
}
-static int tcs3414_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tcs3414_probe(struct i2c_client *client)
{
struct tcs3414_data *data;
struct iio_dev *indio_dev;
@@ -374,7 +373,7 @@ static struct i2c_driver tcs3414_driver = {
.name = TCS3414_DRV_NAME,
.pm = pm_sleep_ptr(&tcs3414_pm_ops),
},
- .probe = tcs3414_probe,
+ .probe_new = 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 db17fec634be..6187c5487916 100644
--- a/drivers/iio/light/tcs3472.c
+++ b/drivers/iio/light/tcs3472.c
@@ -442,8 +442,7 @@ static const struct iio_info tcs3472_info = {
.attrs = &tcs3472_attribute_group,
};
-static int tcs3472_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tcs3472_probe(struct i2c_client *client)
{
struct tcs3472_data *data;
struct iio_dev *indio_dev;
@@ -610,7 +609,7 @@ static struct i2c_driver tcs3472_driver = {
.name = TCS3472_DRV_NAME,
.pm = pm_sleep_ptr(&tcs3472_pm_ops),
},
- .probe = tcs3472_probe,
+ .probe_new = tcs3472_probe,
.remove = tcs3472_remove,
.id_table = tcs3472_id,
};
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index 951f35ef3f41..d0e42b73203a 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -699,8 +699,7 @@ static const struct iio_info tsl2563_info = {
.write_event_config = &tsl2563_write_interrupt_config,
};
-static int tsl2563_probe(struct i2c_client *client,
- const struct i2c_device_id *device_id)
+static int tsl2563_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct tsl2563_chip *chip;
@@ -880,7 +879,7 @@ static struct i2c_driver tsl2563_i2c_driver = {
.of_match_table = tsl2563_of_match,
.pm = pm_sleep_ptr(&tsl2563_pm_ops),
},
- .probe = tsl2563_probe,
+ .probe_new = tsl2563_probe,
.remove = tsl2563_remove,
.id_table = tsl2563_id,
};
diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c
index 7bcb5c718922..a05f1c0453d1 100644
--- a/drivers/iio/light/tsl2583.c
+++ b/drivers/iio/light/tsl2583.c
@@ -809,8 +809,7 @@ static const struct iio_info tsl2583_info = {
.write_raw = tsl2583_write_raw,
};
-static int tsl2583_probe(struct i2c_client *clientp,
- const struct i2c_device_id *idp)
+static int tsl2583_probe(struct i2c_client *clientp)
{
int ret;
struct tsl2583_chip *chip;
@@ -943,7 +942,7 @@ static struct i2c_driver tsl2583_driver = {
.of_match_table = tsl2583_of_match,
},
.id_table = tsl2583_idtable,
- .probe = tsl2583_probe,
+ .probe_new = tsl2583_probe,
.remove = tsl2583_remove,
};
module_i2c_driver(tsl2583_driver);
diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c
index dd9051f1cc1a..ad50baa0202c 100644
--- a/drivers/iio/light/tsl2772.c
+++ b/drivers/iio/light/tsl2772.c
@@ -1750,9 +1750,9 @@ static const struct tsl2772_chip_info tsl2772_chip_info_tbl[] = {
},
};
-static int tsl2772_probe(struct i2c_client *clientp,
- const struct i2c_device_id *id)
+static int tsl2772_probe(struct i2c_client *clientp)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(clientp);
struct iio_dev *indio_dev;
struct tsl2772_chip *chip;
int ret;
@@ -1931,7 +1931,7 @@ static struct i2c_driver tsl2772_driver = {
.pm = &tsl2772_pm_ops,
},
.id_table = tsl2772_idtable,
- .probe = tsl2772_probe,
+ .probe_new = tsl2772_probe,
};
module_i2c_driver(tsl2772_driver);
diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c
index 090038fed889..d95397eb1526 100644
--- a/drivers/iio/light/tsl4531.c
+++ b/drivers/iio/light/tsl4531.c
@@ -160,8 +160,7 @@ static int tsl4531_check_id(struct i2c_client *client)
}
}
-static int tsl4531_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tsl4531_probe(struct i2c_client *client)
{
struct tsl4531_data *data;
struct iio_dev *indio_dev;
@@ -238,7 +237,7 @@ static struct i2c_driver tsl4531_driver = {
.name = TSL4531_DRV_NAME,
.pm = pm_sleep_ptr(&tsl4531_pm_ops),
},
- .probe = tsl4531_probe,
+ .probe_new = tsl4531_probe,
.remove = tsl4531_remove,
.id_table = tsl4531_id,
};
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c
index 3e652d7f3b0e..8b2a0c99c8e6 100644
--- a/drivers/iio/light/us5182d.c
+++ b/drivers/iio/light/us5182d.c
@@ -832,8 +832,7 @@ static irqreturn_t us5182d_irq_thread_handler(int irq, void *private)
return IRQ_HANDLED;
}
-static int us5182d_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int us5182d_probe(struct i2c_client *client)
{
struct us5182d_data *data;
struct iio_dev *indio_dev;
@@ -975,7 +974,7 @@ static struct i2c_driver us5182d_driver = {
.of_match_table = us5182d_of_match,
.acpi_match_table = ACPI_PTR(us5182d_acpi_match),
},
- .probe = us5182d_probe,
+ .probe_new = us5182d_probe,
.remove = us5182d_remove,
.id_table = us5182d_id,
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index f6c83ecaad8b..cc1a2062e76d 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -17,6 +17,7 @@
* interrupts (VCNL4040, VCNL4200)
*/
+#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
@@ -74,6 +75,10 @@
#define VCNL4000_PROX_EN BIT(1) /* start proximity measurement */
#define VCNL4000_SELF_TIMED_EN BIT(0) /* start self-timed measurement */
+#define VCNL4040_ALS_CONF_ALS_SHUTDOWN BIT(0)
+#define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0)
+#define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */
+
/* Bit masks for interrupt registers. */
#define VCNL4010_INT_THR_SEL BIT(0) /* Select threshold interrupt source */
#define VCNL4010_INT_THR_EN BIT(1) /* Threshold interrupt type */
@@ -101,6 +106,17 @@ static const int vcnl4010_prox_sampling_frequency[][2] = {
{250, 0},
};
+static const int vcnl4040_ps_it_times[][2] = {
+ {0, 100},
+ {0, 150},
+ {0, 200},
+ {0, 250},
+ {0, 300},
+ {0, 350},
+ {0, 400},
+ {0, 800},
+};
+
#define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */
enum vcnl4000_device_ids {
@@ -188,16 +204,61 @@ static int vcnl4000_init(struct vcnl4000_data *data)
return data->chip_spec->set_power_state(data, true);
};
+static ssize_t vcnl4000_write_als_enable(struct vcnl4000_data *data, bool en)
+{
+ int ret;
+
+ mutex_lock(&data->vcnl4000_lock);
+
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
+ if (ret < 0)
+ goto out;
+
+ if (en)
+ ret &= ~VCNL4040_ALS_CONF_ALS_SHUTDOWN;
+ else
+ ret |= VCNL4040_ALS_CONF_ALS_SHUTDOWN;
+
+ ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, ret);
+
+out:
+ mutex_unlock(&data->vcnl4000_lock);
+
+ return ret;
+}
+
+static ssize_t vcnl4000_write_ps_enable(struct vcnl4000_data *data, bool en)
+{
+ int ret;
+
+ mutex_lock(&data->vcnl4000_lock);
+
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+ if (ret < 0)
+ goto out;
+
+ if (en)
+ ret &= ~VCNL4040_PS_CONF1_PS_SHUTDOWN;
+ else
+ ret |= VCNL4040_PS_CONF1_PS_SHUTDOWN;
+
+ ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, ret);
+
+out:
+ mutex_unlock(&data->vcnl4000_lock);
+
+ return ret;
+}
+
static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
{
- u16 val = on ? 0 /* power on */ : 1 /* shut down */;
int ret;
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, val);
+ ret = vcnl4000_write_als_enable(data, on);
if (ret < 0)
return ret;
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val);
+ ret = vcnl4000_write_ps_enable(data, on);
if (ret < 0)
return ret;
@@ -422,6 +483,57 @@ static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
return ret;
}
+static int vcnl4040_read_ps_it(struct vcnl4000_data *data, int *val, int *val2)
+{
+ int ret;
+
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+ if (ret < 0)
+ return ret;
+
+ ret = FIELD_GET(VCNL4040_PS_CONF2_PS_IT, ret);
+
+ if (ret >= ARRAY_SIZE(vcnl4040_ps_it_times))
+ return -EINVAL;
+
+ *val = vcnl4040_ps_it_times[ret][0];
+ *val2 = vcnl4040_ps_it_times[ret][1];
+
+ return 0;
+}
+
+static ssize_t vcnl4040_write_ps_it(struct vcnl4000_data *data, int val)
+{
+ unsigned int i;
+ int ret, index = -1;
+ u16 regval;
+
+ for (i = 0; i < ARRAY_SIZE(vcnl4040_ps_it_times); i++) {
+ if (val == vcnl4040_ps_it_times[i][1]) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index < 0)
+ return -EINVAL;
+
+ mutex_lock(&data->vcnl4000_lock);
+
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+ if (ret < 0)
+ goto out;
+
+ regval = (ret & ~VCNL4040_PS_CONF2_PS_IT) |
+ FIELD_PREP(VCNL4040_PS_CONF2_PS_IT, index);
+ ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
+ regval);
+
+out:
+ mutex_unlock(&data->vcnl4000_lock);
+ return ret;
+}
+
static int vcnl4000_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -458,6 +570,47 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
*val = 0;
*val2 = data->al_scale;
return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_INT_TIME:
+ if (chan->type != IIO_PROXIMITY)
+ return -EINVAL;
+ ret = vcnl4040_read_ps_it(data, val, val2);
+ if (ret < 0)
+ return ret;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vcnl4040_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct vcnl4000_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ if (val != 0)
+ return -EINVAL;
+ if (chan->type != IIO_PROXIMITY)
+ return -EINVAL;
+ return vcnl4040_write_ps_it(data, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vcnl4040_read_avail(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:
+ *vals = (int *)vcnl4040_ps_it_times;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *length = 2 * ARRAY_SIZE(vcnl4040_ps_it_times);
+ return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
@@ -796,6 +949,20 @@ static const struct iio_chan_spec vcnl4010_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(1),
};
+static const struct iio_chan_spec vcnl4040_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ }, {
+ .type = IIO_PROXIMITY,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME),
+ .ext_info = vcnl4000_ext_info,
+ }
+};
+
static const struct iio_info vcnl4000_info = {
.read_raw = vcnl4000_read_raw,
};
@@ -810,6 +977,12 @@ static const struct iio_info vcnl4010_info = {
.write_event_config = vcnl4010_write_event_config,
};
+static const struct iio_info vcnl4040_info = {
+ .read_raw = vcnl4000_read_raw,
+ .write_raw = vcnl4040_write_raw,
+ .read_avail = vcnl4040_read_avail,
+};
+
static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
[VCNL4000] = {
.prod = "VCNL4000",
@@ -839,9 +1012,9 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.measure_light = vcnl4200_measure_light,
.measure_proximity = vcnl4200_measure_proximity,
.set_power_state = vcnl4200_set_power_state,
- .channels = vcnl4000_channels,
- .num_channels = ARRAY_SIZE(vcnl4000_channels),
- .info = &vcnl4000_info,
+ .channels = vcnl4040_channels,
+ .num_channels = ARRAY_SIZE(vcnl4040_channels),
+ .info = &vcnl4040_info,
.irq_support = false,
},
[VCNL4200] = {
@@ -1007,9 +1180,9 @@ static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)
return devm_iio_trigger_register(&client->dev, trigger);
}
-static int vcnl4000_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int vcnl4000_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct vcnl4000_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -1153,7 +1326,7 @@ static struct i2c_driver vcnl4000_driver = {
.pm = pm_ptr(&vcnl4000_pm_ops),
.of_match_table = vcnl_4000_of_match,
},
- .probe = vcnl4000_probe,
+ .probe_new = vcnl4000_probe,
.id_table = vcnl4000_id,
.remove = vcnl4000_remove,
};
diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c
index 3ed37f6057fb..84148b944000 100644
--- a/drivers/iio/light/vcnl4035.c
+++ b/drivers/iio/light/vcnl4035.c
@@ -539,8 +539,7 @@ static int vcnl4035_probe_trigger(struct iio_dev *indio_dev)
return ret;
}
-static int vcnl4035_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int vcnl4035_probe(struct i2c_client *client)
{
struct vcnl4035_data *data;
struct iio_dev *indio_dev;
@@ -668,7 +667,7 @@ static struct i2c_driver vcnl4035_driver = {
.pm = pm_ptr(&vcnl4035_pm_ops),
.of_match_table = vcnl4035_of_match,
},
- .probe = vcnl4035_probe,
+ .probe_new = vcnl4035_probe,
.remove = vcnl4035_remove,
.id_table = vcnl4035_id,
};
diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c
index 9a7800cdfee2..e7d2d5d177d4 100644
--- a/drivers/iio/light/veml6030.c
+++ b/drivers/iio/light/veml6030.c
@@ -786,8 +786,7 @@ static int veml6030_hw_init(struct iio_dev *indio_dev)
return ret;
}
-static int veml6030_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int veml6030_probe(struct i2c_client *client)
{
int ret;
struct veml6030_data *data;
@@ -893,7 +892,7 @@ static struct i2c_driver veml6030_driver = {
.of_match_table = veml6030_of_match,
.pm = pm_ptr(&veml6030_pm_ops),
},
- .probe = veml6030_probe,
+ .probe_new = 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 cfa4e9e7c803..ee76a68deb24 100644
--- a/drivers/iio/light/veml6070.c
+++ b/drivers/iio/light/veml6070.c
@@ -135,8 +135,7 @@ static const struct iio_info veml6070_info = {
.read_raw = veml6070_read_raw,
};
-static int veml6070_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int veml6070_probe(struct i2c_client *client)
{
struct veml6070_data *data;
struct iio_dev *indio_dev;
@@ -199,7 +198,7 @@ static struct i2c_driver veml6070_driver = {
.driver = {
.name = VEML6070_DRV_NAME,
},
- .probe = veml6070_probe,
+ .probe_new = veml6070_probe,
.remove = veml6070_remove,
.id_table = veml6070_id,
};
diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c
index d47a4f6f4e87..8b56df26c59e 100644
--- a/drivers/iio/light/vl6180.c
+++ b/drivers/iio/light/vl6180.c
@@ -493,8 +493,7 @@ static int vl6180_init(struct vl6180_data *data)
return vl6180_hold(data, false);
}
-static int vl6180_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int vl6180_probe(struct i2c_client *client)
{
struct vl6180_data *data;
struct iio_dev *indio_dev;
@@ -539,7 +538,7 @@ static struct i2c_driver vl6180_driver = {
.name = VL6180_DRV_NAME,
.of_match_table = vl6180_of_match,
},
- .probe = vl6180_probe,
+ .probe_new = vl6180_probe,
.id_table = vl6180_id,
};
diff --git a/drivers/iio/light/zopt2201.c b/drivers/iio/light/zopt2201.c
index e0bc9df9c88b..e3bac8b56380 100644
--- a/drivers/iio/light/zopt2201.c
+++ b/drivers/iio/light/zopt2201.c
@@ -501,8 +501,7 @@ static const struct iio_info zopt2201_info = {
.attrs = &zopt2201_attribute_group,
};
-static int zopt2201_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int zopt2201_probe(struct i2c_client *client)
{
struct zopt2201_data *data;
struct iio_dev *indio_dev;
@@ -555,7 +554,7 @@ static struct i2c_driver zopt2201_driver = {
.driver = {
.name = ZOPT2201_DRV_NAME,
},
- .probe = zopt2201_probe,
+ .probe_new = zopt2201_probe,
.id_table = zopt2201_id,
};
diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c
index 7ec9ab3beb45..45abdcce6bc0 100644
--- a/drivers/iio/magnetometer/ak8974.c
+++ b/drivers/iio/magnetometer/ak8974.c
@@ -814,8 +814,7 @@ static const struct regmap_config ak8974_regmap_config = {
.precious_reg = ak8974_precious_reg,
};
-static int ak8974_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int ak8974_probe(struct i2c_client *i2c)
{
struct iio_dev *indio_dev;
struct ak8974 *ak8974;
@@ -1047,7 +1046,7 @@ static struct i2c_driver ak8974_driver = {
.pm = pm_ptr(&ak8974_dev_pm_ops),
.of_match_table = ak8974_of_match,
},
- .probe = ak8974_probe,
+ .probe_new = ak8974_probe,
.remove = ak8974_remove,
.id_table = ak8974_id,
};
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index caf03a2a98a5..924b481a3034 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -876,9 +876,9 @@ static irqreturn_t ak8975_handle_trigger(int irq, void *p)
return IRQ_HANDLED;
}
-static int ak8975_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ak8975_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ak8975_data *data;
struct iio_dev *indio_dev;
struct gpio_desc *eoc_gpiod;
@@ -1110,7 +1110,7 @@ static struct i2c_driver ak8975_driver = {
.of_match_table = ak8975_of_match,
.acpi_match_table = ak_acpi_match,
},
- .probe = ak8975_probe,
+ .probe_new = 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 570deaa87836..44b8960eea17 100644
--- a/drivers/iio/magnetometer/bmc150_magn_i2c.c
+++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c
@@ -16,9 +16,9 @@
#include "bmc150_magn.h"
-static int bmc150_magn_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bmc150_magn_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct regmap *regmap;
const char *name = NULL;
@@ -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 = bmc150_magn_i2c_probe,
+ .probe_new = 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 18a13dd51296..7ef2b1d56289 100644
--- a/drivers/iio/magnetometer/hmc5843_i2c.c
+++ b/drivers/iio/magnetometer/hmc5843_i2c.c
@@ -52,9 +52,9 @@ static const struct regmap_config hmc5843_i2c_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
-static int hmc5843_i2c_probe(struct i2c_client *cli,
- const struct i2c_device_id *id)
+static int hmc5843_i2c_probe(struct i2c_client *cli)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(cli);
struct regmap *regmap = devm_regmap_init_i2c(cli,
&hmc5843_i2c_regmap_config);
if (IS_ERR(regmap))
@@ -95,7 +95,7 @@ static struct i2c_driver hmc5843_driver = {
.of_match_table = hmc5843_of_match,
},
.id_table = hmc5843_id,
- .probe = hmc5843_i2c_probe,
+ .probe_new = 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 b870ad803862..661176a885ad 100644
--- a/drivers/iio/magnetometer/mag3110.c
+++ b/drivers/iio/magnetometer/mag3110.c
@@ -469,9 +469,9 @@ static const struct iio_info mag3110_info = {
static const unsigned long mag3110_scan_masks[] = {0x7, 0xf, 0};
-static int mag3110_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mag3110_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct mag3110_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -641,7 +641,7 @@ static struct i2c_driver mag3110_driver = {
.of_match_table = mag3110_of_match,
.pm = pm_sleep_ptr(&mag3110_pm_ops),
},
- .probe = mag3110_probe,
+ .probe_new = mag3110_probe,
.remove = mag3110_remove,
.id_table = mag3110_id,
};
diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c
index 186edfcda0b7..756dadbad106 100644
--- a/drivers/iio/magnetometer/mmc35240.c
+++ b/drivers/iio/magnetometer/mmc35240.c
@@ -481,8 +481,7 @@ static const struct regmap_config mmc35240_regmap_config = {
.num_reg_defaults = ARRAY_SIZE(mmc35240_reg_defaults),
};
-static int mmc35240_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mmc35240_probe(struct i2c_client *client)
{
struct mmc35240_data *data;
struct iio_dev *indio_dev;
@@ -576,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 = mmc35240_probe,
+ .probe_new = mmc35240_probe,
.id_table = mmc35240_id,
};
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
index c5d8c303db4e..b4098d3b3813 100644
--- a/drivers/iio/magnetometer/st_magn_i2c.c
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -54,8 +54,7 @@ static const struct of_device_id st_magn_of_match[] = {
};
MODULE_DEVICE_TABLE(of, st_magn_of_match);
-static int st_magn_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int st_magn_i2c_probe(struct i2c_client *client)
{
const struct st_sensor_settings *settings;
struct st_sensor_data *mdata;
@@ -107,7 +106,7 @@ static struct i2c_driver st_magn_driver = {
.name = "st-magn-i2c",
.of_match_table = st_magn_of_match,
},
- .probe = st_magn_i2c_probe,
+ .probe_new = st_magn_i2c_probe,
.id_table = st_magn_id_table,
};
module_i2c_driver(st_magn_driver);
diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c
index 801c760feb4d..753717158b07 100644
--- a/drivers/iio/magnetometer/yamaha-yas530.c
+++ b/drivers/iio/magnetometer/yamaha-yas530.c
@@ -1384,9 +1384,9 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
},
};
-static int yas5xx_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int yas5xx_probe(struct i2c_client *i2c)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
struct iio_dev *indio_dev;
struct device *dev = &i2c->dev;
struct yas5xx *yas5xx;
@@ -1605,7 +1605,7 @@ static struct i2c_driver yas5xx_driver = {
.of_match_table = yas5xx_of_match,
.pm = pm_ptr(&yas5xx_dev_pm_ops),
},
- .probe = yas5xx_probe,
+ .probe_new = yas5xx_probe,
.remove = yas5xx_remove,
.id_table = yas5xx_id,
};
diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
index 93558fddfa9b..edd8c69f6d2e 100644
--- a/drivers/iio/multiplexer/iio-mux.c
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -416,11 +416,9 @@ static int mux_probe(struct platform_device *pdev)
}
mux->control = devm_mux_control_get(dev, NULL);
- if (IS_ERR(mux->control)) {
- if (PTR_ERR(mux->control) != -EPROBE_DEFER)
- dev_err(dev, "failed to get control-mux\n");
- return PTR_ERR(mux->control);
- }
+ if (IS_ERR(mux->control))
+ return dev_err_probe(dev, PTR_ERR(mux->control),
+ "failed to get control-mux\n");
i = 0;
for (state = 0; state < all_children; state++) {
diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c
index ed5fc0b50fe9..aa140d632101 100644
--- a/drivers/iio/potentiometer/ad5272.c
+++ b/drivers/iio/potentiometer/ad5272.c
@@ -158,9 +158,9 @@ static int ad5272_reset(struct ad5272_data *data)
return 0;
}
-static int ad5272_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ad5272_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct ad5272_data *data;
@@ -218,7 +218,7 @@ static struct i2c_driver ad5272_driver = {
.name = "ad5272",
.of_match_table = ad5272_dt_ids,
},
- .probe = ad5272_probe,
+ .probe_new = ad5272_probe,
.id_table = ad5272_id,
};
diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c
index 5c212ed7a931..0b5e475807cb 100644
--- a/drivers/iio/potentiometer/ds1803.c
+++ b/drivers/iio/potentiometer/ds1803.c
@@ -202,8 +202,9 @@ static const struct iio_info ds1803_info = {
.read_avail = ds1803_read_avail,
};
-static int ds1803_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int ds1803_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct ds1803_data *data;
struct iio_dev *indio_dev;
@@ -251,7 +252,7 @@ static struct i2c_driver ds1803_driver = {
.name = "ds1803",
.of_match_table = ds1803_dt_ids,
},
- .probe = ds1803_probe,
+ .probe_new = ds1803_probe,
.id_table = ds1803_id,
};
diff --git a/drivers/iio/potentiometer/max5432.c b/drivers/iio/potentiometer/max5432.c
index aed3b6ab82a2..94ef27ef3fb5 100644
--- a/drivers/iio/potentiometer/max5432.c
+++ b/drivers/iio/potentiometer/max5432.c
@@ -85,8 +85,7 @@ static const struct iio_info max5432_info = {
.write_raw = max5432_write_raw,
};
-static int max5432_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max5432_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
@@ -124,7 +123,7 @@ static struct i2c_driver max5432_driver = {
.name = "max5432",
.of_match_table = max5432_dt_ids,
},
- .probe = max5432_probe,
+ .probe_new = max5432_probe,
};
module_i2c_driver(max5432_driver);
diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c
index d996dc367fb7..a3465b413b0c 100644
--- a/drivers/iio/potentiometer/tpl0102.c
+++ b/drivers/iio/potentiometer/tpl0102.c
@@ -120,9 +120,9 @@ static const struct iio_info tpl0102_info = {
.write_raw = tpl0102_write_raw,
};
-static int tpl0102_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tpl0102_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct tpl0102_data *data;
struct iio_dev *indio_dev;
@@ -161,7 +161,7 @@ static struct i2c_driver tpl0102_driver = {
.driver = {
.name = "tpl0102",
},
- .probe = tpl0102_probe,
+ .probe_new = tpl0102_probe,
.id_table = tpl0102_id,
};
diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c
index 5ec7060d31d9..b82f093f1e6a 100644
--- a/drivers/iio/potentiostat/lmp91000.c
+++ b/drivers/iio/potentiostat/lmp91000.c
@@ -292,8 +292,7 @@ static const struct iio_buffer_setup_ops lmp91000_buffer_setup_ops = {
.predisable = lmp91000_buffer_predisable,
};
-static int lmp91000_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lmp91000_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct lmp91000_data *data;
@@ -417,7 +416,7 @@ static struct i2c_driver lmp91000_driver = {
.name = LMP91000_DRV_NAME,
.of_match_table = lmp91000_of_match,
},
- .probe = lmp91000_probe,
+ .probe_new = lmp91000_probe,
.remove = lmp91000_remove,
.id_table = lmp91000_id,
};
diff --git a/drivers/iio/pressure/abp060mg.c b/drivers/iio/pressure/abp060mg.c
index e1c3bdb371ee..c0140779366a 100644
--- a/drivers/iio/pressure/abp060mg.c
+++ b/drivers/iio/pressure/abp060mg.c
@@ -174,9 +174,9 @@ static void abp060mg_init_device(struct iio_dev *indio_dev, unsigned long id)
state->offset -= ABP060MG_NUM_COUNTS >> 1;
}
-static int abp060mg_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int abp060mg_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct abp_state *state;
unsigned long cfg_id = id->driver_data;
@@ -255,7 +255,7 @@ static struct i2c_driver abp060mg_driver = {
.driver = {
.name = "abp060mg",
},
- .probe = abp060mg_probe,
+ .probe_new = 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 0c27211f3ea0..14eab086d24a 100644
--- a/drivers/iio/pressure/bmp280-i2c.c
+++ b/drivers/iio/pressure/bmp280-i2c.c
@@ -5,11 +5,11 @@
#include "bmp280.h"
-static int bmp280_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bmp280_i2c_probe(struct i2c_client *client)
{
struct regmap *regmap;
const struct regmap_config *regmap_config;
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
switch (id->driver_data) {
case BMP180_CHIP_ID:
@@ -65,7 +65,7 @@ static struct i2c_driver bmp280_i2c_driver = {
.of_match_table = bmp280_of_i2c_match,
.pm = pm_ptr(&bmp280_dev_pm_ops),
},
- .probe = bmp280_i2c_probe,
+ .probe_new = 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 f0b0d198c6d4..43650b048d62 100644
--- a/drivers/iio/pressure/dlhl60d.c
+++ b/drivers/iio/pressure/dlhl60d.c
@@ -282,9 +282,9 @@ static irqreturn_t dlh_interrupt(int irq, void *private)
return IRQ_HANDLED;
};
-static int dlh_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int dlh_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct dlh_state *st;
struct iio_dev *indio_dev;
int ret;
@@ -362,7 +362,7 @@ static struct i2c_driver dlh_driver = {
.name = "dlhl60d",
.of_match_table = dlh_of_match,
},
- .probe = dlh_probe,
+ .probe_new = 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 984a3f511a1a..2af275a24ff9 100644
--- a/drivers/iio/pressure/dps310.c
+++ b/drivers/iio/pressure/dps310.c
@@ -827,9 +827,9 @@ static const struct iio_info dps310_info = {
.write_raw = dps310_write_raw,
};
-static int dps310_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int dps310_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct dps310_data *data;
struct iio_dev *iio;
int rc;
@@ -887,7 +887,7 @@ static struct i2c_driver dps310_driver = {
.name = DPS310_DEV_NAME,
.acpi_match_table = dps310_acpi_match,
},
- .probe = dps310_probe,
+ .probe_new = 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 9538118c9648..bd1f71a99cfa 100644
--- a/drivers/iio/pressure/hp03.c
+++ b/drivers/iio/pressure/hp03.c
@@ -208,9 +208,9 @@ static const struct iio_info hp03_info = {
.read_raw = &hp03_read_raw,
};
-static int hp03_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int hp03_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct hp03_priv *priv;
@@ -282,7 +282,7 @@ static struct i2c_driver hp03_driver = {
.name = "hp03",
.of_match_table = hp03_of_match,
},
- .probe = hp03_probe,
+ .probe_new = 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 986b7a59712e..b6d2ff464341 100644
--- a/drivers/iio/pressure/hp206c.c
+++ b/drivers/iio/pressure/hp206c.c
@@ -352,9 +352,9 @@ static const struct iio_info hp206c_info = {
.write_raw = hp206c_write_raw,
};
-static int hp206c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int hp206c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct hp206c_data *data;
int ret;
@@ -409,7 +409,7 @@ MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);
#endif
static struct i2c_driver hp206c_driver = {
- .probe = hp206c_probe,
+ .probe_new = hp206c_probe,
.id_table = hp206c_id,
.driver = {
.name = "hp206c",
diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c
index b62f28585db5..407cf25ea0e3 100644
--- a/drivers/iio/pressure/icp10100.c
+++ b/drivers/iio/pressure/icp10100.c
@@ -530,8 +530,7 @@ static void icp10100_pm_disable(void *data)
pm_runtime_disable(dev);
}
-static int icp10100_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int icp10100_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct icp10100_state *st;
@@ -649,7 +648,7 @@ static struct i2c_driver icp10100_driver = {
.pm = pm_ptr(&icp10100_pm),
.of_match_table = icp10100_of_match,
},
- .probe = icp10100_probe,
+ .probe_new = icp10100_probe,
.id_table = icp10100_id,
};
module_i2c_driver(icp10100_driver);
diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c
index 5bf5b9abe6f1..02ea38c8a3e4 100644
--- a/drivers/iio/pressure/mpl115.c
+++ b/drivers/iio/pressure/mpl115.c
@@ -4,12 +4,13 @@
*
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
*
- * TODO: shutdown pin
+ * TODO: synchronization with system suspend
*/
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include "mpl115.h"
@@ -27,6 +28,7 @@ struct mpl115_data {
s16 a0;
s16 b1, b2;
s16 c12;
+ struct gpio_desc *shutdown;
const struct mpl115_ops *ops;
};
@@ -102,16 +104,24 @@ static int mpl115_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
+ pm_runtime_get_sync(data->dev);
ret = mpl115_comp_pressure(data, val, val2);
if (ret < 0)
return ret;
+ pm_runtime_mark_last_busy(data->dev);
+ pm_runtime_put_autosuspend(data->dev);
+
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_RAW:
+ pm_runtime_get_sync(data->dev);
/* temperature -5.35 C / LSB, 472 LSB is 25 C */
ret = mpl115_read_temp(data);
if (ret < 0)
return ret;
+ pm_runtime_mark_last_busy(data->dev);
+ pm_runtime_put_autosuspend(data->dev);
*val = ret >> 6;
+
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
*val = -605;
@@ -168,6 +178,8 @@ int mpl115_probe(struct device *dev, const char *name,
if (ret)
return ret;
+ dev_set_drvdata(dev, indio_dev);
+
ret = data->ops->read(data->dev, MPL115_A0);
if (ret < 0)
return ret;
@@ -185,10 +197,58 @@ int mpl115_probe(struct device *dev, const char *name,
return ret;
data->c12 = ret;
+ data->shutdown = devm_gpiod_get_optional(dev, "shutdown",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(data->shutdown))
+ return dev_err_probe(dev, PTR_ERR(data->shutdown),
+ "cannot get shutdown gpio\n");
+
+ if (data->shutdown) {
+ /* Enable runtime PM */
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ /*
+ * As the device takes 3 ms to come up with a fresh
+ * reading after power-on and 5 ms to actually power-on,
+ * do not shut it down unnecessarily. Set autosuspend to
+ * 2000 ms.
+ */
+ pm_runtime_set_autosuspend_delay(dev, 2000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_put(dev);
+
+ dev_dbg(dev, "low-power mode enabled");
+ } else
+ dev_dbg(dev, "low-power mode disabled");
+
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(mpl115_probe, IIO_MPL115);
+static int mpl115_runtime_suspend(struct device *dev)
+{
+ struct mpl115_data *data = iio_priv(dev_get_drvdata(dev));
+
+ gpiod_set_value(data->shutdown, 1);
+
+ return 0;
+}
+
+static int mpl115_runtime_resume(struct device *dev)
+{
+ struct mpl115_data *data = iio_priv(dev_get_drvdata(dev));
+
+ gpiod_set_value(data->shutdown, 0);
+ usleep_range(5000, 6000);
+
+ return 0;
+}
+
+EXPORT_NS_RUNTIME_DEV_PM_OPS(mpl115_dev_pm_ops, mpl115_runtime_suspend,
+ mpl115_runtime_resume, NULL, IIO_MPL115);
+
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/pressure/mpl115.h b/drivers/iio/pressure/mpl115.h
index 57d55eb8e661..78a0068a17bb 100644
--- a/drivers/iio/pressure/mpl115.h
+++ b/drivers/iio/pressure/mpl115.h
@@ -6,6 +6,8 @@
* Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com>
*/
+#include <linux/pm_runtime.h>
+
#ifndef _MPL115_H_
#define _MPL115_H_
@@ -18,4 +20,7 @@ struct mpl115_ops {
int mpl115_probe(struct device *dev, const char *name,
const struct mpl115_ops *ops);
+/*PM ops */
+extern const struct dev_pm_ops mpl115_dev_pm_ops;
+
#endif
diff --git a/drivers/iio/pressure/mpl115_i2c.c b/drivers/iio/pressure/mpl115_i2c.c
index 099ab1c6832c..ade4dd854ddf 100644
--- a/drivers/iio/pressure/mpl115_i2c.c
+++ b/drivers/iio/pressure/mpl115_i2c.c
@@ -35,9 +35,9 @@ static const struct mpl115_ops mpl115_i2c_ops = {
.write = mpl115_i2c_write,
};
-static int mpl115_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mpl115_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
@@ -53,8 +53,9 @@ MODULE_DEVICE_TABLE(i2c, mpl115_i2c_id);
static struct i2c_driver mpl115_i2c_driver = {
.driver = {
.name = "mpl115",
+ .pm = pm_ptr(&mpl115_dev_pm_ops),
},
- .probe = mpl115_i2c_probe,
+ .probe_new = mpl115_i2c_probe,
.id_table = mpl115_i2c_id,
};
module_i2c_driver(mpl115_i2c_driver);
diff --git a/drivers/iio/pressure/mpl115_spi.c b/drivers/iio/pressure/mpl115_spi.c
index 7feec87e2704..58d218fd90dc 100644
--- a/drivers/iio/pressure/mpl115_spi.c
+++ b/drivers/iio/pressure/mpl115_spi.c
@@ -92,6 +92,7 @@ MODULE_DEVICE_TABLE(spi, mpl115_spi_ids);
static struct spi_driver mpl115_spi_driver = {
.driver = {
.name = "mpl115",
+ .pm = pm_ptr(&mpl115_dev_pm_ops),
},
.probe = mpl115_spi_probe,
.id_table = mpl115_spi_ids,
diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c
index 2f22aba61e4d..72e811a5c96e 100644
--- a/drivers/iio/pressure/mpl3115.c
+++ b/drivers/iio/pressure/mpl3115.c
@@ -230,9 +230,9 @@ static const struct iio_info mpl3115_info = {
.read_raw = &mpl3115_read_raw,
};
-static int mpl3115_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mpl3115_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct mpl3115_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -335,7 +335,7 @@ static struct i2c_driver mpl3115_driver = {
.of_match_table = mpl3115_of_match,
.pm = pm_sleep_ptr(&mpl3115_pm_ops),
},
- .probe = mpl3115_probe,
+ .probe_new = mpl3115_probe,
.remove = mpl3115_remove,
.id_table = mpl3115_id,
};
diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c
index b681a4183909..caf882497656 100644
--- a/drivers/iio/pressure/ms5611_i2c.c
+++ b/drivers/iio/pressure/ms5611_i2c.c
@@ -79,9 +79,9 @@ static int ms5611_i2c_read_adc_temp_and_pressure(struct ms5611_state *st,
return ms5611_i2c_read_adc(st, pressure);
}
-static int ms5611_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ms5611_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ms5611_state *st;
struct iio_dev *indio_dev;
@@ -130,7 +130,7 @@ static struct i2c_driver ms5611_driver = {
.of_match_table = ms5611_i2c_matches,
},
.id_table = ms5611_id,
- .probe = ms5611_i2c_probe,
+ .probe_new = ms5611_i2c_probe,
.remove = ms5611_i2c_remove,
};
module_i2c_driver(ms5611_driver);
diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
index 70c70019142a..c4981b29dccb 100644
--- a/drivers/iio/pressure/ms5637.c
+++ b/drivers/iio/pressure/ms5637.c
@@ -142,9 +142,9 @@ static const struct iio_info ms5637_info = {
.attrs = &ms5637_attribute_group,
};
-static int ms5637_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ms5637_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct ms_tp_data *data;
struct ms_tp_dev *dev_data;
struct iio_dev *indio_dev;
@@ -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 = ms5637_probe,
+ .probe_new = 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 58fede861891..f2c3bb568d16 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -76,8 +76,7 @@ static const struct i2c_device_id st_press_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, st_press_id_table);
-static int st_press_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int st_press_i2c_probe(struct i2c_client *client)
{
const struct st_sensor_settings *settings;
struct st_sensor_data *press_data;
@@ -117,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 = st_press_i2c_probe,
+ .probe_new = 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 685fcf65334f..2fbf14aff033 100644
--- a/drivers/iio/pressure/t5403.c
+++ b/drivers/iio/pressure/t5403.c
@@ -208,9 +208,9 @@ static const struct iio_info t5403_info = {
.attrs = &t5403_attribute_group,
};
-static int t5403_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int t5403_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct t5403_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -260,7 +260,7 @@ static struct i2c_driver t5403_driver = {
.driver = {
.name = "t5403",
},
- .probe = t5403_probe,
+ .probe_new = 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 f26dd8cbb387..ade465014be1 100644
--- a/drivers/iio/pressure/zpa2326_i2c.c
+++ b/drivers/iio/pressure/zpa2326_i2c.c
@@ -38,9 +38,9 @@ static unsigned int zpa2326_i2c_hwid(const struct i2c_client *client)
(ZPA2326_SA0(client->addr) << ZPA2326_DEVICE_ID_SA0_SHIFT));
}
-static int zpa2326_probe_i2c(struct i2c_client *client,
- const struct i2c_device_id *i2c_id)
+static int zpa2326_probe_i2c(struct i2c_client *client)
{
+ const struct i2c_device_id *i2c_id = i2c_client_get_device_id(client);
struct regmap *regmap;
regmap = devm_regmap_init_i2c(client, &zpa2326_regmap_i2c_config);
@@ -76,7 +76,7 @@ static struct i2c_driver zpa2326_i2c_driver = {
.of_match_table = zpa2326_i2c_matches,
.pm = ZPA2326_PM_OPS,
},
- .probe = zpa2326_probe_i2c,
+ .probe_new = 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 5b6ea783795d..7b8f40b7ccf3 100644
--- a/drivers/iio/proximity/isl29501.c
+++ b/drivers/iio/proximity/isl29501.c
@@ -949,8 +949,7 @@ static irqreturn_t isl29501_trigger_handler(int irq, void *p)
return IRQ_HANDLED;
}
-static int isl29501_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int isl29501_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct isl29501_private *isl29501;
@@ -1009,7 +1008,7 @@ static struct i2c_driver isl29501_driver = {
.name = "isl29501",
},
.id_table = isl29501_id,
- .probe = isl29501_probe,
+ .probe_new = isl29501_probe,
};
module_i2c_driver(isl29501_driver);
diff --git a/drivers/iio/proximity/mb1232.c b/drivers/iio/proximity/mb1232.c
index 0bca5f74de68..e70cac8240af 100644
--- a/drivers/iio/proximity/mb1232.c
+++ b/drivers/iio/proximity/mb1232.c
@@ -180,9 +180,9 @@ static const struct iio_info mb1232_info = {
.read_raw = mb1232_read_raw,
};
-static int mb1232_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mb1232_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct mb1232_data *data;
int ret;
@@ -264,7 +264,7 @@ static struct i2c_driver mb1232_driver = {
.name = "maxbotix-mb1232",
.of_match_table = of_mb1232_match,
},
- .probe = mb1232_probe,
+ .probe_new = 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 791a33d5286c..c9eead01a031 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -253,8 +253,7 @@ static const struct iio_info lidar_info = {
.read_raw = lidar_read_raw,
};
-static int lidar_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lidar_probe(struct i2c_client *client)
{
struct lidar_data *data;
struct iio_dev *indio_dev;
@@ -366,7 +365,7 @@ static struct i2c_driver lidar_driver = {
.of_match_table = lidar_dt_ids,
.pm = pm_ptr(&lidar_pm_ops),
},
- .probe = lidar_probe,
+ .probe_new = lidar_probe,
.remove = lidar_remove,
.id_table = lidar_id,
};
diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c
index cb80b3c9d073..44f72b78bd50 100644
--- a/drivers/iio/proximity/rfd77402.c
+++ b/drivers/iio/proximity/rfd77402.c
@@ -257,8 +257,7 @@ static void rfd77402_disable(void *client)
rfd77402_powerdown(client);
}
-static int rfd77402_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int rfd77402_probe(struct i2c_client *client)
{
struct rfd77402_data *data;
struct iio_dev *indio_dev;
@@ -319,7 +318,7 @@ static struct i2c_driver rfd77402_driver = {
.name = RFD77402_DRV_NAME,
.pm = pm_sleep_ptr(&rfd77402_pm_ops),
},
- .probe = rfd77402_probe,
+ .probe_new = rfd77402_probe,
.id_table = rfd77402_id,
};
diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c
index 7ed11339c31e..61866d0440f7 100644
--- a/drivers/iio/proximity/srf08.c
+++ b/drivers/iio/proximity/srf08.c
@@ -443,9 +443,9 @@ static const struct iio_info srf02_info = {
.read_raw = srf08_read_raw,
};
-static int srf08_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int srf08_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct srf08_data *data;
int ret;
@@ -549,7 +549,7 @@ static struct i2c_driver srf08_driver = {
.name = "srf08",
.of_match_table = of_srf08_match,
},
- .probe = srf08_probe,
+ .probe_new = srf08_probe,
.id_table = srf08_id,
};
module_i2c_driver(srf08_driver);
diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c
index 7fa2213d23ba..6e19d22e6a01 100644
--- a/drivers/iio/proximity/sx9360.c
+++ b/drivers/iio/proximity/sx9360.c
@@ -865,6 +865,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(sx9360_pm_ops, sx9360_suspend, sx9360_resume);
static const struct acpi_device_id sx9360_acpi_match[] = {
{ "STH9360", SX9360_WHOAMI_VALUE },
+ { "SAMM0208", SX9360_WHOAMI_VALUE },
{ }
};
MODULE_DEVICE_TABLE(acpi, sx9360_acpi_match);
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index d4670864ddc7..8794e75e5bf9 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -901,8 +901,7 @@ static void sx9500_gpio_probe(struct i2c_client *client,
}
}
-static int sx9500_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int sx9500_probe(struct i2c_client *client)
{
int ret;
struct iio_dev *indio_dev;
@@ -1056,7 +1055,7 @@ static struct i2c_driver sx9500_driver = {
.of_match_table = of_match_ptr(sx9500_of_match),
.pm = pm_sleep_ptr(&sx9500_pm_ops),
},
- .probe = sx9500_probe,
+ .probe_new = sx9500_probe,
.remove = sx9500_remove,
.id_table = sx9500_id,
};
diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c
index d70a6b4f0bf8..eba9256730ec 100644
--- a/drivers/iio/proximity/sx_common.c
+++ b/drivers/iio/proximity/sx_common.c
@@ -424,13 +424,6 @@ static const struct iio_buffer_setup_ops sx_common_buffer_setup_ops = {
.postdisable = sx_common_buffer_postdisable,
};
-static void sx_common_regulator_disable(void *_data)
-{
- struct sx_common_data *data = _data;
-
- regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
-}
-
#define SX_COMMON_SOFT_RESET 0xde
static int sx_common_init_device(struct device *dev, struct iio_dev *indio_dev)
@@ -474,6 +467,7 @@ int sx_common_probe(struct i2c_client *client,
const struct sx_common_chip_info *chip_info,
const struct regmap_config *regmap_config)
{
+ static const char * const regulator_names[] = { "vdd", "svdd" };
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct sx_common_data *data;
@@ -487,8 +481,6 @@ int sx_common_probe(struct i2c_client *client,
data->chip_info = chip_info;
data->client = client;
- data->supplies[0].supply = "vdd";
- data->supplies[1].supply = "svdd";
mutex_init(&data->mutex);
init_completion(&data->completion);
@@ -497,23 +489,14 @@ int sx_common_probe(struct i2c_client *client,
return dev_err_probe(dev, PTR_ERR(data->regmap),
"Could init register map\n");
- ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
- data->supplies);
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
+ regulator_names);
if (ret)
return dev_err_probe(dev, ret, "Unable to get regulators\n");
- ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
- if (ret)
- return dev_err_probe(dev, ret, "Unable to enable regulators\n");
-
/* Must wait for Tpor time after initial power up */
usleep_range(1000, 1100);
- ret = devm_add_action_or_reset(dev, sx_common_regulator_disable, data);
- if (ret)
- return dev_err_probe(dev, ret,
- "Unable to register regulators deleter\n");
-
ret = data->chip_info->ops.check_whoami(dev, indio_dev);
if (ret)
return dev_err_probe(dev, ret, "error reading WHOAMI\n");
diff --git a/drivers/iio/proximity/sx_common.h b/drivers/iio/proximity/sx_common.h
index 5d3edeb75f4e..49d4517103b0 100644
--- a/drivers/iio/proximity/sx_common.h
+++ b/drivers/iio/proximity/sx_common.h
@@ -102,7 +102,6 @@ struct sx_common_chip_info {
* @trig: IIO trigger object.
* @regmap: Register map.
* @num_default_regs: Number of default registers to set at init.
- * @supplies: Power supplies object.
* @chan_prox_stat: Last reading of the proximity status for each channel.
* We only send an event to user space when this changes.
* @trigger_enabled: True when the device trigger is enabled.
@@ -120,7 +119,6 @@ struct sx_common_data {
struct iio_trigger *trig;
struct regmap *regmap;
- struct regulator_bulk_data supplies[2];
unsigned long chan_prox_stat;
bool trigger_enabled;
diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
index e8ed849e3b76..ed384f33e0c7 100644
--- a/drivers/iio/temperature/Kconfig
+++ b/drivers/iio/temperature/Kconfig
@@ -128,6 +128,16 @@ config TSYS02D
This driver can also be built as a module. If so, the module will
be called tsys02d.
+config MAX30208
+ tristate "Maxim MAX30208 digital temperature sensor"
+ depends on I2C
+ help
+ If you say yes here you get support for Maxim MAX30208
+ digital temperature sensor connected via I2C.
+
+ This driver can also be built as a module. If so, the module
+ will be called max30208.
+
config MAX31856
tristate "MAX31856 thermocouple sensor"
depends on SPI
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index dd08e562ffe0..dfec8c6d3019 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_IQS620AT_TEMP) += iqs620at-temp.o
obj-$(CONFIG_LTC2983) += ltc2983.o
obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o
obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
+obj-$(CONFIG_MAX30208) += max30208.o
obj-$(CONFIG_MAX31856) += max31856.o
obj-$(CONFIG_MAX31865) += max31865.o
obj-$(CONFIG_MLX90614) += mlx90614.o
diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
index a60ccf183687..fcb96c44d954 100644
--- a/drivers/iio/temperature/ltc2983.c
+++ b/drivers/iio/temperature/ltc2983.c
@@ -25,9 +25,12 @@
#define LTC2983_STATUS_REG 0x0000
#define LTC2983_TEMP_RES_START_REG 0x0010
#define LTC2983_TEMP_RES_END_REG 0x005F
+#define LTC2983_EEPROM_KEY_REG 0x00B0
+#define LTC2983_EEPROM_READ_STATUS_REG 0x00D0
#define LTC2983_GLOBAL_CONFIG_REG 0x00F0
#define LTC2983_MULT_CHANNEL_START_REG 0x00F4
#define LTC2983_MULT_CHANNEL_END_REG 0x00F7
+#define LTC2986_EEPROM_STATUS_REG 0x00F9
#define LTC2983_MUX_CONFIG_REG 0x00FF
#define LTC2983_CHAN_ASSIGN_START_REG 0x0200
#define LTC2983_CHAN_ASSIGN_END_REG 0x024F
@@ -35,13 +38,21 @@
#define LTC2983_CUST_SENS_TBL_END_REG 0x03CF
#define LTC2983_DIFFERENTIAL_CHAN_MIN 2
-#define LTC2983_MAX_CHANNELS_NR 20
#define LTC2983_MIN_CHANNELS_NR 1
#define LTC2983_SLEEP 0x97
#define LTC2983_CUSTOM_STEINHART_SIZE 24
#define LTC2983_CUSTOM_SENSOR_ENTRY_SZ 6
#define LTC2983_CUSTOM_STEINHART_ENTRY_SZ 4
+#define LTC2983_EEPROM_KEY 0xA53C0F5A
+#define LTC2983_EEPROM_WRITE_CMD 0x15
+#define LTC2983_EEPROM_READ_CMD 0x16
+#define LTC2983_EEPROM_STATUS_FAILURE_MASK GENMASK(3, 1)
+#define LTC2983_EEPROM_READ_FAILURE_MASK GENMASK(7, 0)
+
+#define LTC2983_EEPROM_WRITE_TIME_MS 2600
+#define LTC2983_EEPROM_READ_TIME_MS 20
+
#define LTC2983_CHAN_START_ADDR(chan) \
(((chan - 1) * 4) + LTC2983_CHAN_ASSIGN_START_REG)
#define LTC2983_CHAN_RES_ADDR(chan) \
@@ -171,6 +182,7 @@ enum {
LTC2983_SENSOR_DIODE = 28,
LTC2983_SENSOR_SENSE_RESISTOR = 29,
LTC2983_SENSOR_DIRECT_ADC = 30,
+ LTC2983_SENSOR_ACTIVE_TEMP = 31,
};
#define to_thermocouple(_sensor) \
@@ -191,7 +203,17 @@ enum {
#define to_adc(_sensor) \
container_of(_sensor, struct ltc2983_adc, sensor)
+#define to_temp(_sensor) \
+ container_of(_sensor, struct ltc2983_temp, sensor)
+
+struct ltc2983_chip_info {
+ unsigned int max_channels_nr;
+ bool has_temp;
+ bool has_eeprom;
+};
+
struct ltc2983_data {
+ const struct ltc2983_chip_info *info;
struct regmap *regmap;
struct spi_device *spi;
struct mutex lock;
@@ -209,6 +231,8 @@ struct ltc2983_data {
* Holds the converted temperature
*/
__be32 temp __aligned(IIO_DMA_MINALIGN);
+ __be32 chan_val;
+ __be32 eeprom_key;
};
struct ltc2983_sensor {
@@ -271,6 +295,12 @@ struct ltc2983_adc {
bool single_ended;
};
+struct ltc2983_temp {
+ struct ltc2983_sensor sensor;
+ struct ltc2983_custom_sensor *custom;
+ bool single_ended;
+};
+
/*
* Convert to Q format numbers. These number's are integers where
* the number of integer and fractional bits are specified. The resolution
@@ -313,19 +343,18 @@ static int __ltc2983_fault_handler(const struct ltc2983_data *st,
return 0;
}
-static int __ltc2983_chan_assign_common(const struct ltc2983_data *st,
+static int __ltc2983_chan_assign_common(struct ltc2983_data *st,
const struct ltc2983_sensor *sensor,
u32 chan_val)
{
u32 reg = LTC2983_CHAN_START_ADDR(sensor->chan);
- __be32 __chan_val;
chan_val |= LTC2983_CHAN_TYPE(sensor->type);
dev_dbg(&st->spi->dev, "Assign reg:0x%04X, val:0x%08X\n", reg,
chan_val);
- __chan_val = cpu_to_be32(chan_val);
- return regmap_bulk_write(st->regmap, reg, &__chan_val,
- sizeof(__chan_val));
+ st->chan_val = cpu_to_be32(chan_val);
+ return regmap_bulk_write(st->regmap, reg, &st->chan_val,
+ sizeof(st->chan_val));
}
static int __ltc2983_chan_custom_sensor_assign(struct ltc2983_data *st,
@@ -606,6 +635,22 @@ static int ltc2983_adc_assign_chan(struct ltc2983_data *st,
return __ltc2983_chan_assign_common(st, sensor, chan_val);
}
+static int ltc2983_temp_assign_chan(struct ltc2983_data *st,
+ const struct ltc2983_sensor *sensor)
+{
+ struct ltc2983_temp *temp = to_temp(sensor);
+ u32 chan_val;
+ int ret;
+
+ chan_val = LTC2983_ADC_SINGLE_ENDED(temp->single_ended);
+
+ ret = __ltc2983_chan_custom_sensor_assign(st, temp->custom, &chan_val);
+ if (ret)
+ return ret;
+
+ return __ltc2983_chan_assign_common(st, sensor, chan_val);
+}
+
static struct ltc2983_sensor *
ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data *st,
const struct ltc2983_sensor *sensor)
@@ -771,10 +816,10 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
if (rtd->sensor_config & LTC2983_RTD_4_WIRE_MASK) {
/* 4-wire */
u8 min = LTC2983_DIFFERENTIAL_CHAN_MIN,
- max = LTC2983_MAX_CHANNELS_NR;
+ max = st->info->max_channels_nr;
if (rtd->sensor_config & LTC2983_RTD_ROTATION_MASK)
- max = LTC2983_MAX_CHANNELS_NR - 1;
+ max = st->info->max_channels_nr - 1;
if (((rtd->sensor_config & LTC2983_RTD_KELVIN_R_SENSE_MASK)
== LTC2983_RTD_KELVIN_R_SENSE_MASK) &&
@@ -1143,6 +1188,38 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child,
return &adc->sensor;
}
+static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child,
+ struct ltc2983_data *st,
+ const struct ltc2983_sensor *sensor)
+{
+ struct ltc2983_temp *temp;
+
+ temp = devm_kzalloc(&st->spi->dev, sizeof(*temp), GFP_KERNEL);
+ if (!temp)
+ return ERR_PTR(-ENOMEM);
+
+ if (fwnode_property_read_bool(child, "adi,single-ended"))
+ temp->single_ended = true;
+
+ if (!temp->single_ended &&
+ sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) {
+ dev_err(&st->spi->dev, "Invalid chan:%d for differential temp\n",
+ sensor->chan);
+ return ERR_PTR(-EINVAL);
+ }
+
+ temp->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-temp",
+ false, 4096, true);
+ if (IS_ERR(temp->custom))
+ return ERR_CAST(temp->custom);
+
+ /* set common parameters */
+ temp->sensor.assign_chan = ltc2983_temp_assign_chan;
+ temp->sensor.fault_handler = ltc2983_common_fault_handler;
+
+ return &temp->sensor;
+}
+
static int ltc2983_chan_read(struct ltc2983_data *st,
const struct ltc2983_sensor *sensor, int *val)
{
@@ -1302,10 +1379,10 @@ static int ltc2983_parse_dt(struct ltc2983_data *st)
/* check if we have a valid channel */
if (sensor.chan < LTC2983_MIN_CHANNELS_NR ||
- sensor.chan > LTC2983_MAX_CHANNELS_NR) {
+ sensor.chan > st->info->max_channels_nr) {
ret = -EINVAL;
dev_err(dev, "chan:%d must be from %u to %u\n", sensor.chan,
- LTC2983_MIN_CHANNELS_NR, LTC2983_MAX_CHANNELS_NR);
+ LTC2983_MIN_CHANNELS_NR, st->info->max_channels_nr);
goto put_child;
} else if (channel_avail_mask & BIT(sensor.chan)) {
ret = -EINVAL;
@@ -1345,6 +1422,9 @@ static int ltc2983_parse_dt(struct ltc2983_data *st)
st->iio_channels--;
} else if (sensor.type == LTC2983_SENSOR_DIRECT_ADC) {
st->sensors[chan] = ltc2983_adc_new(child, st, &sensor);
+ } else if (st->info->has_temp &&
+ sensor.type == LTC2983_SENSOR_ACTIVE_TEMP) {
+ st->sensors[chan] = ltc2983_temp_new(child, st, &sensor);
} else {
dev_err(dev, "Unknown sensor type %d\n", sensor.type);
ret = -EINVAL;
@@ -1371,6 +1451,45 @@ put_child:
return ret;
}
+static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd,
+ unsigned int wait_time, unsigned int status_reg,
+ unsigned long status_fail_mask)
+{
+ unsigned long time;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_bulk_write(st->regmap, LTC2983_EEPROM_KEY_REG,
+ &st->eeprom_key, sizeof(st->eeprom_key));
+ if (ret)
+ return ret;
+
+ reinit_completion(&st->completion);
+
+ ret = regmap_write(st->regmap, LTC2983_STATUS_REG,
+ LTC2983_STATUS_START(true) | cmd);
+ if (ret)
+ return ret;
+
+ time = wait_for_completion_timeout(&st->completion,
+ msecs_to_jiffies(wait_time));
+ if (!time) {
+ dev_err(&st->spi->dev, "EEPROM command timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ ret = regmap_read(st->regmap, status_reg, &val);
+ if (ret)
+ return ret;
+
+ if (val & status_fail_mask) {
+ dev_err(&st->spi->dev, "EEPROM command failed: 0x%02X\n", val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio)
{
u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0, status;
@@ -1396,6 +1515,15 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio)
if (ret)
return ret;
+ if (st->info->has_eeprom && !assign_iio) {
+ ret = ltc2983_eeprom_cmd(st, LTC2983_EEPROM_READ_CMD,
+ LTC2983_EEPROM_READ_TIME_MS,
+ LTC2983_EEPROM_READ_STATUS_REG,
+ LTC2983_EEPROM_READ_FAILURE_MASK);
+ if (!ret)
+ return 0;
+ }
+
for (chan = 0; chan < st->num_channels; chan++) {
u32 chan_type = 0, *iio_chan;
@@ -1435,9 +1563,13 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio)
static const struct regmap_range ltc2983_reg_ranges[] = {
regmap_reg_range(LTC2983_STATUS_REG, LTC2983_STATUS_REG),
regmap_reg_range(LTC2983_TEMP_RES_START_REG, LTC2983_TEMP_RES_END_REG),
+ regmap_reg_range(LTC2983_EEPROM_KEY_REG, LTC2983_EEPROM_KEY_REG),
+ regmap_reg_range(LTC2983_EEPROM_READ_STATUS_REG,
+ LTC2983_EEPROM_READ_STATUS_REG),
regmap_reg_range(LTC2983_GLOBAL_CONFIG_REG, LTC2983_GLOBAL_CONFIG_REG),
regmap_reg_range(LTC2983_MULT_CHANNEL_START_REG,
LTC2983_MULT_CHANNEL_END_REG),
+ regmap_reg_range(LTC2986_EEPROM_STATUS_REG, LTC2986_EEPROM_STATUS_REG),
regmap_reg_range(LTC2983_MUX_CONFIG_REG, LTC2983_MUX_CONFIG_REG),
regmap_reg_range(LTC2983_CHAN_ASSIGN_START_REG,
LTC2983_CHAN_ASSIGN_END_REG),
@@ -1482,6 +1614,12 @@ static int ltc2983_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
+ st->info = device_get_match_data(&spi->dev);
+ if (!st->info)
+ st->info = (void *)spi_get_device_id(spi)->driver_data;
+ if (!st->info)
+ return -ENODEV;
+
st->regmap = devm_regmap_init_spi(spi, &ltc2983_regmap_config);
if (IS_ERR(st->regmap)) {
dev_err(&spi->dev, "Failed to initialize regmap\n");
@@ -1491,6 +1629,7 @@ static int ltc2983_probe(struct spi_device *spi)
mutex_init(&st->lock);
init_completion(&st->completion);
st->spi = spi;
+ st->eeprom_key = cpu_to_be32(LTC2983_EEPROM_KEY);
spi_set_drvdata(spi, st);
ret = ltc2983_parse_dt(st);
@@ -1524,6 +1663,15 @@ static int ltc2983_probe(struct spi_device *spi)
return ret;
}
+ if (st->info->has_eeprom) {
+ ret = ltc2983_eeprom_cmd(st, LTC2983_EEPROM_WRITE_CMD,
+ LTC2983_EEPROM_WRITE_TIME_MS,
+ LTC2986_EEPROM_STATUS_REG,
+ LTC2983_EEPROM_STATUS_FAILURE_MASK);
+ if (ret)
+ return ret;
+ }
+
indio_dev->name = name;
indio_dev->num_channels = st->iio_channels;
indio_dev->channels = st->iio_chan;
@@ -1554,14 +1702,35 @@ static int ltc2983_suspend(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(ltc2983_pm_ops, ltc2983_suspend,
ltc2983_resume);
+static const struct ltc2983_chip_info ltc2983_chip_info_data = {
+ .max_channels_nr = 20,
+};
+
+static const struct ltc2983_chip_info ltc2984_chip_info_data = {
+ .max_channels_nr = 20,
+ .has_eeprom = true,
+};
+
+static const struct ltc2983_chip_info ltc2986_chip_info_data = {
+ .max_channels_nr = 10,
+ .has_temp = true,
+ .has_eeprom = true,
+};
+
static const struct spi_device_id ltc2983_id_table[] = {
- { "ltc2983" },
+ { "ltc2983", (kernel_ulong_t)&ltc2983_chip_info_data },
+ { "ltc2984", (kernel_ulong_t)&ltc2984_chip_info_data },
+ { "ltc2986", (kernel_ulong_t)&ltc2986_chip_info_data },
+ { "ltm2985", (kernel_ulong_t)&ltc2986_chip_info_data },
{},
};
MODULE_DEVICE_TABLE(spi, ltc2983_id_table);
static const struct of_device_id ltc2983_of_match[] = {
- { .compatible = "adi,ltc2983" },
+ { .compatible = "adi,ltc2983", .data = &ltc2983_chip_info_data },
+ { .compatible = "adi,ltc2984", .data = &ltc2984_chip_info_data },
+ { .compatible = "adi,ltc2986", .data = &ltc2986_chip_info_data },
+ { .compatible = "adi,ltm2985", .data = &ltc2986_chip_info_data },
{},
};
MODULE_DEVICE_TABLE(of, ltc2983_of_match);
diff --git a/drivers/iio/temperature/max30208.c b/drivers/iio/temperature/max30208.c
new file mode 100644
index 000000000000..c85c21474711
--- /dev/null
+++ b/drivers/iio/temperature/max30208.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (c) Rajat Khandelwal <rajat.khandelwal@linux.intel.com>
+ *
+ * Maxim MAX30208 digital temperature sensor with 0.1°C accuracy
+ * (7-bit I2C slave address (0x50 - 0x53))
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#define MAX30208_STATUS 0x00
+#define MAX30208_STATUS_TEMP_RDY BIT(0)
+#define MAX30208_INT_ENABLE 0x01
+#define MAX30208_INT_ENABLE_TEMP_RDY BIT(0)
+
+#define MAX30208_FIFO_OVF_CNTR 0x06
+#define MAX30208_FIFO_DATA_CNTR 0x07
+#define MAX30208_FIFO_DATA 0x08
+
+#define MAX30208_FIFO_CONFIG 0x0a
+#define MAX30208_FIFO_CONFIG_RO BIT(1)
+
+#define MAX30208_SYSTEM_CTRL 0x0c
+#define MAX30208_SYSTEM_CTRL_RESET 0x01
+
+#define MAX30208_TEMP_SENSOR_SETUP 0x14
+#define MAX30208_TEMP_SENSOR_SETUP_CONV BIT(0)
+
+struct max30208_data {
+ struct i2c_client *client;
+ struct iio_dev *indio_dev;
+ struct mutex lock; /* Lock to prevent concurrent reads of temperature readings */
+};
+
+static const struct iio_chan_spec max30208_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+/**
+ * max30208_request() - Request a reading
+ * @data: Struct comprising member elements of the device
+ *
+ * Requests a reading from the device and waits until the conversion is ready.
+ */
+static int max30208_request(struct max30208_data *data)
+{
+ /*
+ * Sensor can take up to 500 ms to respond so execute a total of
+ * 10 retries to give the device sufficient time.
+ */
+ int retries = 10;
+ u8 regval;
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP);
+ if (ret < 0)
+ return ret;
+
+ regval = ret | MAX30208_TEMP_SENSOR_SETUP_CONV;
+
+ ret = i2c_smbus_write_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP, regval);
+ if (ret)
+ return ret;
+
+ while (retries--) {
+ ret = i2c_smbus_read_byte_data(data->client, MAX30208_STATUS);
+ if (ret < 0)
+ return ret;
+
+ if (ret & MAX30208_STATUS_TEMP_RDY)
+ return 0;
+
+ msleep(50);
+ }
+ dev_err(&data->client->dev, "Temperature conversion failed\n");
+
+ return -ETIMEDOUT;
+}
+
+static int max30208_update_temp(struct max30208_data *data)
+{
+ u8 data_count;
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ ret = max30208_request(data);
+ if (ret)
+ goto unlock;
+
+ ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_OVF_CNTR);
+ if (ret < 0)
+ goto unlock;
+ else if (!ret) {
+ ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_DATA_CNTR);
+ if (ret < 0)
+ goto unlock;
+
+ data_count = ret;
+ } else
+ data_count = 1;
+
+ while (data_count) {
+ ret = i2c_smbus_read_word_swapped(data->client, MAX30208_FIFO_DATA);
+ if (ret < 0)
+ goto unlock;
+
+ data_count--;
+ }
+
+unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+/**
+ * max30208_config_setup() - Set up FIFO configuration register
+ * @data: Struct comprising member elements of the device
+ *
+ * Sets the rollover bit to '1' to enable overwriting FIFO during overflow.
+ */
+static int max30208_config_setup(struct max30208_data *data)
+{
+ u8 regval;
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ regval = ret | MAX30208_FIFO_CONFIG_RO;
+
+ ret = i2c_smbus_write_byte_data(data->client, MAX30208_FIFO_CONFIG, regval);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int max30208_read(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct max30208_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = max30208_update_temp(data);
+ if (ret < 0)
+ return ret;
+
+ *val = sign_extend32(ret, 15);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = 5;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info max30208_info = {
+ .read_raw = max30208_read,
+};
+
+static int max30208_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct max30208_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = i2c;
+ mutex_init(&data->lock);
+
+ indio_dev->name = "max30208";
+ indio_dev->channels = max30208_channels;
+ indio_dev->num_channels = ARRAY_SIZE(max30208_channels);
+ indio_dev->info = &max30208_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = i2c_smbus_write_byte_data(data->client, MAX30208_SYSTEM_CTRL,
+ MAX30208_SYSTEM_CTRL_RESET);
+ if (ret) {
+ dev_err(dev, "Failure in performing reset\n");
+ return ret;
+ }
+
+ msleep(50);
+
+ ret = max30208_config_setup(data);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret) {
+ dev_err(dev, "Failed to register IIO device\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id max30208_id_table[] = {
+ { "max30208" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max30208_id_table);
+
+static const struct acpi_device_id max30208_acpi_match[] = {
+ { "MAX30208" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, max30208_acpi_match);
+
+static const struct of_device_id max30208_of_match[] = {
+ { .compatible = "maxim,max30208" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max30208_of_match);
+
+static struct i2c_driver max30208_driver = {
+ .driver = {
+ .name = "max30208",
+ .of_match_table = max30208_of_match,
+ .acpi_match_table = max30208_acpi_match,
+ },
+ .probe_new = max30208_probe,
+ .id_table = max30208_id_table,
+};
+module_i2c_driver(max30208_driver);
+
+MODULE_AUTHOR("Rajat Khandelwal <rajat.khandelwal@linux.intel.com>");
+MODULE_DESCRIPTION("Maxim MAX30208 digital temperature sensor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
index 8eb0f962ed25..909fadb62349 100644
--- a/drivers/iio/temperature/mlx90614.c
+++ b/drivers/iio/temperature/mlx90614.c
@@ -537,9 +537,9 @@ static int mlx90614_probe_num_ir_sensors(struct i2c_client *client)
return (ret & MLX90614_CONFIG_DUAL_MASK) ? 1 : 0;
}
-static int mlx90614_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mlx90614_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *indio_dev;
struct mlx90614_data *data;
int ret;
@@ -675,7 +675,7 @@ static struct i2c_driver mlx90614_driver = {
.of_match_table = mlx90614_of_match,
.pm = pm_ptr(&mlx90614_pm_ops),
},
- .probe = mlx90614_probe,
+ .probe_new = mlx90614_probe,
.remove = mlx90614_remove,
.id_table = mlx90614_id,
};
diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c
index f6dec0e5f097..753b7a4ccfdd 100644
--- a/drivers/iio/temperature/mlx90632.c
+++ b/drivers/iio/temperature/mlx90632.c
@@ -6,11 +6,14 @@
*
* Driver for the Melexis MLX90632 I2C 16-bit IR thermopile sensor
*/
+#include <linux/bitfield.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
+#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/mod_devicetable.h>
@@ -55,6 +58,12 @@
#define MLX90632_EE_Ha 0x2481 /* Ha customer calib value reg 16bit */
#define MLX90632_EE_Hb 0x2482 /* Hb customer calib value reg 16bit */
+#define MLX90632_EE_MEDICAL_MEAS1 0x24E1 /* Medical measurement 1 16bit */
+#define MLX90632_EE_MEDICAL_MEAS2 0x24E2 /* Medical measurement 2 16bit */
+#define MLX90632_EE_EXTENDED_MEAS1 0x24F1 /* Extended measurement 1 16bit */
+#define MLX90632_EE_EXTENDED_MEAS2 0x24F2 /* Extended measurement 2 16bit */
+#define MLX90632_EE_EXTENDED_MEAS3 0x24F3 /* Extended measurement 3 16bit */
+
/* Register addresses - volatile */
#define MLX90632_REG_I2C_ADDR 0x3000 /* Chip I2C address register */
@@ -62,13 +71,19 @@
#define MLX90632_REG_CONTROL 0x3001 /* Control Register address */
#define MLX90632_CFG_PWR_MASK GENMASK(2, 1) /* PowerMode Mask */
#define MLX90632_CFG_MTYP_MASK GENMASK(8, 4) /* Meas select Mask */
+#define MLX90632_CFG_SOB_MASK BIT(11)
/* PowerModes statuses */
#define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1)
#define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /* hold */
-#define MLX90632_PWR_STATUS_SLEEP_STEP MLX90632_PWR_STATUS(1) /* sleep step*/
+#define MLX90632_PWR_STATUS_SLEEP_STEP MLX90632_PWR_STATUS(1) /* sleep step */
#define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /* step */
-#define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous*/
+#define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous */
+
+#define MLX90632_EE_RR GENMASK(10, 8) /* Only Refresh Rate bits */
+#define MLX90632_REFRESH_RATE(ee_val) FIELD_GET(MLX90632_EE_RR, ee_val)
+ /* Extract Refresh Rate from ee register */
+#define MLX90632_REFRESH_RATE_STATUS(refresh_rate) (refresh_rate << 8)
/* Measurement types */
#define MLX90632_MTYP_MEDICAL 0
@@ -116,8 +131,9 @@
#define MLX90632_REF_12 12LL /* ResCtrlRef value of Ch 1 or Ch 2 */
#define MLX90632_REF_3 12LL /* ResCtrlRef value of Channel 3 */
#define MLX90632_MAX_MEAS_NUM 31 /* Maximum measurements in list */
-#define MLX90632_SLEEP_DELAY_MS 3000 /* Autosleep delay */
+#define MLX90632_SLEEP_DELAY_MS 6000 /* Autosleep delay */
#define MLX90632_EXTENDED_LIMIT 27000 /* Extended mode raw value limit */
+#define MLX90632_MEAS_MAX_TIME 2000 /* Max measurement time in ms for the lowest refresh rate */
/**
* struct mlx90632_data - private data for the MLX90632 device
@@ -130,6 +146,9 @@
* @object_ambient_temperature: Ambient temperature at object (might differ of
* the ambient temperature of sensor.
* @regulator: Regulator of the device
+ * @powerstatus: Current POWER status of the device
+ * @interaction_ts: Timestamp of the last temperature read that is used
+ * for power management in jiffies
*/
struct mlx90632_data {
struct i2c_client *client;
@@ -139,6 +158,8 @@ struct mlx90632_data {
u8 mtyp;
u32 object_ambient_temperature;
struct regulator *regulator;
+ int powerstatus;
+ unsigned long interaction_ts;
};
static const struct regmap_range mlx90632_volatile_reg_range[] = {
@@ -158,6 +179,8 @@ static const struct regmap_range mlx90632_read_reg_range[] = {
regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka),
regmap_reg_range(MLX90632_EE_CTRL, MLX90632_EE_I2C_ADDR),
regmap_reg_range(MLX90632_EE_Ha, MLX90632_EE_Hb),
+ regmap_reg_range(MLX90632_EE_MEDICAL_MEAS1, MLX90632_EE_MEDICAL_MEAS2),
+ regmap_reg_range(MLX90632_EE_EXTENDED_MEAS1, MLX90632_EE_EXTENDED_MEAS3),
regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD),
regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
@@ -196,18 +219,40 @@ static const struct regmap_config mlx90632_regmap = {
.cache_type = REGCACHE_RBTREE,
};
-static s32 mlx90632_pwr_set_sleep_step(struct regmap *regmap)
+static int mlx90632_pwr_set_sleep_step(struct regmap *regmap)
{
- return regmap_update_bits(regmap, MLX90632_REG_CONTROL,
- MLX90632_CFG_PWR_MASK,
- MLX90632_PWR_STATUS_SLEEP_STEP);
+ struct mlx90632_data *data =
+ iio_priv(dev_get_drvdata(regmap_get_device(regmap)));
+ int ret;
+
+ if (data->powerstatus == MLX90632_PWR_STATUS_SLEEP_STEP)
+ return 0;
+
+ ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL, MLX90632_CFG_PWR_MASK,
+ MLX90632_PWR_STATUS_SLEEP_STEP);
+ if (ret < 0)
+ return ret;
+
+ data->powerstatus = MLX90632_PWR_STATUS_SLEEP_STEP;
+ return 0;
}
-static s32 mlx90632_pwr_continuous(struct regmap *regmap)
+static int mlx90632_pwr_continuous(struct regmap *regmap)
{
- return regmap_update_bits(regmap, MLX90632_REG_CONTROL,
- MLX90632_CFG_PWR_MASK,
- MLX90632_PWR_STATUS_CONTINUOUS);
+ struct mlx90632_data *data =
+ iio_priv(dev_get_drvdata(regmap_get_device(regmap)));
+ int ret;
+
+ if (data->powerstatus == MLX90632_PWR_STATUS_CONTINUOUS)
+ return 0;
+
+ ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL, MLX90632_CFG_PWR_MASK,
+ MLX90632_PWR_STATUS_CONTINUOUS);
+ if (ret < 0)
+ return ret;
+
+ data->powerstatus = MLX90632_PWR_STATUS_CONTINUOUS;
+ return 0;
}
/**
@@ -219,6 +264,63 @@ static void mlx90632_reset_delay(void)
usleep_range(150, 200);
}
+static int mlx90632_get_measurement_time(struct regmap *regmap, u16 meas)
+{
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(regmap, meas, &reg);
+ if (ret < 0)
+ return ret;
+
+ return MLX90632_MEAS_MAX_TIME >> FIELD_GET(MLX90632_EE_RR, reg);
+}
+
+static int mlx90632_calculate_dataset_ready_time(struct mlx90632_data *data)
+{
+ unsigned int refresh_time;
+ int ret;
+
+ if (data->mtyp == MLX90632_MTYP_MEDICAL) {
+ ret = mlx90632_get_measurement_time(data->regmap,
+ MLX90632_EE_MEDICAL_MEAS1);
+ if (ret < 0)
+ return ret;
+
+ refresh_time = ret;
+
+ ret = mlx90632_get_measurement_time(data->regmap,
+ MLX90632_EE_MEDICAL_MEAS2);
+ if (ret < 0)
+ return ret;
+
+ refresh_time += ret;
+ } else {
+ ret = mlx90632_get_measurement_time(data->regmap,
+ MLX90632_EE_EXTENDED_MEAS1);
+ if (ret < 0)
+ return ret;
+
+ refresh_time = ret;
+
+ ret = mlx90632_get_measurement_time(data->regmap,
+ MLX90632_EE_EXTENDED_MEAS2);
+ if (ret < 0)
+ return ret;
+
+ refresh_time += ret;
+
+ ret = mlx90632_get_measurement_time(data->regmap,
+ MLX90632_EE_EXTENDED_MEAS3);
+ if (ret < 0)
+ return ret;
+
+ refresh_time += ret;
+ }
+
+ return refresh_time;
+}
+
/**
* mlx90632_perform_measurement() - Trigger and retrieve current measurement cycle
* @data: pointer to mlx90632_data object containing regmap information
@@ -249,26 +351,75 @@ static int mlx90632_perform_measurement(struct mlx90632_data *data)
return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2;
}
-static int mlx90632_set_meas_type(struct regmap *regmap, u8 type)
+/**
+ * mlx90632_perform_measurement_burst() - Trigger and retrieve current measurement
+ * cycle in step sleep mode
+ * @data: pointer to mlx90632_data object containing regmap information
+ *
+ * Perform a measurement and return 2 as measurement cycle position reported
+ * by sensor. This is a blocking function for amount dependent on the sensor
+ * refresh rate.
+ */
+static int mlx90632_perform_measurement_burst(struct mlx90632_data *data)
+{
+ unsigned int reg_status;
+ int ret;
+
+ ret = regmap_write_bits(data->regmap, MLX90632_REG_CONTROL,
+ MLX90632_CFG_SOB_MASK, MLX90632_CFG_SOB_MASK);
+ if (ret < 0)
+ return ret;
+
+ ret = mlx90632_calculate_dataset_ready_time(data);
+ if (ret < 0)
+ return ret;
+
+ msleep(ret); /* Wait minimum time for dataset to be ready */
+
+ ret = regmap_read_poll_timeout(data->regmap, MLX90632_REG_STATUS,
+ reg_status,
+ (reg_status & MLX90632_STAT_BUSY) == 0,
+ 10000, 100 * 10000);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "data not ready");
+ return -ETIMEDOUT;
+ }
+
+ return 2;
+}
+
+static int mlx90632_set_meas_type(struct mlx90632_data *data, u8 type)
{
+ int current_powerstatus;
int ret;
- if ((type != MLX90632_MTYP_MEDICAL) && (type != MLX90632_MTYP_EXTENDED))
- return -EINVAL;
+ if (data->mtyp == type)
+ return 0;
+
+ current_powerstatus = data->powerstatus;
+ ret = mlx90632_pwr_continuous(data->regmap);
+ if (ret < 0)
+ return ret;
- ret = regmap_write(regmap, MLX90632_REG_I2C_CMD, MLX90632_RESET_CMD);
+ ret = regmap_write(data->regmap, MLX90632_REG_I2C_CMD, MLX90632_RESET_CMD);
if (ret < 0)
return ret;
mlx90632_reset_delay();
- ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL,
+ ret = regmap_update_bits(data->regmap, MLX90632_REG_CONTROL,
(MLX90632_CFG_MTYP_MASK | MLX90632_CFG_PWR_MASK),
(MLX90632_MTYP_STATUS(type) | MLX90632_PWR_STATUS_HALT));
if (ret < 0)
return ret;
- return mlx90632_pwr_continuous(regmap);
+ data->mtyp = type;
+ data->powerstatus = MLX90632_PWR_STATUS_HALT;
+
+ if (current_powerstatus == MLX90632_PWR_STATUS_SLEEP_STEP)
+ return mlx90632_pwr_set_sleep_step(data->regmap);
+
+ return mlx90632_pwr_continuous(data->regmap);
}
static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
@@ -284,7 +435,7 @@ static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
*channel_old = 1;
break;
default:
- return -EINVAL;
+ return -ECHRNG;
}
return 0;
@@ -293,8 +444,8 @@ static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
static int mlx90632_read_ambient_raw(struct regmap *regmap,
s16 *ambient_new_raw, s16 *ambient_old_raw)
{
- int ret;
unsigned int read_tmp;
+ int ret;
ret = regmap_read(regmap, MLX90632_RAM_3(1), &read_tmp);
if (ret < 0)
@@ -313,11 +464,11 @@ static int mlx90632_read_object_raw(struct regmap *regmap,
int perform_measurement_ret,
s16 *object_new_raw, s16 *object_old_raw)
{
- int ret;
unsigned int read_tmp;
- s16 read;
- u8 channel = 0;
u8 channel_old = 0;
+ u8 channel = 0;
+ s16 read;
+ int ret;
ret = mlx90632_channel_new_select(perform_measurement_ret, &channel,
&channel_old);
@@ -352,14 +503,34 @@ static int mlx90632_read_all_channel(struct mlx90632_data *data,
s16 *ambient_new_raw, s16 *ambient_old_raw,
s16 *object_new_raw, s16 *object_old_raw)
{
- s32 ret, measurement;
+ s32 measurement;
+ int ret;
mutex_lock(&data->lock);
- measurement = mlx90632_perform_measurement(data);
- if (measurement < 0) {
- ret = measurement;
+ ret = mlx90632_set_meas_type(data, MLX90632_MTYP_MEDICAL);
+ if (ret < 0)
+ goto read_unlock;
+
+ switch (data->powerstatus) {
+ case MLX90632_PWR_STATUS_CONTINUOUS:
+ ret = mlx90632_perform_measurement(data);
+ if (ret < 0)
+ goto read_unlock;
+
+ break;
+ case MLX90632_PWR_STATUS_SLEEP_STEP:
+ ret = mlx90632_perform_measurement_burst(data);
+ if (ret < 0)
+ goto read_unlock;
+
+ break;
+ default:
+ ret = -EOPNOTSUPP;
goto read_unlock;
}
+
+ measurement = ret; /* If we came here ret holds the measurement position */
+
ret = mlx90632_read_ambient_raw(data->regmap, ambient_new_raw,
ambient_old_raw);
if (ret < 0)
@@ -441,14 +612,26 @@ static int mlx90632_read_all_channel_extended(struct mlx90632_data *data, s16 *o
s32 ret, meas;
mutex_lock(&data->lock);
- ret = mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_EXTENDED);
+ ret = mlx90632_set_meas_type(data, MLX90632_MTYP_EXTENDED);
if (ret < 0)
goto read_unlock;
- ret = read_poll_timeout(mlx90632_perform_measurement, meas, meas == 19,
- 50000, 800000, false, data);
- if (ret != 0)
+ switch (data->powerstatus) {
+ case MLX90632_PWR_STATUS_CONTINUOUS:
+ ret = read_poll_timeout(mlx90632_perform_measurement, meas, meas == 19,
+ 50000, 800000, false, data);
+ if (ret)
+ goto read_unlock;
+ break;
+ case MLX90632_PWR_STATUS_SLEEP_STEP:
+ ret = mlx90632_perform_measurement_burst(data);
+ if (ret < 0)
+ goto read_unlock;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
goto read_unlock;
+ }
ret = mlx90632_read_object_raw_extended(data->regmap, object_new_raw);
if (ret < 0)
@@ -457,8 +640,6 @@ static int mlx90632_read_all_channel_extended(struct mlx90632_data *data, s16 *o
ret = mlx90632_read_ambient_raw_extended(data->regmap, ambient_new_raw, ambient_old_raw);
read_unlock:
- (void) mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_MEDICAL);
-
mutex_unlock(&data->lock);
return ret;
}
@@ -466,9 +647,9 @@ read_unlock:
static int mlx90632_read_ee_register(struct regmap *regmap, u16 reg_lsb,
s32 *reg_value)
{
- s32 ret;
unsigned int read;
u32 value;
+ int ret;
ret = regmap_read(regmap, reg_lsb, &read);
if (ret < 0)
@@ -632,12 +813,12 @@ static s32 mlx90632_calc_temp_object_extended(s64 object, s64 ambient, s64 refle
static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
{
- s32 ret;
+ s16 ambient_new_raw, ambient_old_raw, object_new_raw, object_old_raw;
s32 Ea, Eb, Fa, Fb, Ga;
unsigned int read_tmp;
- s16 Ha, Hb, Gb, Ka;
- s16 ambient_new_raw, ambient_old_raw, object_new_raw, object_old_raw;
s64 object, ambient;
+ s16 Ha, Hb, Gb, Ka;
+ int ret;
ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Ea, &Ea);
if (ret < 0)
@@ -711,11 +892,11 @@ static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
static int mlx90632_calc_ambient_dsp105(struct mlx90632_data *data, int *val)
{
- s32 ret;
+ s16 ambient_new_raw, ambient_old_raw;
unsigned int read_tmp;
s32 PT, PR, PG, PO;
+ int ret;
s16 Gb;
- s16 ambient_new_raw, ambient_old_raw;
ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_R, &PR);
if (ret < 0)
@@ -743,12 +924,73 @@ static int mlx90632_calc_ambient_dsp105(struct mlx90632_data *data, int *val)
return ret;
}
+static int mlx90632_get_refresh_rate(struct mlx90632_data *data,
+ int *refresh_rate)
+{
+ unsigned int meas1;
+ int ret;
+
+ ret = regmap_read(data->regmap, MLX90632_EE_MEDICAL_MEAS1, &meas1);
+ if (ret < 0)
+ return ret;
+
+ *refresh_rate = MLX90632_REFRESH_RATE(meas1);
+
+ return ret;
+}
+
+static const int mlx90632_freqs[][2] = {
+ {0, 500000},
+ {1, 0},
+ {2, 0},
+ {4, 0},
+ {8, 0},
+ {16, 0},
+ {32, 0},
+ {64, 0}
+};
+
+/**
+ * mlx90632_pm_interraction_wakeup() - Measure time between user interactions to change powermode
+ * @data: pointer to mlx90632_data object containing interaction_ts information
+ *
+ * Switch to continuous mode when interaction is faster than MLX90632_MEAS_MAX_TIME. Update the
+ * interaction_ts for each function call with the jiffies to enable measurement between function
+ * calls. Initial value of the interaction_ts needs to be set before this function call.
+ */
+static int mlx90632_pm_interraction_wakeup(struct mlx90632_data *data)
+{
+ unsigned long now;
+ int ret;
+
+ now = jiffies;
+ if (time_in_range(now, data->interaction_ts,
+ data->interaction_ts +
+ msecs_to_jiffies(MLX90632_MEAS_MAX_TIME + 100))) {
+ if (data->powerstatus == MLX90632_PWR_STATUS_SLEEP_STEP) {
+ ret = mlx90632_pwr_continuous(data->regmap);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ data->interaction_ts = now;
+
+ return 0;
+}
+
static int mlx90632_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
struct mlx90632_data *data = iio_priv(indio_dev);
int ret;
+ int cr;
+
+ pm_runtime_get_sync(&data->client->dev);
+ ret = mlx90632_pm_interraction_wakeup(data);
+ if (ret < 0)
+ goto mlx90632_read_raw_pm;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
@@ -756,16 +998,22 @@ static int mlx90632_read_raw(struct iio_dev *indio_dev,
case IIO_MOD_TEMP_AMBIENT:
ret = mlx90632_calc_ambient_dsp105(data, val);
if (ret < 0)
- return ret;
- return IIO_VAL_INT;
+ goto mlx90632_read_raw_pm;
+
+ ret = IIO_VAL_INT;
+ break;
case IIO_MOD_TEMP_OBJECT:
ret = mlx90632_calc_object_dsp105(data, val);
if (ret < 0)
- return ret;
- return IIO_VAL_INT;
+ goto mlx90632_read_raw_pm;
+
+ ret = IIO_VAL_INT;
+ break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
+ break;
case IIO_CHAN_INFO_CALIBEMISSIVITY:
if (data->emissivity == 1000) {
*val = 1;
@@ -774,13 +1022,30 @@ static int mlx90632_read_raw(struct iio_dev *indio_dev,
*val = 0;
*val2 = data->emissivity * 1000;
}
- return IIO_VAL_INT_PLUS_MICRO;
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
case IIO_CHAN_INFO_CALIBAMBIENT:
*val = data->object_ambient_temperature;
- return IIO_VAL_INT;
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = mlx90632_get_refresh_rate(data, &cr);
+ if (ret < 0)
+ goto mlx90632_read_raw_pm;
+
+ *val = mlx90632_freqs[cr][0];
+ *val2 = mlx90632_freqs[cr][1];
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
+
+mlx90632_read_raw_pm:
+ pm_runtime_mark_last_busy(&data->client->dev);
+ pm_runtime_put_autosuspend(&data->client->dev);
+ return ret;
}
static int mlx90632_write_raw(struct iio_dev *indio_dev,
@@ -805,12 +1070,30 @@ static int mlx90632_write_raw(struct iio_dev *indio_dev,
}
}
+static int mlx90632_read_avail(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_SAMP_FREQ:
+ *vals = (int *)mlx90632_freqs;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *length = 2 * ARRAY_SIZE(mlx90632_freqs);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct iio_chan_spec mlx90632_channels[] = {
{
.type = IIO_TEMP,
.modified = 1,
.channel2 = IIO_MOD_TEMP_AMBIENT,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
{
.type = IIO_TEMP,
@@ -818,19 +1101,29 @@ static const struct iio_chan_spec mlx90632_channels[] = {
.channel2 = IIO_MOD_TEMP_OBJECT,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) | BIT(IIO_CHAN_INFO_CALIBAMBIENT),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
};
static const struct iio_info mlx90632_info = {
.read_raw = mlx90632_read_raw,
.write_raw = mlx90632_write_raw,
+ .read_avail = mlx90632_read_avail,
};
-static int mlx90632_sleep(struct mlx90632_data *data)
+static void mlx90632_sleep(void *_data)
+{
+ struct mlx90632_data *data = _data;
+
+ mlx90632_pwr_set_sleep_step(data->regmap);
+}
+
+static int mlx90632_suspend(struct mlx90632_data *data)
{
regcache_mark_dirty(data->regmap);
- dev_dbg(&data->client->dev, "Requesting sleep");
+ dev_dbg(&data->client->dev, "Requesting suspend");
return mlx90632_pwr_set_sleep_step(data->regmap);
}
@@ -875,14 +1168,14 @@ static int mlx90632_enable_regulator(struct mlx90632_data *data)
return ret;
}
-static int mlx90632_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mlx90632_probe(struct i2c_client *client)
{
- struct iio_dev *indio_dev;
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct mlx90632_data *mlx90632;
+ struct iio_dev *indio_dev;
struct regmap *regmap;
- int ret;
unsigned int read;
+ int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mlx90632));
if (!indio_dev) {
@@ -902,6 +1195,7 @@ static int mlx90632_probe(struct i2c_client *client,
mlx90632->client = client;
mlx90632->regmap = regmap;
mlx90632->mtyp = MLX90632_MTYP_MEDICAL;
+ mlx90632->powerstatus = MLX90632_PWR_STATUS_HALT;
mutex_init(&mlx90632->lock);
indio_dev->name = id->name;
@@ -933,6 +1227,13 @@ static int mlx90632_probe(struct i2c_client *client,
return ret;
}
+ ret = devm_add_action_or_reset(&client->dev, mlx90632_sleep, mlx90632);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to setup low power cleanup action %d\n",
+ ret);
+ return ret;
+ }
+
ret = regmap_read(mlx90632->regmap, MLX90632_EE_VERSION, &read);
if (ret < 0) {
dev_err(&client->dev, "read of version failed: %d\n", ret);
@@ -961,32 +1262,20 @@ static int mlx90632_probe(struct i2c_client *client,
mlx90632->emissivity = 1000;
mlx90632->object_ambient_temperature = 25000; /* 25 degrees milliCelsius */
+ mlx90632->interaction_ts = jiffies; /* Set initial value */
- pm_runtime_disable(&client->dev);
- ret = pm_runtime_set_active(&client->dev);
- if (ret < 0) {
- mlx90632_sleep(mlx90632);
+ pm_runtime_get_noresume(&client->dev);
+ pm_runtime_set_active(&client->dev);
+
+ ret = devm_pm_runtime_enable(&client->dev);
+ if (ret)
return ret;
- }
- pm_runtime_enable(&client->dev);
+
pm_runtime_set_autosuspend_delay(&client->dev, MLX90632_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
- return iio_device_register(indio_dev);
-}
-
-static void mlx90632_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct mlx90632_data *data = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
-
- pm_runtime_disable(&client->dev);
- pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
-
- mlx90632_sleep(data);
+ return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id mlx90632_id[] = {
@@ -1001,33 +1290,54 @@ static const struct of_device_id mlx90632_of_match[] = {
};
MODULE_DEVICE_TABLE(of, mlx90632_of_match);
-static int __maybe_unused mlx90632_pm_suspend(struct device *dev)
+static int mlx90632_pm_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
- struct mlx90632_data *data = iio_priv(indio_dev);
+ struct mlx90632_data *data = iio_priv(dev_get_drvdata(dev));
+ int ret;
- return mlx90632_sleep(data);
+ ret = mlx90632_suspend(data);
+ if (ret < 0)
+ return ret;
+
+ ret = regulator_disable(data->regulator);
+ if (ret < 0)
+ dev_err(regmap_get_device(data->regmap),
+ "Failed to disable power regulator: %d\n", ret);
+
+ return ret;
}
-static int __maybe_unused mlx90632_pm_resume(struct device *dev)
+static int mlx90632_pm_resume(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
- struct mlx90632_data *data = iio_priv(indio_dev);
+ struct mlx90632_data *data = iio_priv(dev_get_drvdata(dev));
+ int ret;
+
+ ret = mlx90632_enable_regulator(data);
+ if (ret < 0)
+ return ret;
return mlx90632_wakeup(data);
}
-static UNIVERSAL_DEV_PM_OPS(mlx90632_pm_ops, mlx90632_pm_suspend,
- mlx90632_pm_resume, NULL);
+static int mlx90632_pm_runtime_suspend(struct device *dev)
+{
+ struct mlx90632_data *data = iio_priv(dev_get_drvdata(dev));
+
+ return mlx90632_pwr_set_sleep_step(data->regmap);
+}
+
+static const struct dev_pm_ops mlx90632_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(mlx90632_pm_suspend, mlx90632_pm_resume)
+ RUNTIME_PM_OPS(mlx90632_pm_runtime_suspend, NULL, NULL)
+};
static struct i2c_driver mlx90632_driver = {
.driver = {
.name = "mlx90632",
.of_match_table = mlx90632_of_match,
- .pm = &mlx90632_pm_ops,
+ .pm = pm_ptr(&mlx90632_pm_ops),
},
- .probe = mlx90632_probe,
- .remove = mlx90632_remove,
+ .probe_new = 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 706a760f30b4..cdf08477e63f 100644
--- a/drivers/iio/temperature/tmp006.c
+++ b/drivers/iio/temperature/tmp006.c
@@ -212,8 +212,7 @@ static void tmp006_powerdown_cleanup(void *dev)
tmp006_power(dev, false);
}
-static int tmp006_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tmp006_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct tmp006_data *data;
@@ -284,7 +283,7 @@ static struct i2c_driver tmp006_driver = {
.name = "tmp006",
.pm = pm_sleep_ptr(&tmp006_pm_ops),
},
- .probe = tmp006_probe,
+ .probe_new = 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 f3420d8a0e35..8d27aa3bdd6d 100644
--- a/drivers/iio/temperature/tmp007.c
+++ b/drivers/iio/temperature/tmp007.c
@@ -446,9 +446,9 @@ static void tmp007_powerdown_action_cb(void *priv)
tmp007_powerdown(data);
}
-static int tmp007_probe(struct i2c_client *client,
- const struct i2c_device_id *tmp007_id)
+static int tmp007_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *tmp007_id = i2c_client_get_device_id(client);
struct tmp007_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -574,7 +574,7 @@ static struct i2c_driver tmp007_driver = {
.of_match_table = tmp007_of_match,
.pm = pm_sleep_ptr(&tmp007_pm_ops),
},
- .probe = tmp007_probe,
+ .probe_new = tmp007_probe,
.id_table = tmp007_id,
};
module_i2c_driver(tmp007_driver);
diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c
index 60d58ec5b063..30b268ba82cc 100644
--- a/drivers/iio/temperature/tsys01.c
+++ b/drivers/iio/temperature/tsys01.c
@@ -176,8 +176,7 @@ static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev)
return devm_iio_device_register(dev, indio_dev);
}
-static int tsys01_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tsys01_i2c_probe(struct i2c_client *client)
{
struct tsys01_dev *dev_data;
struct iio_dev *indio_dev;
@@ -219,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 = tsys01_i2c_probe,
+ .probe_new = 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 49c275e4f510..cdefe046ab17 100644
--- a/drivers/iio/temperature/tsys02d.c
+++ b/drivers/iio/temperature/tsys02d.c
@@ -121,9 +121,9 @@ static const struct iio_info tsys02d_info = {
.attrs = &tsys02d_attribute_group,
};
-static int tsys02d_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tsys02d_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ms_ht_dev *dev_data;
struct iio_dev *indio_dev;
int ret;
@@ -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 = tsys02d_probe,
+ .probe_new = tsys02d_probe,
.id_table = tsys02d_id,
.driver = {
.name = "tsys02d",
diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c
index 6b05eed41612..575d725696a9 100644
--- a/drivers/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/iio/trigger/iio-trig-sysfs.c
@@ -138,18 +138,18 @@ static int iio_sysfs_trigger_probe(int id)
}
if (foundit) {
ret = -EINVAL;
- goto out1;
+ goto err_unlock;
}
t = kmalloc(sizeof(*t), GFP_KERNEL);
if (t == NULL) {
ret = -ENOMEM;
- goto out1;
+ goto err_unlock;
}
t->id = id;
t->trig = iio_trigger_alloc(&iio_sysfs_trig_dev, "sysfstrig%d", id);
if (!t->trig) {
ret = -ENOMEM;
- goto free_t;
+ goto err_free_sys_trig;
}
t->trig->dev.groups = iio_sysfs_trigger_attr_groups;
@@ -159,17 +159,17 @@ static int iio_sysfs_trigger_probe(int id)
ret = iio_trigger_register(t->trig);
if (ret)
- goto out2;
+ goto err_free_trig;
list_add(&t->l, &iio_sysfs_trig_list);
__module_get(THIS_MODULE);
mutex_unlock(&iio_sysfs_trig_list_mut);
return 0;
-out2:
+err_free_trig:
iio_trigger_free(t->trig);
-free_t:
+err_free_sys_trig:
kfree(t);
-out1:
+err_unlock:
mutex_unlock(&iio_sysfs_trig_list_mut);
return ret;
}