summaryrefslogtreecommitdiff
path: root/drivers/iio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/Kconfig1
-rw-r--r--drivers/iio/Makefile1
-rw-r--r--drivers/iio/TODO13
-rw-r--r--drivers/iio/accel/Kconfig12
-rw-r--r--drivers/iio/accel/adis16201.c2
-rw-r--r--drivers/iio/accel/adis16209.c2
-rw-r--r--drivers/iio/accel/adxl313_core.c23
-rw-r--r--drivers/iio/accel/adxl313_i2c.c11
-rw-r--r--drivers/iio/accel/adxl313_spi.c12
-rw-r--r--drivers/iio/accel/adxl345_core.c32
-rw-r--r--drivers/iio/accel/adxl345_i2c.c4
-rw-r--r--drivers/iio/accel/adxl345_spi.c4
-rw-r--r--drivers/iio/accel/adxl355_core.c36
-rw-r--r--drivers/iio/accel/adxl355_i2c.c16
-rw-r--r--drivers/iio/accel/adxl355_spi.c16
-rw-r--r--drivers/iio/accel/adxl367.c7
-rw-r--r--drivers/iio/accel/adxl367_i2c.c3
-rw-r--r--drivers/iio/accel/adxl367_spi.c3
-rw-r--r--drivers/iio/accel/adxl372.c320
-rw-r--r--drivers/iio/accel/adxl372.h20
-rw-r--r--drivers/iio/accel/adxl372_i2c.c18
-rw-r--r--drivers/iio/accel/adxl372_spi.c18
-rw-r--r--drivers/iio/accel/adxl380.c10
-rw-r--r--drivers/iio/accel/adxl380_i2c.c9
-rw-r--r--drivers/iio/accel/adxl380_spi.c9
-rw-r--r--drivers/iio/accel/bma180.c15
-rw-r--r--drivers/iio/accel/bma220_core.c4
-rw-r--r--drivers/iio/accel/bma220_i2c.c3
-rw-r--r--drivers/iio/accel/bma220_spi.c3
-rw-r--r--drivers/iio/accel/bma400_core.c3
-rw-r--r--drivers/iio/accel/bma400_i2c.c3
-rw-r--r--drivers/iio/accel/bma400_spi.c3
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c12
-rw-r--r--drivers/iio/accel/bmc150-accel-i2c.c21
-rw-r--r--drivers/iio/accel/bmc150-accel-spi.c19
-rw-r--r--drivers/iio/accel/bmi088-accel-i2c.c7
-rw-r--r--drivers/iio/accel/bmi088-accel-spi.c6
-rw-r--r--drivers/iio/accel/da280.c6
-rw-r--r--drivers/iio/accel/da311.c2
-rw-r--r--drivers/iio/accel/dmard06.c7
-rw-r--r--drivers/iio/accel/dmard09.c9
-rw-r--r--drivers/iio/accel/dmard10.c2
-rw-r--r--drivers/iio/accel/fxls8962af-core.c3
-rw-r--r--drivers/iio/accel/fxls8962af-i2c.c9
-rw-r--r--drivers/iio/accel/fxls8962af-spi.c5
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c96
-rw-r--r--drivers/iio/accel/kionix-kx022a.c2
-rw-r--r--drivers/iio/accel/kxcjk-1013.c11
-rw-r--r--drivers/iio/accel/kxsd9-i2c.c3
-rw-r--r--drivers/iio/accel/kxsd9-spi.c3
-rw-r--r--drivers/iio/accel/kxsd9.c5
-rw-r--r--drivers/iio/accel/mc3230.c4
-rw-r--r--drivers/iio/accel/mma7455_i2c.c4
-rw-r--r--drivers/iio/accel/mma7455_spi.c4
-rw-r--r--drivers/iio/accel/mma7660.c3
-rw-r--r--drivers/iio/accel/mma8452.c105
-rw-r--r--drivers/iio/accel/mma9551.c7
-rw-r--r--drivers/iio/accel/mma9553.c8
-rw-r--r--drivers/iio/accel/msa311.c3
-rw-r--r--drivers/iio/accel/mxc4005.c10
-rw-r--r--drivers/iio/accel/mxc6255.c5
-rw-r--r--drivers/iio/accel/sca3000.c215
-rw-r--r--drivers/iio/accel/sca3300.c4
-rw-r--r--drivers/iio/accel/ssp_accel_sensor.c2
-rw-r--r--drivers/iio/accel/st_accel_i2c.c53
-rw-r--r--drivers/iio/accel/st_accel_spi.c41
-rw-r--r--drivers/iio/accel/stk8312.c21
-rw-r--r--drivers/iio/accel/stk8ba50.c17
-rw-r--r--drivers/iio/adc/88pm886-gpadc.c5
-rw-r--r--drivers/iio/adc/Kconfig136
-rw-r--r--drivers/iio/adc/Makefile8
-rw-r--r--drivers/iio/adc/ad4000.c63
-rw-r--r--drivers/iio/adc/ad4030.c628
-rw-r--r--drivers/iio/adc/ad4062.c27
-rw-r--r--drivers/iio/adc/ad4080.c351
-rw-r--r--drivers/iio/adc/ad4130.c493
-rw-r--r--drivers/iio/adc/ad4134.c3
-rw-r--r--drivers/iio/adc/ad4170-4.c59
-rw-r--r--drivers/iio/adc/ad4691.c2083
-rw-r--r--drivers/iio/adc/ad4695.c23
-rw-r--r--drivers/iio/adc/ad4851.c19
-rw-r--r--drivers/iio/adc/ad7091r5.c12
-rw-r--r--drivers/iio/adc/ad7091r8.c6
-rw-r--r--drivers/iio/adc/ad7124.c5
-rw-r--r--drivers/iio/adc/ad7173.c38
-rw-r--r--drivers/iio/adc/ad7191.c66
-rw-r--r--drivers/iio/adc/ad7192.c23
-rw-r--r--drivers/iio/adc/ad7266.c10
-rw-r--r--drivers/iio/adc/ad7280a.c82
-rw-r--r--drivers/iio/adc/ad7291.c2
-rw-r--r--drivers/iio/adc/ad7292.c19
-rw-r--r--drivers/iio/adc/ad7298.c3
-rw-r--r--drivers/iio/adc/ad7380.c89
-rw-r--r--drivers/iio/adc/ad7405.c1
-rw-r--r--drivers/iio/adc/ad7476.c60
-rw-r--r--drivers/iio/adc/ad7606.c2
-rw-r--r--drivers/iio/adc/ad7606_par.c1
-rw-r--r--drivers/iio/adc/ad7606_spi.c22
-rw-r--r--drivers/iio/adc/ad7625.c5
-rw-r--r--drivers/iio/adc/ad7766.c12
-rw-r--r--drivers/iio/adc/ad7768-1.c235
-rw-r--r--drivers/iio/adc/ad7779.c7
-rw-r--r--drivers/iio/adc/ad7780.c54
-rw-r--r--drivers/iio/adc/ad7791.c29
-rw-r--r--drivers/iio/adc/ad7793.c58
-rw-r--r--drivers/iio/adc/ad7887.c4
-rw-r--r--drivers/iio/adc/ad7923.c18
-rw-r--r--drivers/iio/adc/ad7944.c6
-rw-r--r--drivers/iio/adc/ad7949.c31
-rw-r--r--drivers/iio/adc/ad799x.c149
-rw-r--r--drivers/iio/adc/ad9467.c116
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c45
-rw-r--r--drivers/iio/adc/ade9000.c29
-rw-r--r--drivers/iio/adc/adi-axi-adc.c36
-rw-r--r--drivers/iio/adc/aspeed_adc.c73
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c6
-rw-r--r--drivers/iio/adc/at91_adc.c26
-rw-r--r--drivers/iio/adc/axp20x_adc.c1
-rw-r--r--drivers/iio/adc/bcm_iproc_adc.c1
-rw-r--r--drivers/iio/adc/berlin2-adc.c1
-rw-r--r--drivers/iio/adc/cc10001_adc.c10
-rw-r--r--drivers/iio/adc/cpcap-adc.c16
-rw-r--r--drivers/iio/adc/dln2-adc.c12
-rw-r--r--drivers/iio/adc/envelope-detector.c2
-rw-r--r--drivers/iio/adc/fsl-imx25-gcq.c3
-rw-r--r--drivers/iio/adc/gehc-pmc-adc.c2
-rw-r--r--drivers/iio/adc/hi8435.c3
-rw-r--r--drivers/iio/adc/hx711.c130
-rw-r--r--drivers/iio/adc/imx7d_adc.c1
-rw-r--r--drivers/iio/adc/imx8qxp-adc.c1
-rw-r--r--drivers/iio/adc/imx93_adc.c1
-rw-r--r--drivers/iio/adc/ina2xx-adc.c89
-rw-r--r--drivers/iio/adc/ingenic-adc.c69
-rw-r--r--drivers/iio/adc/intel_dc_ti_adc.c5
-rw-r--r--drivers/iio/adc/intel_mrfld_adc.c1
-rw-r--r--drivers/iio/adc/lpc18xx_adc.c1
-rw-r--r--drivers/iio/adc/lpc32xx_adc.c5
-rw-r--r--drivers/iio/adc/ltc2309.c91
-rw-r--r--drivers/iio/adc/ltc2378.c857
-rw-r--r--drivers/iio/adc/ltc2471.c4
-rw-r--r--drivers/iio/adc/ltc2485.c2
-rw-r--r--drivers/iio/adc/ltc2496.c1
-rw-r--r--drivers/iio/adc/ltc2497.c5
-rw-r--r--drivers/iio/adc/max1027.c13
-rw-r--r--drivers/iio/adc/max11100.c1
-rw-r--r--drivers/iio/adc/max1118.c7
-rw-r--r--drivers/iio/adc/max11205.c4
-rw-r--r--drivers/iio/adc/max11410.c8
-rw-r--r--drivers/iio/adc/max1241.c9
-rw-r--r--drivers/iio/adc/max1363.c88
-rw-r--r--drivers/iio/adc/max14001.c5
-rw-r--r--drivers/iio/adc/max34408.c5
-rw-r--r--drivers/iio/adc/max77541-adc.c3
-rw-r--r--drivers/iio/adc/max9611.c1
-rw-r--r--drivers/iio/adc/mcp320x.c27
-rw-r--r--drivers/iio/adc/mcp3422.c82
-rw-r--r--drivers/iio/adc/mcp3564.c26
-rw-r--r--drivers/iio/adc/mcp3911.c15
-rw-r--r--drivers/iio/adc/men_z188_adc.c2
-rw-r--r--drivers/iio/adc/meson_saradc.c23
-rw-r--r--drivers/iio/adc/mp2629_adc.c1
-rw-r--r--drivers/iio/adc/mt6323-auxadc.c313
-rw-r--r--drivers/iio/adc/mt6359-auxadc.c4
-rw-r--r--drivers/iio/adc/mt6360-adc.c1
-rw-r--r--drivers/iio/adc/mt6370-adc.c1
-rw-r--r--drivers/iio/adc/mt6577_auxadc.c1
-rw-r--r--drivers/iio/adc/nau7802.c6
-rw-r--r--drivers/iio/adc/nct7201.c1
-rw-r--r--drivers/iio/adc/npcm_adc.c28
-rw-r--r--drivers/iio/adc/nxp-sar-adc.c44
-rw-r--r--drivers/iio/adc/pac1921.c6
-rw-r--r--drivers/iio/adc/pac1934.c2
-rw-r--r--drivers/iio/adc/palmas_gpadc.c8
-rw-r--r--drivers/iio/adc/qcom-pm8xxx-xoadc.c40
-rw-r--r--drivers/iio/adc/qcom-spmi-adc5-gen3.c828
-rw-r--r--drivers/iio/adc/qcom-spmi-adc5.c1
-rw-r--r--drivers/iio/adc/qcom-spmi-iadc.c18
-rw-r--r--drivers/iio/adc/qcom-spmi-rradc.c1
-rw-r--r--drivers/iio/adc/qcom-spmi-vadc.c1
-rw-r--r--drivers/iio/adc/rcar-gyroadc.c14
-rw-r--r--drivers/iio/adc/rohm-bd79112.c3
-rw-r--r--drivers/iio/adc/rohm-bd79124.c7
-rw-r--r--drivers/iio/adc/rtq6056.c11
-rw-r--r--drivers/iio/adc/rzg2l_adc.c1
-rw-r--r--drivers/iio/adc/rzn1-adc.c1
-rw-r--r--drivers/iio/adc/rzt2h_adc.c1
-rw-r--r--drivers/iio/adc/sd_adc_modulator.c2
-rw-r--r--drivers/iio/adc/sophgo-cv1800b-adc.c1
-rw-r--r--drivers/iio/adc/spear_adc.c29
-rw-r--r--drivers/iio/adc/stm32-adc-core.c2
-rw-r--r--drivers/iio/adc/stm32-adc.c13
-rw-r--r--drivers/iio/adc/stm32-dfsdm-adc.c12
-rw-r--r--drivers/iio/adc/sun20i-gpadc-iio.c31
-rw-r--r--drivers/iio/adc/sun4i-gpadc-iio.c6
-rw-r--r--drivers/iio/adc/ti-adc081c.c13
-rw-r--r--drivers/iio/adc/ti-adc0832.c9
-rw-r--r--drivers/iio/adc/ti-adc084s021.c9
-rw-r--r--drivers/iio/adc/ti-adc108s102.c3
-rw-r--r--drivers/iio/adc/ti-adc12138.c6
-rw-r--r--drivers/iio/adc/ti-adc128s052.c25
-rw-r--r--drivers/iio/adc/ti-adc161s626.c46
-rw-r--r--drivers/iio/adc/ti-ads1015.c51
-rw-r--r--drivers/iio/adc/ti-ads1018.c7
-rw-r--r--drivers/iio/adc/ti-ads1100.c4
-rw-r--r--drivers/iio/adc/ti-ads1119.c22
-rw-r--r--drivers/iio/adc/ti-ads112c14.c1454
-rw-r--r--drivers/iio/adc/ti-ads124s08.c8
-rw-r--r--drivers/iio/adc/ti-ads1298.c28
-rw-r--r--drivers/iio/adc/ti-ads131e08.c6
-rw-r--r--drivers/iio/adc/ti-ads131m02.c11
-rw-r--r--drivers/iio/adc/ti-ads7138.c46
-rw-r--r--drivers/iio/adc/ti-ads7924.c7
-rw-r--r--drivers/iio/adc/ti-ads7950.c425
-rw-r--r--drivers/iio/adc/ti-ads8688.c75
-rw-r--r--drivers/iio/adc/ti-lmp92064.c2
-rw-r--r--drivers/iio/adc/ti-tlc4541.c5
-rw-r--r--drivers/iio/adc/ti-tsc2046.c25
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c6
-rw-r--r--drivers/iio/adc/twl4030-madc.c3
-rw-r--r--drivers/iio/adc/twl6030-gpadc.c3
-rw-r--r--drivers/iio/adc/versal-sysmon-core.c1052
-rw-r--r--drivers/iio/adc/versal-sysmon-i2c.c134
-rw-r--r--drivers/iio/adc/versal-sysmon.c92
-rw-r--r--drivers/iio/adc/versal-sysmon.h120
-rw-r--r--drivers/iio/adc/vf610_adc.c1
-rw-r--r--drivers/iio/adc/viperboard_adc.c4
-rw-r--r--drivers/iio/adc/xilinx-ams.c191
-rw-r--r--drivers/iio/adc/xilinx-xadc-core.c12
-rw-r--r--drivers/iio/addac/ad74115.c7
-rw-r--r--drivers/iio/addac/ad74413r.c12
-rw-r--r--drivers/iio/addac/stx104.c6
-rw-r--r--drivers/iio/afe/iio-rescale.c2
-rw-r--r--drivers/iio/amplifiers/Kconfig8
-rw-r--r--drivers/iio/amplifiers/ad8366.c404
-rw-r--r--drivers/iio/amplifiers/ada4250.c4
-rw-r--r--drivers/iio/amplifiers/adl8113.c1
-rw-r--r--drivers/iio/amplifiers/hmc425a.c1
-rw-r--r--drivers/iio/buffer/industrialio-buffer-cb.c1
-rw-r--r--drivers/iio/buffer/industrialio-buffer-dmaengine.c44
-rw-r--r--drivers/iio/buffer/industrialio-hw-consumer.c18
-rw-r--r--drivers/iio/buffer/kfifo_buf.c41
-rw-r--r--drivers/iio/cdc/ad7150.c9
-rw-r--r--drivers/iio/cdc/ad7746.c8
-rw-r--r--drivers/iio/chemical/ags02ma.c2
-rw-r--r--drivers/iio/chemical/ams-iaq-core.c3
-rw-r--r--drivers/iio/chemical/atlas-ezo-sensor.c7
-rw-r--r--drivers/iio/chemical/atlas-sensor.c30
-rw-r--r--drivers/iio/chemical/bme680_core.c4
-rw-r--r--drivers/iio/chemical/bme680_i2c.c9
-rw-r--r--drivers/iio/chemical/bme680_spi.c10
-rw-r--r--drivers/iio/chemical/ccs811.c8
-rw-r--r--drivers/iio/chemical/ens160_core.c2
-rw-r--r--drivers/iio/chemical/ens160_i2c.c2
-rw-r--r--drivers/iio/chemical/ens160_spi.c2
-rw-r--r--drivers/iio/chemical/mhz19b.c18
-rw-r--r--drivers/iio/chemical/pms7003.c1
-rw-r--r--drivers/iio/chemical/scd30_core.c91
-rw-r--r--drivers/iio/chemical/scd30_i2c.c10
-rw-r--r--drivers/iio/chemical/scd30_serial.c5
-rw-r--r--drivers/iio/chemical/sgp30.c11
-rw-r--r--drivers/iio/chemical/sgp40.c2
-rw-r--r--drivers/iio/chemical/sps30.c24
-rw-r--r--drivers/iio/chemical/sps30_i2c.c7
-rw-r--r--drivers/iio/chemical/sps30_serial.c5
-rw-r--r--drivers/iio/chemical/sunrise_co2.c1
-rw-r--r--drivers/iio/chemical/vz89x.c5
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_activity.c8
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c1
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c11
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-attributes.c83
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c55
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.h2
-rw-r--r--drivers/iio/common/inv_sensors/inv_sensors_timestamp.c111
-rw-r--r--drivers/iio/common/ms_sensors/ms_sensors_i2c.c2
-rw-r--r--drivers/iio/common/scmi_sensors/scmi_iio.c13
-rw-r--r--drivers/iio/common/ssp_sensors/ssp_dev.c4
-rw-r--r--drivers/iio/common/ssp_sensors/ssp_iio_sensor.h12
-rw-r--r--drivers/iio/common/ssp_sensors/ssp_spi.c8
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c34
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_trigger.c4
-rw-r--r--drivers/iio/dac/Kconfig74
-rw-r--r--drivers/iio/dac/Makefile3
-rw-r--r--drivers/iio/dac/ad3530r.c414
-rw-r--r--drivers/iio/dac/ad3552r-hs.c5
-rw-r--r--drivers/iio/dac/ad3552r.c7
-rw-r--r--drivers/iio/dac/ad5064.c126
-rw-r--r--drivers/iio/dac/ad5360.c45
-rw-r--r--drivers/iio/dac/ad5380.c64
-rw-r--r--drivers/iio/dac/ad5446-i2c.c15
-rw-r--r--drivers/iio/dac/ad5446-spi.c63
-rw-r--r--drivers/iio/dac/ad5449.c14
-rw-r--r--drivers/iio/dac/ad5504.c43
-rw-r--r--drivers/iio/dac/ad5592r.c1
-rw-r--r--drivers/iio/dac/ad5593r.c1
-rw-r--r--drivers/iio/dac/ad5624r_spi.c12
-rw-r--r--drivers/iio/dac/ad5686-spi.c231
-rw-r--r--drivers/iio/dac/ad5686.c825
-rw-r--r--drivers/iio/dac/ad5686.h181
-rw-r--r--drivers/iio/dac/ad5696-i2c.c107
-rw-r--r--drivers/iio/dac/ad5706r.c252
-rw-r--r--drivers/iio/dac/ad5755.c15
-rw-r--r--drivers/iio/dac/ad5758.c7
-rw-r--r--drivers/iio/dac/ad5761.c8
-rw-r--r--drivers/iio/dac/ad5764.c8
-rw-r--r--drivers/iio/dac/ad5766.c4
-rw-r--r--drivers/iio/dac/ad5770r.c4
-rw-r--r--drivers/iio/dac/ad5791.c10
-rw-r--r--drivers/iio/dac/ad7293.c34
-rw-r--r--drivers/iio/dac/ad7303.c7
-rw-r--r--drivers/iio/dac/ad8460.c2
-rw-r--r--drivers/iio/dac/ad8801.c4
-rw-r--r--drivers/iio/dac/ad9739a.c3
-rw-r--r--drivers/iio/dac/adi-axi-dac.c4
-rw-r--r--drivers/iio/dac/dpot-dac.c2
-rw-r--r--drivers/iio/dac/ds4424.c373
-rw-r--r--drivers/iio/dac/lpc18xx_dac.c1
-rw-r--r--drivers/iio/dac/ltc1660.c4
-rw-r--r--drivers/iio/dac/ltc2632.c353
-rw-r--r--drivers/iio/dac/ltc2664.c9
-rw-r--r--drivers/iio/dac/ltc2688.c3
-rw-r--r--drivers/iio/dac/m62332.c19
-rw-r--r--drivers/iio/dac/max22007.c3
-rw-r--r--drivers/iio/dac/max517.c10
-rw-r--r--drivers/iio/dac/max5522.c54
-rw-r--r--drivers/iio/dac/max5821.c15
-rw-r--r--drivers/iio/dac/mcf54415_dac.c180
-rw-r--r--drivers/iio/dac/mcp4725.c5
-rw-r--r--drivers/iio/dac/mcp4728.c3
-rw-r--r--drivers/iio/dac/mcp47a1.c166
-rw-r--r--drivers/iio/dac/mcp47feb02.c131
-rw-r--r--drivers/iio/dac/mcp4821.c146
-rw-r--r--drivers/iio/dac/mcp4922.c8
-rw-r--r--drivers/iio/dac/rohm-bd79703.c8
-rw-r--r--drivers/iio/dac/stm32-dac-core.c1
-rw-r--r--drivers/iio/dac/stm32-dac.c1
-rw-r--r--drivers/iio/dac/ti-dac082s085.c13
-rw-r--r--drivers/iio/dac/ti-dac5571.c24
-rw-r--r--drivers/iio/dac/ti-dac7311.c6
-rw-r--r--drivers/iio/dac/ti-dac7612.c2
-rw-r--r--drivers/iio/dac/vf610_dac.c1
-rw-r--r--drivers/iio/filter/admv8818.c63
-rw-r--r--drivers/iio/flow/Kconfig22
-rw-r--r--drivers/iio/flow/Makefile7
-rw-r--r--drivers/iio/flow/slf3s.c542
-rw-r--r--drivers/iio/frequency/Kconfig10
-rw-r--r--drivers/iio/frequency/Makefile1
-rw-r--r--drivers/iio/frequency/ad9523.c113
-rw-r--r--drivers/iio/frequency/adf41513.c1246
-rw-r--r--drivers/iio/frequency/adf4350.c15
-rw-r--r--drivers/iio/frequency/adf4371.c4
-rw-r--r--drivers/iio/frequency/adf4377.c141
-rw-r--r--drivers/iio/frequency/admfm2000.c1
-rw-r--r--drivers/iio/frequency/admv1013.c107
-rw-r--r--drivers/iio/frequency/admv1014.c92
-rw-r--r--drivers/iio/frequency/admv4420.c37
-rw-r--r--drivers/iio/frequency/adrf6780.c70
-rw-r--r--drivers/iio/gyro/adis16080.c4
-rw-r--r--drivers/iio/gyro/adis16136.c8
-rw-r--r--drivers/iio/gyro/adis16260.c15
-rw-r--r--drivers/iio/gyro/adxrs290.c80
-rw-r--r--drivers/iio/gyro/adxrs450.c4
-rw-r--r--drivers/iio/gyro/bmg160_core.c16
-rw-r--r--drivers/iio/gyro/bmg160_i2c.c7
-rw-r--r--drivers/iio/gyro/bmg160_spi.c7
-rw-r--r--drivers/iio/gyro/fxas21002c_i2c.c3
-rw-r--r--drivers/iio/gyro/fxas21002c_spi.c3
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c91
-rw-r--r--drivers/iio/gyro/itg3200_buffer.c2
-rw-r--r--drivers/iio/gyro/itg3200_core.c2
-rw-r--r--drivers/iio/gyro/mpu3050-core.c34
-rw-r--r--drivers/iio/gyro/mpu3050-i2c.c2
-rw-r--r--drivers/iio/gyro/ssp_gyro_sensor.c2
-rw-r--r--drivers/iio/gyro/st_gyro_i2c.c19
-rw-r--r--drivers/iio/gyro/st_gyro_spi.c19
-rw-r--r--drivers/iio/health/afe4403.c6
-rw-r--r--drivers/iio/health/afe4404.c6
-rw-r--r--drivers/iio/health/max30100.c6
-rw-r--r--drivers/iio/health/max30102.c11
-rw-r--r--drivers/iio/humidity/am2315.c2
-rw-r--r--drivers/iio/humidity/dht11.c1
-rw-r--r--drivers/iio/humidity/ens210.c32
-rw-r--r--drivers/iio/humidity/hdc100x.c13
-rw-r--r--drivers/iio/humidity/hdc2010.c5
-rw-r--r--drivers/iio/humidity/hdc3020.c9
-rw-r--r--drivers/iio/humidity/hid-sensor-humidity.c36
-rw-r--r--drivers/iio/humidity/hts221_buffer.c5
-rw-r--r--drivers/iio/humidity/hts221_i2c.c3
-rw-r--r--drivers/iio/humidity/hts221_spi.c2
-rw-r--r--drivers/iio/humidity/htu21.c5
-rw-r--r--drivers/iio/humidity/si7005.c4
-rw-r--r--drivers/iio/humidity/si7020.c5
-rw-r--r--drivers/iio/iio_core_trigger.h2
-rw-r--r--drivers/iio/imu/Kconfig1
-rw-r--r--drivers/iio/imu/Makefile1
-rw-r--r--drivers/iio/imu/adis16400.c30
-rw-r--r--drivers/iio/imu/adis16460.c2
-rw-r--r--drivers/iio/imu/adis16475.c55
-rw-r--r--drivers/iio/imu/adis16480.c45
-rw-r--r--drivers/iio/imu/adis16550.c100
-rw-r--r--drivers/iio/imu/adis_trigger.c2
-rw-r--r--drivers/iio/imu/bmi160/bmi160_core.c20
-rw-r--r--drivers/iio/imu/bmi160/bmi160_i2c.c5
-rw-r--r--drivers/iio/imu/bmi160/bmi160_spi.c5
-rw-r--r--drivers/iio/imu/bmi270/bmi270_core.c2
-rw-r--r--drivers/iio/imu/bmi270/bmi270_i2c.c5
-rw-r--r--drivers/iio/imu/bmi270/bmi270_spi.c6
-rw-r--r--drivers/iio/imu/bmi323/bmi323_core.c5
-rw-r--r--drivers/iio/imu/bmi323/bmi323_i2c.c3
-rw-r--r--drivers/iio/imu/bmi323/bmi323_spi.c3
-rw-r--r--drivers/iio/imu/bno055/bno055.c29
-rw-r--r--drivers/iio/imu/bno055/bno055_i2c.c3
-rw-r--r--drivers/iio/imu/bno055/bno055_ser_core.c5
-rw-r--r--drivers/iio/imu/fxos8700_core.c2
-rw-r--r--drivers/iio/imu/fxos8700_i2c.c3
-rw-r--r--drivers/iio/imu/fxos8700_spi.c3
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600.h10
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c24
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c54
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h4
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_core.c12
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c20
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c21
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c21
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c3
-rw-r--r--drivers/iio/imu/inv_icm42607/Kconfig30
-rw-r--r--drivers/iio/imu/inv_icm42607/Makefile13
-rw-r--r--drivers/iio/imu/inv_icm42607/inv_icm42607.h421
-rw-r--r--drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c316
-rw-r--r--drivers/iio/imu/inv_icm42607/inv_icm42607_core.c702
-rw-r--r--drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c313
-rw-r--r--drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c97
-rw-r--r--drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c107
-rw-r--r--drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c99
-rw-r--r--drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h38
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600.h2
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c7
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600_core.c2
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c19
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c1
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c17
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c37
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c6
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c35
-rw-r--r--drivers/iio/imu/kmx61.c132
-rw-r--r--drivers/iio/imu/smi240.c2
-rw-r--r--drivers/iio/imu/smi330/smi330_i2c.c1
-rw-r--r--drivers/iio/imu/smi330/smi330_spi.c1
-rw-r--r--drivers/iio/imu/st_lsm6dsx/Makefile2
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h28
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c56
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c84
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c246
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c49
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c1
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c48
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c5
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c5
-rw-r--r--drivers/iio/industrialio-backend.c85
-rw-r--r--drivers/iio/industrialio-buffer.c87
-rw-r--r--drivers/iio/industrialio-core.c56
-rw-r--r--drivers/iio/industrialio-event.c6
-rw-r--r--drivers/iio/industrialio-trigger.c33
-rw-r--r--drivers/iio/inkern.c62
-rw-r--r--drivers/iio/light/Kconfig30
-rw-r--r--drivers/iio/light/Makefile2
-rw-r--r--drivers/iio/light/acpi-als.c46
-rw-r--r--drivers/iio/light/adjd_s311.c2
-rw-r--r--drivers/iio/light/adux1020.c6
-rw-r--r--drivers/iio/light/al3000a.c3
-rw-r--r--drivers/iio/light/al3010.c13
-rw-r--r--drivers/iio/light/al3320a.c11
-rw-r--r--drivers/iio/light/apds9160.c11
-rw-r--r--drivers/iio/light/apds9300.c6
-rw-r--r--drivers/iio/light/apds9306.c15
-rw-r--r--drivers/iio/light/apds9960.c6
-rw-r--r--drivers/iio/light/apds9999.c332
-rw-r--r--drivers/iio/light/as73211.c7
-rw-r--r--drivers/iio/light/bh1745.c5
-rw-r--r--drivers/iio/light/bh1750.c10
-rw-r--r--drivers/iio/light/bh1780.c3
-rw-r--r--drivers/iio/light/cm32181.c3
-rw-r--r--drivers/iio/light/cm3232.c6
-rw-r--r--drivers/iio/light/cm3323.c24
-rw-r--r--drivers/iio/light/cm3605.c6
-rw-r--r--drivers/iio/light/cm36651.c2
-rw-r--r--drivers/iio/light/cros_ec_light_prox.c9
-rw-r--r--drivers/iio/light/gp2ap002.c33
-rw-r--r--drivers/iio/light/gp2ap020a00f.c311
-rw-r--r--drivers/iio/light/hid-sensor-als.c93
-rw-r--r--drivers/iio/light/hid-sensor-prox.c69
-rw-r--r--drivers/iio/light/iqs621-als.c111
-rw-r--r--drivers/iio/light/isl29018.c7
-rw-r--r--drivers/iio/light/isl29028.c26
-rw-r--r--drivers/iio/light/isl29125.c2
-rw-r--r--drivers/iio/light/isl76682.c2
-rw-r--r--drivers/iio/light/jsa1212.c3
-rw-r--r--drivers/iio/light/ltr390.c7
-rw-r--r--drivers/iio/light/ltr501.c20
-rw-r--r--drivers/iio/light/ltrf216a.c8
-rw-r--r--drivers/iio/light/lv0104cs.c2
-rw-r--r--drivers/iio/light/max44000.c3
-rw-r--r--drivers/iio/light/max44009.c2
-rw-r--r--drivers/iio/light/noa1305.c2
-rw-r--r--drivers/iio/light/opt3001.c562
-rw-r--r--drivers/iio/light/opt4001.c41
-rw-r--r--drivers/iio/light/opt4060.c13
-rw-r--r--drivers/iio/light/pa12203001.c2
-rw-r--r--drivers/iio/light/rpr0521.c13
-rw-r--r--drivers/iio/light/si1133.c71
-rw-r--r--drivers/iio/light/si1145.c18
-rw-r--r--drivers/iio/light/st_uvis25_core.c5
-rw-r--r--drivers/iio/light/st_uvis25_i2c.c3
-rw-r--r--drivers/iio/light/st_uvis25_spi.c3
-rw-r--r--drivers/iio/light/stk3310.c117
-rw-r--r--drivers/iio/light/tcs3414.c2
-rw-r--r--drivers/iio/light/tcs3472.c490
-rw-r--r--drivers/iio/light/tsl2563.c11
-rw-r--r--drivers/iio/light/tsl2583.c50
-rw-r--r--drivers/iio/light/tsl2591.c129
-rw-r--r--drivers/iio/light/tsl2772.c47
-rw-r--r--drivers/iio/light/tsl4531.c2
-rw-r--r--drivers/iio/light/us5182d.c3
-rw-r--r--drivers/iio/light/vcnl4000.c521
-rw-r--r--drivers/iio/light/vcnl4035.c43
-rw-r--r--drivers/iio/light/veml3235.c2
-rw-r--r--drivers/iio/light/veml3328.c422
-rw-r--r--drivers/iio/light/veml6030.c24
-rw-r--r--drivers/iio/light/veml6040.c2
-rw-r--r--drivers/iio/light/veml6046x00.c3
-rw-r--r--drivers/iio/light/veml6070.c20
-rw-r--r--drivers/iio/light/veml6075.c10
-rw-r--r--drivers/iio/light/vl6180.c5
-rw-r--r--drivers/iio/light/zopt2201.c47
-rw-r--r--drivers/iio/magnetometer/Kconfig33
-rw-r--r--drivers/iio/magnetometer/Makefile4
-rw-r--r--drivers/iio/magnetometer/af8133j.c2
-rw-r--r--drivers/iio/magnetometer/ak8974.c22
-rw-r--r--drivers/iio/magnetometer/ak8975.c276
-rw-r--r--drivers/iio/magnetometer/bmc150_magn.c193
-rw-r--r--drivers/iio/magnetometer/bmc150_magn_i2c.c7
-rw-r--r--drivers/iio/magnetometer/bmc150_magn_spi.c7
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c96
-rw-r--r--drivers/iio/magnetometer/hmc5843_i2c.c8
-rw-r--r--drivers/iio/magnetometer/hmc5843_spi.c6
-rw-r--r--drivers/iio/magnetometer/mag3110.c2
-rw-r--r--drivers/iio/magnetometer/mmc35240.c3
-rw-r--r--drivers/iio/magnetometer/mmc5633.c5
-rw-r--r--drivers/iio/magnetometer/mmc5983.c347
-rw-r--r--drivers/iio/magnetometer/qmc5883l.c516
-rw-r--r--drivers/iio/magnetometer/qmc6308.c601
-rw-r--r--drivers/iio/magnetometer/rm3100-core.c98
-rw-r--r--drivers/iio/magnetometer/si7210.c24
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c13
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c19
-rw-r--r--drivers/iio/magnetometer/st_magn_spi.c13
-rw-r--r--drivers/iio/magnetometer/tlv493d.c3
-rw-r--r--drivers/iio/magnetometer/tmag5273.c2
-rw-r--r--drivers/iio/magnetometer/yamaha-yas530.c45
-rw-r--r--drivers/iio/multiplexer/iio-mux.c2
-rw-r--r--drivers/iio/orientation/hid-sensor-incl-3d.c56
-rw-r--r--drivers/iio/orientation/hid-sensor-rotation.c184
-rw-r--r--drivers/iio/position/hid-sensor-custom-intel-hinge.c20
-rw-r--r--drivers/iio/potentiometer/ad5272.c11
-rw-r--r--drivers/iio/potentiometer/ds1803.c9
-rw-r--r--drivers/iio/potentiometer/max5432.c1
-rw-r--r--drivers/iio/potentiometer/max5481.c9
-rw-r--r--drivers/iio/potentiometer/max5487.c7
-rw-r--r--drivers/iio/potentiometer/mcp4018.c1
-rw-r--r--drivers/iio/potentiometer/mcp41010.c13
-rw-r--r--drivers/iio/potentiometer/mcp4131.c129
-rw-r--r--drivers/iio/potentiometer/mcp4531.c1
-rw-r--r--drivers/iio/potentiometer/tpl0102.c8
-rw-r--r--drivers/iio/potentiometer/x9250.c4
-rw-r--r--drivers/iio/potentiostat/lmp91000.c6
-rw-r--r--drivers/iio/pressure/abp060mg.c90
-rw-r--r--drivers/iio/pressure/abp2030pa.c3
-rw-r--r--drivers/iio/pressure/abp2030pa_i2c.c3
-rw-r--r--drivers/iio/pressure/abp2030pa_spi.c3
-rw-r--r--drivers/iio/pressure/adp810.c3
-rw-r--r--drivers/iio/pressure/bmp280-core.c40
-rw-r--r--drivers/iio/pressure/bmp280-i2c.c12
-rw-r--r--drivers/iio/pressure/bmp280-spi.c16
-rw-r--r--drivers/iio/pressure/cros_ec_baro.c9
-rw-r--r--drivers/iio/pressure/dlhl60d.c8
-rw-r--r--drivers/iio/pressure/dps310.c5
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c77
-rw-r--r--drivers/iio/pressure/hp03.c2
-rw-r--r--drivers/iio/pressure/hp206c.c3
-rw-r--r--drivers/iio/pressure/hsc030pa.c3
-rw-r--r--drivers/iio/pressure/hsc030pa_i2c.c10
-rw-r--r--drivers/iio/pressure/hsc030pa_spi.c3
-rw-r--r--drivers/iio/pressure/icp10100.c3
-rw-r--r--drivers/iio/pressure/mpl115.c15
-rw-r--r--drivers/iio/pressure/mpl115_i2c.c2
-rw-r--r--drivers/iio/pressure/mpl115_spi.c2
-rw-r--r--drivers/iio/pressure/mpl3115.c2
-rw-r--r--drivers/iio/pressure/mprls0025pa.c1
-rw-r--r--drivers/iio/pressure/mprls0025pa_i2c.c3
-rw-r--r--drivers/iio/pressure/mprls0025pa_spi.c3
-rw-r--r--drivers/iio/pressure/ms5611_i2c.c5
-rw-r--r--drivers/iio/pressure/ms5611_spi.c5
-rw-r--r--drivers/iio/pressure/ms5637.c9
-rw-r--r--drivers/iio/pressure/rohm-bm1390.c29
-rw-r--r--drivers/iio/pressure/sdp500.c3
-rw-r--r--drivers/iio/pressure/st_pressure_i2c.c17
-rw-r--r--drivers/iio/pressure/st_pressure_spi.c25
-rw-r--r--drivers/iio/pressure/t5403.c2
-rw-r--r--drivers/iio/pressure/zpa2326.c7
-rw-r--r--drivers/iio/pressure/zpa2326_i2c.c3
-rw-r--r--drivers/iio/pressure/zpa2326_spi.c3
-rw-r--r--drivers/iio/proximity/Kconfig15
-rw-r--r--drivers/iio/proximity/Makefile1
-rw-r--r--drivers/iio/proximity/as3935.c7
-rw-r--r--drivers/iio/proximity/aw96103.c4
-rw-r--r--drivers/iio/proximity/cros_ec_mkbp_proximity.c1
-rw-r--r--drivers/iio/proximity/d3323aa.c3
-rw-r--r--drivers/iio/proximity/hx9023s.c10
-rw-r--r--drivers/iio/proximity/irsd200.c2
-rw-r--r--drivers/iio/proximity/isl29501.c3
-rw-r--r--drivers/iio/proximity/mb1232.c19
-rw-r--r--drivers/iio/proximity/ping.c1
-rw-r--r--drivers/iio/proximity/pulsedlight-lidar-lite-v2.c5
-rw-r--r--drivers/iio/proximity/rfd77402.c9
-rw-r--r--drivers/iio/proximity/srf04.c6
-rw-r--r--drivers/iio/proximity/srf08.c23
-rw-r--r--drivers/iio/proximity/sx9310.c5
-rw-r--r--drivers/iio/proximity/sx9324.c9
-rw-r--r--drivers/iio/proximity/sx9360.c9
-rw-r--r--drivers/iio/proximity/sx9500.c2
-rw-r--r--drivers/iio/proximity/sx_common.c2
-rw-r--r--drivers/iio/proximity/vcnl3020.c6
-rw-r--r--drivers/iio/proximity/vl53l0x-i2c.c13
-rw-r--r--drivers/iio/proximity/vl53l1x-i2c.c756
-rw-r--r--drivers/iio/resolver/ad2s1200.c21
-rw-r--r--drivers/iio/resolver/ad2s1210.c38
-rw-r--r--drivers/iio/resolver/ad2s90.c2
-rw-r--r--drivers/iio/temperature/Makefile2
-rw-r--r--drivers/iio/temperature/hid-sensor-temperature.c38
-rw-r--r--drivers/iio/temperature/ltc2983.c634
-rw-r--r--drivers/iio/temperature/max30208.c2
-rw-r--r--drivers/iio/temperature/max31856.c3
-rw-r--r--drivers/iio/temperature/max31865.c3
-rw-r--r--drivers/iio/temperature/maxim_thermocouple.c25
-rw-r--r--drivers/iio/temperature/mcp9600.c7
-rw-r--r--drivers/iio/temperature/mlx90614.c5
-rw-r--r--drivers/iio/temperature/mlx90632.c3
-rw-r--r--drivers/iio/temperature/mlx90635.c3
-rw-r--r--drivers/iio/temperature/tmp006.c5
-rw-r--r--drivers/iio/temperature/tmp007.c7
-rw-r--r--drivers/iio/temperature/tmp117.c17
-rw-r--r--drivers/iio/temperature/tsys01.c5
-rw-r--r--drivers/iio/temperature/tsys02d.c2
-rw-r--r--drivers/iio/test/iio-test-format.c97
-rw-r--r--drivers/iio/test/iio-test-gts.c2
-rw-r--r--drivers/iio/test/iio-test-rescale.c2
-rw-r--r--drivers/iio/trigger/Kconfig9
-rw-r--r--drivers/iio/trigger/Makefile1
-rw-r--r--drivers/iio/trigger/iio-trig-interrupt.c109
-rw-r--r--drivers/iio/trigger/stm32-lptimer-trigger.c1
-rw-r--r--drivers/iio/trigger/stm32-timer-trigger.c1
660 files changed, 26342 insertions, 8417 deletions
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 661127aed2f9..652557a5b851 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -92,6 +92,7 @@ source "drivers/iio/common/Kconfig"
source "drivers/iio/dac/Kconfig"
source "drivers/iio/dummy/Kconfig"
source "drivers/iio/filter/Kconfig"
+source "drivers/iio/flow/Kconfig"
source "drivers/iio/frequency/Kconfig"
source "drivers/iio/gyro/Kconfig"
source "drivers/iio/health/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index cb80ef837e84..f03a4100c800 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -29,6 +29,7 @@ obj-y += dac/
obj-y += dummy/
obj-y += gyro/
obj-y += filter/
+obj-y += flow/
obj-y += frequency/
obj-y += health/
obj-y += humidity/
diff --git a/drivers/iio/TODO b/drivers/iio/TODO
index 2ace27d1ac62..7b05308248d7 100644
--- a/drivers/iio/TODO
+++ b/drivers/iio/TODO
@@ -5,12 +5,17 @@ Documentation
tree
- Yaml conversions for abandoned drivers
- ABI Documentation
- - Audit driviers/iio/staging/Documentation
+ - Audit drivers/staging/iio/Documentation
-- Converting drivers from device tree centric to more generic
-property handlers.
+- Converting drivers from device tree centric to generic property handlers.
- Refactor old platform_data constructs from drivers and convert it
-to state struct and using property handlers and readers.
+ to state struct and using property handlers and readers.
+
+- Convert selected IIO drivers to use fully device managed resource APIs.
+
+- Evaluate and possibly adopt cleanup.h helpers (guard()(), __free(), et cetera)
+ in drivers where manual resource management is still used and there is a
+ significant improvement to the code flow and complexity to be had.
Mailing list: linux-iio@vger.kernel.org
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 3d3f8d8673dd..4094299e2ed8 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -158,24 +158,24 @@ config ADXL372
select IIO_TRIGGERED_BUFFER
config ADXL372_SPI
- tristate "Analog Devices ADXL372 3-Axis Accelerometer SPI Driver"
+ tristate "Analog Devices ADXL371/ADXL372 3-Axis Accelerometer SPI Driver"
depends on SPI
select ADXL372
select REGMAP_SPI
help
- Say yes here to add support for the Analog Devices ADXL372 triaxial
- acceleration sensor.
+ Say yes here to add support for the Analog Devices ADXL371/ADXL372
+ triaxial acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called adxl372_spi.
config ADXL372_I2C
- tristate "Analog Devices ADXL372 3-Axis Accelerometer I2C Driver"
+ tristate "Analog Devices ADXL371/ADXL372 3-Axis Accelerometer I2C Driver"
depends on I2C
select ADXL372
select REGMAP_I2C
help
- Say yes here to add support for the Analog Devices ADXL372 triaxial
- acceleration sensor.
+ Say yes here to add support for the Analog Devices ADXL371/ADXL372
+ triaxial acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called adxl372_i2c.
diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c
index 5127e58eebc7..ba0f97944c6d 100644
--- a/drivers/iio/accel/adis16201.c
+++ b/drivers/iio/accel/adis16201.c
@@ -147,7 +147,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
/*
* The raw ADC value is 1278 when the temperature
* is 25 degrees and the scale factor per milli
- * degree celcius is -470.
+ * degree Celsius is -470.
*/
*val = 25000 / -470 - 1278;
return IIO_VAL_INT;
diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c
index 41ffd92f27fd..04e169f221c4 100644
--- a/drivers/iio/accel/adis16209.c
+++ b/drivers/iio/accel/adis16209.c
@@ -186,7 +186,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
/*
* The raw ADC value is 0x4FE when the temperature
* is 45 degrees and the scale factor per milli
- * degree celcius is -470.
+ * degree Celsius is -470.
*/
*val = 25000 / -470 - 0x4FE;
return IIO_VAL_INT;
diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c
index 9f5d4d2cb325..6dc918c4ae17 100644
--- a/drivers/iio/accel/adxl313_core.c
+++ b/drivers/iio/accel/adxl313_core.c
@@ -8,6 +8,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/overflow.h>
@@ -356,19 +357,15 @@ static int adxl313_read_axis(struct adxl313_data *data,
{
int ret;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
ret = regmap_bulk_read(data->regmap,
ADXL313_REG_DATA_AXIS(chan->address),
&data->transf_buf, sizeof(data->transf_buf));
if (ret)
- goto unlock_ret;
-
- ret = le16_to_cpu(data->transf_buf);
+ return ret;
-unlock_ret:
- mutex_unlock(&data->lock);
- return ret;
+ return le16_to_cpu(data->transf_buf);
}
static int adxl313_read_freq_avail(struct iio_dev *indio_dev,
@@ -998,6 +995,8 @@ static int adxl313_buffer_predisable(struct iio_dev *indio_dev)
ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL,
FIELD_PREP(ADXL313_REG_FIFO_CTL_MODE_MSK, ADXL313_FIFO_BYPASS));
+ if (ret)
+ return ret;
ret = regmap_write(data->regmap, ADXL313_REG_INT_ENABLE, 0);
if (ret)
@@ -1241,7 +1240,9 @@ int adxl313_core_probe(struct device *dev,
data->regmap = regmap;
data->chip_info = chip_info;
- mutex_init(&data->lock);
+ ret = devm_mutex_init(dev, &data->lock);
+ if (ret)
+ return ret;
indio_dev->name = chip_info->name;
indio_dev->info = &adxl313_info;
@@ -1251,10 +1252,8 @@ int adxl313_core_probe(struct device *dev,
indio_dev->available_scan_masks = adxl313_scan_masks;
ret = adxl313_setup(dev, data, setup);
- if (ret) {
- dev_err(dev, "ADXL313 setup failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "ADXL313 setup failed\n");
int_line = adxl313_get_int_type(dev, &irq);
if (int_line == ADXL313_INT_NONE) {
diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c
index b67ff0b4dc54..2eea8d4d044b 100644
--- a/drivers/iio/accel/adxl313_i2c.c
+++ b/drivers/iio/accel/adxl313_i2c.c
@@ -8,7 +8,6 @@
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -65,6 +64,7 @@ MODULE_DEVICE_TABLE(of, adxl313_of_match);
static int adxl313_i2c_probe(struct i2c_client *client)
{
const struct adxl313_chip_info *chip_data;
+ struct device *dev = &client->dev;
struct regmap *regmap;
/*
@@ -75,13 +75,10 @@ static int adxl313_i2c_probe(struct i2c_client *client)
regmap = devm_regmap_init_i2c(client,
&adxl31x_i2c_regmap_config[chip_data->type]);
- if (IS_ERR(regmap)) {
- dev_err(&client->dev, "Error initializing i2c regmap: %ld\n",
- PTR_ERR(regmap));
- return PTR_ERR(regmap);
- }
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing i2c regmap\n");
- return adxl313_core_probe(&client->dev, regmap, chip_data, NULL);
+ return adxl313_core_probe(dev, regmap, chip_data, NULL);
}
static struct i2c_driver adxl313_i2c_driver = {
diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c
index dedb0885c277..a61295de104f 100644
--- a/drivers/iio/accel/adxl313_spi.c
+++ b/drivers/iio/accel/adxl313_spi.c
@@ -7,7 +7,6 @@
* Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf
*/
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -70,6 +69,7 @@ static int adxl313_spi_setup(struct device *dev, struct regmap *regmap)
static int adxl313_spi_probe(struct spi_device *spi)
{
const struct adxl313_chip_info *chip_data;
+ struct device *dev = &spi->dev;
struct regmap *regmap;
int ret;
@@ -83,14 +83,10 @@ static int adxl313_spi_probe(struct spi_device *spi)
regmap = devm_regmap_init_spi(spi,
&adxl31x_spi_regmap_config[chip_data->type]);
- if (IS_ERR(regmap)) {
- dev_err(&spi->dev, "Error initializing spi regmap: %ld\n",
- PTR_ERR(regmap));
- return PTR_ERR(regmap);
- }
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing spi regmap\n");
- return adxl313_core_probe(&spi->dev, regmap,
- chip_data, &adxl313_spi_setup);
+ return adxl313_core_probe(dev, regmap, chip_data, &adxl313_spi_setup);
}
static const struct spi_device_id adxl313_spi_id[] = {
diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
index 78e3f799ecc1..6c9080d88c60 100644
--- a/drivers/iio/accel/adxl345_core.c
+++ b/drivers/iio/accel/adxl345_core.c
@@ -213,6 +213,7 @@ static const struct iio_event_spec adxl345_events[] = {
.dir = IIO_EV_DIR_RISING,
.mask_shared_by_type =
BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_SCALE) |
BIT(IIO_EV_INFO_VALUE),
},
{
@@ -221,6 +222,7 @@ static const struct iio_event_spec adxl345_events[] = {
.dir = IIO_EV_DIR_RISING,
.mask_shared_by_type =
BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_SCALE) |
BIT(IIO_EV_INFO_VALUE),
},
{
@@ -228,14 +230,19 @@ static const struct iio_event_spec adxl345_events[] = {
.type = IIO_EV_TYPE_GESTURE,
.dir = IIO_EV_DIR_SINGLETAP,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
- .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
+ .mask_shared_by_type =
+ BIT(IIO_EV_INFO_SCALE) |
+ BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_TIMEOUT),
},
{
/* double tap */
.type = IIO_EV_TYPE_GESTURE,
.dir = IIO_EV_DIR_DOUBLETAP,
- .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
+ .mask_shared_by_type =
+ BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_SCALE) |
+ BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_RESET_TIMEOUT) |
BIT(IIO_EV_INFO_TAP2_MIN_DELAY),
},
@@ -274,6 +281,7 @@ static const struct iio_event_spec adxl345_fake_chan_events[] = {
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
.mask_shared_by_type =
+ BIT(IIO_EV_INFO_SCALE) |
BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_PERIOD),
},
@@ -283,6 +291,7 @@ static const struct iio_event_spec adxl345_fake_chan_events[] = {
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
.mask_shared_by_type =
+ BIT(IIO_EV_INFO_SCALE) |
BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_PERIOD),
},
@@ -1341,6 +1350,16 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev,
unsigned int tap_threshold;
int ret;
+ /*
+ * The event threshold LSB is fixed at 62.5 mg/LSB
+ * 0.0625 * 9.80665 = 0.612915625 m/s^2
+ */
+ if (info == IIO_EV_INFO_SCALE) {
+ *val = 0;
+ *val2 = 612915;
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+
switch (type) {
case IIO_EV_TYPE_MAG:
return adxl345_read_mag_value(st, dir, info,
@@ -1355,12 +1374,6 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev,
case IIO_EV_TYPE_GESTURE:
switch (info) {
case IIO_EV_INFO_VALUE:
- /*
- * The scale factor would be 62.5mg/LSB (i.e. 0xFF = 16g) but
- * not applied here. In context of this general purpose sensor,
- * what imports is rather signal intensity than the absolute
- * measured g value.
- */
ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP,
&tap_threshold);
if (ret)
@@ -1401,6 +1414,9 @@ static int adxl345_write_event_value(struct iio_dev *indio_dev,
if (ret)
return ret;
+ if (info == IIO_EV_INFO_SCALE)
+ return -EINVAL;
+
switch (type) {
case IIO_EV_TYPE_MAG:
ret = adxl345_write_mag_value(st, dir, info,
diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c
index af84c0043c6c..511fb610436c 100644
--- a/drivers/iio/accel/adxl345_i2c.c
+++ b/drivers/iio/accel/adxl345_i2c.c
@@ -43,8 +43,8 @@ static const struct adxl345_chip_info adxl375_i2c_info = {
};
static const struct i2c_device_id adxl345_i2c_id[] = {
- { "adxl345", (kernel_ulong_t)&adxl345_i2c_info },
- { "adxl375", (kernel_ulong_t)&adxl375_i2c_info },
+ { .name = "adxl345", .driver_data = (kernel_ulong_t)&adxl345_i2c_info },
+ { .name = "adxl375", .driver_data = (kernel_ulong_t)&adxl375_i2c_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id);
diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c
index 0315f4bfd69a..4fa1b04f75b6 100644
--- a/drivers/iio/accel/adxl345_spi.c
+++ b/drivers/iio/accel/adxl345_spi.c
@@ -60,8 +60,8 @@ static const struct adxl345_chip_info adxl375_spi_info = {
};
static const struct spi_device_id adxl345_spi_id[] = {
- { "adxl345", (kernel_ulong_t)&adxl345_spi_info },
- { "adxl375", (kernel_ulong_t)&adxl375_spi_info },
+ { .name = "adxl345", .driver_data = (kernel_ulong_t)&adxl345_spi_info },
+ { .name = "adxl375", .driver_data = (kernel_ulong_t)&adxl375_spi_info },
{ }
};
MODULE_DEVICE_TABLE(spi, adxl345_spi_id);
diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c
index 1c1d64d5cbcb..080c9f6f9a11 100644
--- a/drivers/iio/accel/adxl355_core.c
+++ b/drivers/iio/accel/adxl355_core.c
@@ -17,7 +17,6 @@
#include <linux/limits.h>
#include <linux/math64.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/units.h>
@@ -336,10 +335,8 @@ static int adxl355_setup(struct adxl355_data *data)
return ret;
do {
- if (--retries == 0) {
- dev_err(data->dev, "Shadow registers mismatch\n");
- return -EIO;
- }
+ if (--retries == 0)
+ return dev_err_probe(data->dev, -EIO, "Shadow registers mismatch\n");
/*
* Perform a software reset to make sure the device is in a consistent
@@ -351,7 +348,7 @@ static int adxl355_setup(struct adxl355_data *data)
return ret;
/* Wait at least 5ms after software reset */
- usleep_range(5000, 10000);
+ fsleep(5 * USEC_PER_MSEC);
/* Read shadow registers for comparison */
ret = regmap_bulk_read(data->regmap,
@@ -745,7 +742,7 @@ static const struct iio_chan_spec adxl355_channels[] = {
BIT(IIO_CHAN_INFO_OFFSET),
.scan_index = 3,
.scan_type = {
- .sign = 's',
+ .sign = 'u',
.realbits = 12,
.storagebits = 16,
.endianness = IIO_BE,
@@ -771,14 +768,11 @@ static int adxl355_probe_trigger(struct iio_dev *indio_dev, int irq)
ret = devm_request_irq(data->dev, irq, &iio_trigger_generic_data_rdy_poll,
IRQF_NO_THREAD, "adxl355_irq", data->dready_trig);
if (ret)
- return dev_err_probe(data->dev, ret, "request irq %d failed\n",
- irq);
+ return ret;
ret = devm_iio_trigger_register(data->dev, data->dready_trig);
- if (ret) {
- dev_err(data->dev, "iio trigger register failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(data->dev, ret, "iio trigger register failed\n");
indio_dev->trig = iio_trigger_get(data->dready_trig);
@@ -802,7 +796,9 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap,
data->dev = dev;
data->op_mode = ADXL355_STANDBY;
data->chip_info = chip_info;
- mutex_init(&data->lock);
+ ret = devm_mutex_init(dev, &data->lock);
+ if (ret)
+ return ret;
indio_dev->name = chip_info->name;
indio_dev->info = &adxl355_info;
@@ -812,18 +808,14 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap,
indio_dev->available_scan_masks = adxl355_avail_scan_masks;
ret = adxl355_setup(data);
- if (ret) {
- dev_err(dev, "ADXL355 setup failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "ADXL355 setup failed\n");
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
&iio_pollfunc_store_time,
&adxl355_trigger_handler, NULL);
- if (ret) {
- dev_err(dev, "iio triggered buffer setup failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "iio triggered buffer setup failed\n");
irq = fwnode_irq_get_byname(dev_fwnode(dev), "DRDY");
if (irq > 0) {
diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c
index 1a512c7b792b..e533a7aabd44 100644
--- a/drivers/iio/accel/adxl355_i2c.c
+++ b/drivers/iio/accel/adxl355_i2c.c
@@ -7,7 +7,6 @@
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include "adxl355.h"
@@ -23,6 +22,7 @@ static const struct regmap_config adxl355_i2c_regmap_config = {
static int adxl355_i2c_probe(struct i2c_client *client)
{
struct regmap *regmap;
+ struct device *dev = &client->dev;
const struct adxl355_chip_info *chip_data;
chip_data = i2c_get_match_data(client);
@@ -30,19 +30,15 @@ static int adxl355_i2c_probe(struct i2c_client *client)
return -ENODEV;
regmap = devm_regmap_init_i2c(client, &adxl355_i2c_regmap_config);
- if (IS_ERR(regmap)) {
- dev_err(&client->dev, "Error initializing i2c regmap: %ld\n",
- PTR_ERR(regmap));
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing i2c regmap\n");
- return PTR_ERR(regmap);
- }
-
- return adxl355_core_probe(&client->dev, regmap, chip_data);
+ return adxl355_core_probe(dev, regmap, chip_data);
}
static const struct i2c_device_id adxl355_i2c_id[] = {
- { "adxl355", (kernel_ulong_t)&adxl35x_chip_info[ADXL355] },
- { "adxl359", (kernel_ulong_t)&adxl35x_chip_info[ADXL359] },
+ { .name = "adxl355", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL355] },
+ { .name = "adxl359", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL359] },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl355_i2c_id);
diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c
index 869e3e57d6f7..d2209ca8ca6e 100644
--- a/drivers/iio/accel/adxl355_spi.c
+++ b/drivers/iio/accel/adxl355_spi.c
@@ -6,7 +6,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/property.h>
@@ -26,6 +25,7 @@ static const struct regmap_config adxl355_spi_regmap_config = {
static int adxl355_spi_probe(struct spi_device *spi)
{
const struct adxl355_chip_info *chip_data;
+ struct device *dev = &spi->dev;
struct regmap *regmap;
chip_data = spi_get_device_match_data(spi);
@@ -33,19 +33,15 @@ static int adxl355_spi_probe(struct spi_device *spi)
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",
- PTR_ERR(regmap));
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing spi regmap\n");
- return PTR_ERR(regmap);
- }
-
- return adxl355_core_probe(&spi->dev, regmap, chip_data);
+ return adxl355_core_probe(dev, regmap, chip_data);
}
static const struct spi_device_id adxl355_spi_id[] = {
- { "adxl355", (kernel_ulong_t)&adxl35x_chip_info[ADXL355] },
- { "adxl359", (kernel_ulong_t)&adxl35x_chip_info[ADXL359] },
+ { .name = "adxl355", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL355] },
+ { .name = "adxl359", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL359] },
{ }
};
MODULE_DEVICE_TABLE(spi, adxl355_spi_id);
diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c
index 0c04b2bb7efb..4ff1c7a0988b 100644
--- a/drivers/iio/accel/adxl367.c
+++ b/drivers/iio/accel/adxl367.c
@@ -13,7 +13,6 @@
#include <linux/iio/sysfs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/unaligned.h>
@@ -1445,7 +1444,9 @@ int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
st->context = context;
st->ops = ops;
- mutex_init(&st->lock);
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
indio_dev->channels = adxl367_channels;
indio_dev->num_channels = ARRAY_SIZE(adxl367_channels);
@@ -1485,7 +1486,7 @@ int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
adxl367_irq_handler, IRQF_ONESHOT,
indio_dev->name, indio_dev);
if (ret)
- return dev_err_probe(st->dev, ret, "Failed to request irq\n");
+ return ret;
return devm_iio_device_register(dev, indio_dev);
}
diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c
index 1c7d2eb054a2..42e747f5d1a1 100644
--- a/drivers/iio/accel/adxl367_i2c.c
+++ b/drivers/iio/accel/adxl367_i2c.c
@@ -5,7 +5,6 @@
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -61,7 +60,7 @@ static int adxl367_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adxl367_i2c_id[] = {
- { "adxl367" },
+ { .name = "adxl367" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id);
diff --git a/drivers/iio/accel/adxl367_spi.c b/drivers/iio/accel/adxl367_spi.c
index 3fed56bb9054..1d1418452bdc 100644
--- a/drivers/iio/accel/adxl367_spi.c
+++ b/drivers/iio/accel/adxl367_spi.c
@@ -4,7 +4,6 @@
* Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
*/
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -138,7 +137,7 @@ static int adxl367_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id adxl367_spi_id[] = {
- { "adxl367", 0 },
+ { .name = "adxl367" },
{ }
};
MODULE_DEVICE_TABLE(spi, adxl367_spi_id);
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
index 28a8793a53b6..e375d068a3f5 100644
--- a/drivers/iio/accel/adxl372.c
+++ b/drivers/iio/accel/adxl372.c
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * ADXL372 3-Axis Digital Accelerometer core driver
+ * ADXL371/ADXL372 3-Axis Digital Accelerometer core driver
*
* Copyright 2018 Analog Devices Inc.
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
@@ -180,6 +181,16 @@ enum adxl372_odr {
ADXL372_ODR_1600HZ,
ADXL372_ODR_3200HZ,
ADXL372_ODR_6400HZ,
+ ADXL372_ODR_NUM
+};
+
+enum adxl371_odr {
+ ADXL371_ODR_320HZ,
+ ADXL371_ODR_640HZ,
+ ADXL371_ODR_1280HZ,
+ ADXL371_ODR_2560HZ,
+ ADXL371_ODR_5120HZ,
+ ADXL371_ODR_NUM
};
enum adxl372_bandwidth {
@@ -214,14 +225,67 @@ enum adxl372_fifo_mode {
ADXL372_FIFO_OLD_SAVED
};
-static const int adxl372_samp_freq_tbl[5] = {
- 400, 800, 1600, 3200, 6400,
+static const int adxl372_samp_freq_tbl[ADXL372_ODR_NUM] = {
+ [ADXL372_ODR_400HZ] = 400,
+ [ADXL372_ODR_800HZ] = 800,
+ [ADXL372_ODR_1600HZ] = 1600,
+ [ADXL372_ODR_3200HZ] = 3200,
+ [ADXL372_ODR_6400HZ] = 6400,
+};
+
+static const int adxl372_bw_freq_tbl[ADXL372_ODR_NUM] = {
+ [ADXL372_BW_200HZ] = 200,
+ [ADXL372_BW_400HZ] = 400,
+ [ADXL372_BW_800HZ] = 800,
+ [ADXL372_BW_1600HZ] = 1600,
+ [ADXL372_BW_3200HZ] = 3200,
+};
+
+static const int adxl371_samp_freq_tbl[ADXL371_ODR_NUM] = {
+ [ADXL371_ODR_320HZ] = 320,
+ [ADXL371_ODR_640HZ] = 640,
+ [ADXL371_ODR_1280HZ] = 1280,
+ [ADXL371_ODR_2560HZ] = 2560,
+ [ADXL371_ODR_5120HZ] = 5120,
};
-static const int adxl372_bw_freq_tbl[5] = {
- 200, 400, 800, 1600, 3200,
+static const int adxl371_bw_freq_tbl[ADXL371_ODR_NUM] = {
+ [ADXL371_ODR_320HZ] = 160,
+ [ADXL371_ODR_640HZ] = 320,
+ [ADXL371_ODR_1280HZ] = 640,
+ [ADXL371_ODR_2560HZ] = 1280,
+ [ADXL371_ODR_5120HZ] = 2560,
};
+const struct adxl372_chip_info adxl371_chip_info = {
+ .name = "adxl371",
+ .samp_freq_tbl = adxl371_samp_freq_tbl,
+ .bw_freq_tbl = adxl371_bw_freq_tbl,
+ .num_freqs = ARRAY_SIZE(adxl371_samp_freq_tbl),
+ .act_time_scale_us = 4125,
+ .act_time_scale_low_us = 8250,
+ .inact_time_scale_ms = 16,
+ .inact_time_scale_low_ms = 32,
+ .max_odr = ADXL371_ODR_5120HZ,
+ /* Silicon erratum (er001) causes FIFO data misalignment on ADXL371 */
+ .fifo_supported = false,
+};
+EXPORT_SYMBOL_NS_GPL(adxl371_chip_info, "IIO_ADXL372");
+
+const struct adxl372_chip_info adxl372_chip_info = {
+ .name = "adxl372",
+ .samp_freq_tbl = adxl372_samp_freq_tbl,
+ .bw_freq_tbl = adxl372_bw_freq_tbl,
+ .num_freqs = ARRAY_SIZE(adxl372_samp_freq_tbl),
+ .act_time_scale_us = 3300,
+ .act_time_scale_low_us = 6600,
+ .inact_time_scale_ms = 13,
+ .inact_time_scale_low_ms = 26,
+ .max_odr = ADXL372_ODR_6400HZ,
+ .fifo_supported = true,
+};
+EXPORT_SYMBOL_NS_GPL(adxl372_chip_info, "IIO_ADXL372");
+
struct adxl372_axis_lookup {
unsigned int bits;
enum adxl372_fifo_format fifo_format;
@@ -257,8 +321,12 @@ static const struct iio_event_spec adxl372_events[] = {
.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 = \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.scan_index = index, \
.scan_type = { \
@@ -279,6 +347,7 @@ static const struct iio_chan_spec adxl372_channels[] = {
};
struct adxl372_state {
+ const struct adxl372_chip_info *chip_info;
int irq;
struct device *dev;
struct regmap *regmap;
@@ -336,18 +405,14 @@ static ssize_t adxl372_write_threshold_value(struct iio_dev *indio_dev, unsigned
struct adxl372_state *st = iio_priv(indio_dev);
int ret;
- mutex_lock(&st->threshold_m);
+ guard(mutex)(&st->threshold_m);
+
ret = regmap_write(st->regmap, addr, ADXL372_THRESH_VAL_H_SEL(threshold));
if (ret < 0)
- goto unlock;
-
- ret = regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5),
- ADXL372_THRESH_VAL_L_SEL(threshold) << 5);
-
-unlock:
- mutex_unlock(&st->threshold_m);
+ return ret;
- return ret;
+ return regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5),
+ ADXL372_THRESH_VAL_L_SEL(threshold) << 5);
}
static int adxl372_read_axis(struct adxl372_state *st, u8 addr)
@@ -471,13 +536,14 @@ static int adxl372_set_activity_time_ms(struct adxl372_state *st,
int ret;
/*
- * 3.3 ms per code is the scale factor of the TIME_ACT register for
- * ODR = 6400 Hz. It is 6.6 ms per code for ODR = 3200 Hz and below.
+ * The scale factor of the TIME_ACT register depends on the ODR.
+ * A higher scale factor is used at the maximum ODR and a lower
+ * one at all other rates.
*/
- if (st->odr == ADXL372_ODR_6400HZ)
- scale_factor = 3300;
+ if (st->odr == st->chip_info->max_odr)
+ scale_factor = st->chip_info->act_time_scale_us;
else
- scale_factor = 6600;
+ scale_factor = st->chip_info->act_time_scale_low_us;
reg_val = DIV_ROUND_CLOSEST(act_time_ms * 1000, scale_factor);
@@ -501,13 +567,14 @@ static int adxl372_set_inactivity_time_ms(struct adxl372_state *st,
int ret;
/*
- * 13 ms per code is the scale factor of the TIME_INACT register for
- * ODR = 6400 Hz. It is 26 ms per code for ODR = 3200 Hz and below.
+ * The scale factor of the TIME_INACT register depends on the ODR.
+ * A higher scale factor is used at the maximum ODR and a lower
+ * one at all other rates.
*/
- if (st->odr == ADXL372_ODR_6400HZ)
- scale_factor = 13;
+ if (st->odr == st->chip_info->max_odr)
+ scale_factor = st->chip_info->inact_time_scale_ms;
else
- scale_factor = 26;
+ scale_factor = st->chip_info->inact_time_scale_low_ms;
res = DIV_ROUND_CLOSEST(inact_time_ms, scale_factor);
reg_val_h = (res >> 8) & 0xFF;
@@ -717,7 +784,7 @@ static int adxl372_setup(struct adxl372_state *st)
if (ret < 0)
return ret;
- ret = adxl372_set_odr(st, ADXL372_ODR_6400HZ);
+ ret = adxl372_set_odr(st, st->chip_info->max_odr);
if (ret < 0)
return ret;
@@ -777,10 +844,10 @@ static int adxl372_read_raw(struct iio_dev *indio_dev,
*val2 = ADXL372_USCALE;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
- *val = adxl372_samp_freq_tbl[st->odr];
+ *val = st->chip_info->samp_freq_tbl[st->odr];
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- *val = adxl372_bw_freq_tbl[st->bw];
+ *val = st->chip_info->bw_freq_tbl[st->bw];
return IIO_VAL_INT;
}
@@ -796,23 +863,17 @@ static int adxl372_write_raw(struct iio_dev *indio_dev,
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
- odr_index = adxl372_find_closest_match(adxl372_samp_freq_tbl,
- ARRAY_SIZE(adxl372_samp_freq_tbl),
- val);
+ odr_index = adxl372_find_closest_match(st->chip_info->samp_freq_tbl,
+ st->chip_info->num_freqs,
+ val);
ret = adxl372_set_odr(st, odr_index);
if (ret < 0)
return ret;
- /*
- * The timer period depends on the ODR selected.
- * At 3200 Hz and below, it is 6.6 ms; at 6400 Hz, it is 3.3 ms
- */
+ /* Recalculate activity time as the timer period depends on ODR */
ret = adxl372_set_activity_time_ms(st, st->act_time_ms);
if (ret < 0)
return ret;
- /*
- * The timer period depends on the ODR selected.
- * At 3200 Hz and below, it is 26 ms; at 6400 Hz, it is 13 ms
- */
+ /* Recalculate inactivity time as the timer period depends on ODR */
ret = adxl372_set_inactivity_time_ms(st, st->inact_time_ms);
if (ret < 0)
return ret;
@@ -825,9 +886,9 @@ static int adxl372_write_raw(struct iio_dev *indio_dev,
return ret;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- bw_index = adxl372_find_closest_match(adxl372_bw_freq_tbl,
- ARRAY_SIZE(adxl372_bw_freq_tbl),
- val);
+ bw_index = adxl372_find_closest_match(st->chip_info->bw_freq_tbl,
+ st->chip_info->num_freqs,
+ val);
return adxl372_set_bandwidth(st, bw_index);
default:
return -EINVAL;
@@ -957,24 +1018,6 @@ static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct ii
return adxl372_set_interrupts(st, st->int1_bitmask, 0);
}
-static ssize_t adxl372_show_filter_freq_avail(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct adxl372_state *st = iio_priv(indio_dev);
- int i;
- size_t len = 0;
-
- for (i = 0; i <= st->odr; i++)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "%d ", adxl372_bw_freq_tbl[i]);
-
- buf[len - 1] = '\n';
-
- return len;
-}
-
static ssize_t adxl372_get_fifo_enabled(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1142,25 +1185,38 @@ static const struct iio_trigger_ops adxl372_peak_data_trigger_ops = {
.set_trigger_state = adxl372_peak_dready_trig_set_state,
};
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400");
-static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available,
- 0444, adxl372_show_filter_freq_avail, NULL, 0);
-
-static struct attribute *adxl372_attributes[] = {
- &iio_const_attr_sampling_frequency_available.dev_attr.attr,
- &iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr,
- NULL,
-};
+static int adxl372_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct adxl372_state *st = iio_priv(indio_dev);
-static const struct attribute_group adxl372_attrs_group = {
- .attrs = adxl372_attributes,
-};
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = st->chip_info->samp_freq_tbl;
+ *type = IIO_VAL_INT;
+ *length = st->chip_info->num_freqs;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ *vals = st->chip_info->bw_freq_tbl;
+ *type = IIO_VAL_INT;
+ /*
+ * Bandwidth cannot exceed half the sampling frequency
+ * (Nyquist), so limit available values based on current ODR.
+ */
+ *length = st->odr + 1;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
static const struct iio_info adxl372_info = {
.validate_trigger = &adxl372_validate_trigger,
- .attrs = &adxl372_attrs_group,
.read_raw = adxl372_read_raw,
.write_raw = adxl372_write_raw,
+ .read_avail = adxl372_read_avail,
.read_event_config = adxl372_read_event_config,
.write_event_config = adxl372_write_event_config,
.read_event_value = adxl372_read_event_value,
@@ -1175,8 +1231,57 @@ bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg)
}
EXPORT_SYMBOL_NS_GPL(adxl372_readable_noinc_reg, "IIO_ADXL372");
+static int adxl372_buffer_setup(struct iio_dev *indio_dev)
+{
+ struct adxl372_state *st = iio_priv(indio_dev);
+ struct device *dev = st->dev;
+ int ret;
+
+ ret = devm_iio_triggered_buffer_setup_ext(dev, indio_dev, NULL,
+ adxl372_trigger_handler,
+ IIO_BUFFER_DIRECTION_IN,
+ &adxl372_buffer_ops,
+ adxl372_fifo_attributes);
+ if (ret)
+ return ret;
+
+ if (!st->irq)
+ return 0;
+
+ st->dready_trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!st->dready_trig)
+ return -ENOMEM;
+
+ st->peak_datardy_trig = devm_iio_trigger_alloc(dev, "%s-dev%d-peak",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!st->peak_datardy_trig)
+ return -ENOMEM;
+
+ st->dready_trig->ops = &adxl372_trigger_ops;
+ st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops;
+ iio_trigger_set_drvdata(st->dready_trig, indio_dev);
+ iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev);
+ ret = devm_iio_trigger_register(dev, st->dready_trig);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_trigger_register(dev, st->peak_datardy_trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(st->dready_trig);
+
+ return devm_request_irq(dev, st->irq,
+ iio_trigger_generic_data_rdy_poll,
+ IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
+ indio_dev->name, st->dready_trig);
+}
+
int adxl372_probe(struct device *dev, struct regmap *regmap,
- int irq, const char *name)
+ int irq, const struct adxl372_chip_info *chip_info)
{
struct iio_dev *indio_dev;
struct adxl372_state *st;
@@ -1192,64 +1297,30 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
st->dev = dev;
st->regmap = regmap;
st->irq = irq;
+ st->chip_info = chip_info;
- mutex_init(&st->threshold_m);
+ ret = devm_mutex_init(dev, &st->threshold_m);
+ if (ret < 0)
+ return ret;
indio_dev->channels = adxl372_channels;
indio_dev->num_channels = ARRAY_SIZE(adxl372_channels);
- indio_dev->available_scan_masks = adxl372_channel_masks;
- indio_dev->name = name;
+ indio_dev->name = chip_info->name;
indio_dev->info = &adxl372_info;
- indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
- ret = adxl372_setup(st);
- if (ret < 0) {
- dev_err(dev, "ADXL372 setup failed\n");
- return ret;
+ if (chip_info->fifo_supported) {
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+ indio_dev->available_scan_masks = adxl372_channel_masks;
+ } else {
+ indio_dev->modes = INDIO_DIRECT_MODE;
}
- ret = devm_iio_triggered_buffer_setup_ext(dev,
- indio_dev, NULL,
- adxl372_trigger_handler,
- IIO_BUFFER_DIRECTION_IN,
- &adxl372_buffer_ops,
- adxl372_fifo_attributes);
+ ret = adxl372_setup(st);
if (ret < 0)
- return ret;
-
- if (st->irq) {
- st->dready_trig = devm_iio_trigger_alloc(dev,
- "%s-dev%d",
- indio_dev->name,
- iio_device_id(indio_dev));
- if (st->dready_trig == NULL)
- return -ENOMEM;
-
- st->peak_datardy_trig = devm_iio_trigger_alloc(dev,
- "%s-dev%d-peak",
- indio_dev->name,
- iio_device_id(indio_dev));
- if (!st->peak_datardy_trig)
- return -ENOMEM;
-
- st->dready_trig->ops = &adxl372_trigger_ops;
- st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops;
- iio_trigger_set_drvdata(st->dready_trig, indio_dev);
- iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev);
- ret = devm_iio_trigger_register(dev, st->dready_trig);
- if (ret < 0)
- return ret;
-
- ret = devm_iio_trigger_register(dev, st->peak_datardy_trig);
- if (ret < 0)
- return ret;
-
- indio_dev->trig = iio_trigger_get(st->dready_trig);
+ return dev_err_probe(dev, ret, "ADXL372 setup failed\n");
- ret = devm_request_irq(dev, st->irq,
- iio_trigger_generic_data_rdy_poll,
- IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
- indio_dev->name, st->dready_trig);
+ if (chip_info->fifo_supported) {
+ ret = adxl372_buffer_setup(indio_dev);
if (ret < 0)
return ret;
}
@@ -1259,5 +1330,6 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
EXPORT_SYMBOL_NS_GPL(adxl372_probe, "IIO_ADXL372");
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
-MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer driver");
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/adxl372.h b/drivers/iio/accel/adxl372.h
index 80a0aa9714fc..353a8b3a9d76 100644
--- a/drivers/iio/accel/adxl372.h
+++ b/drivers/iio/accel/adxl372.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * ADXL372 3-Axis Digital Accelerometer
+ * ADXL371/ADXL372 3-Axis Digital Accelerometer
*
* Copyright 2018 Analog Devices Inc.
*/
@@ -10,8 +10,24 @@
#define ADXL372_REVID 0x03
+struct adxl372_chip_info {
+ const char *name;
+ const int *samp_freq_tbl;
+ const int *bw_freq_tbl;
+ unsigned int num_freqs;
+ unsigned int act_time_scale_us;
+ unsigned int act_time_scale_low_us;
+ unsigned int inact_time_scale_ms;
+ unsigned int inact_time_scale_low_ms;
+ unsigned int max_odr;
+ bool fifo_supported;
+};
+
+extern const struct adxl372_chip_info adxl371_chip_info;
+extern const struct adxl372_chip_info adxl372_chip_info;
+
int adxl372_probe(struct device *dev, struct regmap *regmap,
- int irq, const char *name);
+ int irq, const struct adxl372_chip_info *chip_info);
bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg);
#endif /* _ADXL372_H_ */
diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c
index 186d4fe9a556..e06ddb9c9a7b 100644
--- a/drivers/iio/accel/adxl372_i2c.c
+++ b/drivers/iio/accel/adxl372_i2c.c
@@ -1,12 +1,11 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * ADXL372 3-Axis Digital Accelerometer I2C driver
+ * ADXL371/ADXL372 3-Axis Digital Accelerometer I2C driver
*
* Copyright 2018 Analog Devices Inc.
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -20,11 +19,13 @@ static const struct regmap_config adxl372_regmap_config = {
static int adxl372_i2c_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ const struct adxl372_chip_info *chip_info;
struct regmap *regmap;
unsigned int regval;
int ret;
+ chip_info = i2c_get_match_data(client);
+
regmap = devm_regmap_init_i2c(client, &adxl372_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
@@ -38,17 +39,19 @@ static int adxl372_i2c_probe(struct i2c_client *client)
dev_warn(&client->dev,
"I2C might not work properly with other devices on the bus");
- return adxl372_probe(&client->dev, regmap, client->irq, id->name);
+ return adxl372_probe(&client->dev, regmap, client->irq, chip_info);
}
static const struct i2c_device_id adxl372_i2c_id[] = {
- { "adxl372" },
+ { .name = "adxl371", .driver_data = (kernel_ulong_t)&adxl371_chip_info },
+ { .name = "adxl372", .driver_data = (kernel_ulong_t)&adxl372_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
static const struct of_device_id adxl372_of_match[] = {
- { .compatible = "adi,adxl372" },
+ { .compatible = "adi,adxl371", .data = &adxl371_chip_info },
+ { .compatible = "adi,adxl372", .data = &adxl372_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, adxl372_of_match);
@@ -65,6 +68,7 @@ static struct i2c_driver adxl372_i2c_driver = {
module_i2c_driver(adxl372_i2c_driver);
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
-MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer I2C driver");
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer I2C driver");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("IIO_ADXL372");
diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c
index 39941b519c3b..128e148c4e96 100644
--- a/drivers/iio/accel/adxl372_spi.c
+++ b/drivers/iio/accel/adxl372_spi.c
@@ -1,12 +1,11 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * ADXL372 3-Axis Digital Accelerometer SPI driver
+ * ADXL371/ADXL372 3-Axis Digital Accelerometer SPI driver
*
* Copyright 2018 Analog Devices Inc.
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -22,24 +21,28 @@ static const struct regmap_config adxl372_spi_regmap_config = {
static int adxl372_spi_probe(struct spi_device *spi)
{
- const struct spi_device_id *id = spi_get_device_id(spi);
+ const struct adxl372_chip_info *chip_info;
struct regmap *regmap;
+ chip_info = spi_get_device_match_data(spi);
+
regmap = devm_regmap_init_spi(spi, &adxl372_spi_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- return adxl372_probe(&spi->dev, regmap, spi->irq, id->name);
+ return adxl372_probe(&spi->dev, regmap, spi->irq, chip_info);
}
static const struct spi_device_id adxl372_spi_id[] = {
- { "adxl372", 0 },
+ { .name = "adxl371", .driver_data = (kernel_ulong_t)&adxl371_chip_info },
+ { .name = "adxl372", .driver_data = (kernel_ulong_t)&adxl372_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
static const struct of_device_id adxl372_of_match[] = {
- { .compatible = "adi,adxl372" },
+ { .compatible = "adi,adxl371", .data = &adxl371_chip_info },
+ { .compatible = "adi,adxl372", .data = &adxl372_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, adxl372_of_match);
@@ -56,6 +59,7 @@ static struct spi_driver adxl372_spi_driver = {
module_spi_driver(adxl372_spi_driver);
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
-MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer SPI driver");
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer SPI driver");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("IIO_ADXL372");
diff --git a/drivers/iio/accel/adxl380.c b/drivers/iio/accel/adxl380.c
index 8fab2fdbe147..7dca5523091f 100644
--- a/drivers/iio/accel/adxl380.c
+++ b/drivers/iio/accel/adxl380.c
@@ -31,7 +31,7 @@
#define ADXL319_ID_VAL 382
#define ADXL380_DEVID_AD_REG 0x00
-#define ADLX380_PART_ID_REG 0x02
+#define ADXL380_PART_ID_REG 0x02
#define ADXL380_X_DATA_H_REG 0x15
#define ADXL380_Y_DATA_H_REG 0x17
@@ -877,7 +877,7 @@ static int adxl380_set_fifo_samples(struct adxl380_state *st)
ret = regmap_update_bits(st->regmap, ADXL380_FIFO_CONFIG_0_REG,
ADXL380_FIFO_SAMPLES_8_MSK,
FIELD_PREP(ADXL380_FIFO_SAMPLES_8_MSK,
- (fifo_samples & BIT(8))));
+ !!(fifo_samples & BIT(8))));
if (ret)
return ret;
@@ -1878,7 +1878,7 @@ static int adxl380_setup(struct iio_dev *indio_dev)
if (reg_val != ADXL380_DEVID_AD_VAL)
dev_warn(st->dev, "Unknown chip id %x\n", reg_val);
- ret = regmap_bulk_read(st->regmap, ADLX380_PART_ID_REG,
+ ret = regmap_bulk_read(st->regmap, ADXL380_PART_ID_REG,
&st->transf_buf, 2);
if (ret)
return ret;
@@ -1967,7 +1967,9 @@ int adxl380_probe(struct device *dev, struct regmap *regmap,
st->chip_info = chip_info;
st->odr = ADXL380_ODR_DSM;
- mutex_init(&st->lock);
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
indio_dev->channels = adxl380_channels;
indio_dev->num_channels = ARRAY_SIZE(adxl380_channels);
diff --git a/drivers/iio/accel/adxl380_i2c.c b/drivers/iio/accel/adxl380_i2c.c
index bd8782d08c7d..2673ddbbdc53 100644
--- a/drivers/iio/accel/adxl380_i2c.c
+++ b/drivers/iio/accel/adxl380_i2c.c
@@ -6,7 +6,6 @@
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -33,10 +32,10 @@ static int adxl380_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adxl380_i2c_id[] = {
- { "adxl318", (kernel_ulong_t)&adxl318_chip_info },
- { "adxl319", (kernel_ulong_t)&adxl319_chip_info },
- { "adxl380", (kernel_ulong_t)&adxl380_chip_info },
- { "adxl382", (kernel_ulong_t)&adxl382_chip_info },
+ { .name = "adxl318", .driver_data = (kernel_ulong_t)&adxl318_chip_info },
+ { .name = "adxl319", .driver_data = (kernel_ulong_t)&adxl319_chip_info },
+ { .name = "adxl380", .driver_data = (kernel_ulong_t)&adxl380_chip_info },
+ { .name = "adxl382", .driver_data = (kernel_ulong_t)&adxl382_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl380_i2c_id);
diff --git a/drivers/iio/accel/adxl380_spi.c b/drivers/iio/accel/adxl380_spi.c
index 4ead949b24f1..ae8467f4e6c0 100644
--- a/drivers/iio/accel/adxl380_spi.c
+++ b/drivers/iio/accel/adxl380_spi.c
@@ -5,7 +5,6 @@
* Copyright 2024 Analog Devices Inc.
*/
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -35,10 +34,10 @@ static int adxl380_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id adxl380_spi_id[] = {
- { "adxl318", (kernel_ulong_t)&adxl318_chip_info },
- { "adxl319", (kernel_ulong_t)&adxl319_chip_info },
- { "adxl380", (kernel_ulong_t)&adxl380_chip_info },
- { "adxl382", (kernel_ulong_t)&adxl382_chip_info },
+ { .name = "adxl318", .driver_data = (kernel_ulong_t)&adxl318_chip_info },
+ { .name = "adxl319", .driver_data = (kernel_ulong_t)&adxl319_chip_info },
+ { .name = "adxl380", .driver_data = (kernel_ulong_t)&adxl380_chip_info },
+ { .name = "adxl382", .driver_data = (kernel_ulong_t)&adxl382_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, adxl380_spi_id);
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index 7bc6761f5135..e7dbbd4766dd 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -13,7 +13,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -989,10 +988,8 @@ static int bma180_probe(struct i2c_client *client)
iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
"bma180_event", data->trig);
- if (ret) {
- dev_err(dev, "unable to request IRQ\n");
+ if (ret)
goto err_trigger_free;
- }
data->trig->ops = &bma180_trigger_ops;
iio_trigger_set_drvdata(data->trig, indio_dev);
@@ -1083,11 +1080,11 @@ static int bma180_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
static const struct i2c_device_id bma180_ids[] = {
- { "bma023", (kernel_ulong_t)&bma180_part_info[BMA023] },
- { "bma150", (kernel_ulong_t)&bma180_part_info[BMA150] },
- { "bma180", (kernel_ulong_t)&bma180_part_info[BMA180] },
- { "bma250", (kernel_ulong_t)&bma180_part_info[BMA250] },
- { "smb380", (kernel_ulong_t)&bma180_part_info[BMA150] },
+ { .name = "bma023", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA023] },
+ { .name = "bma150", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA150] },
+ { .name = "bma180", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA180] },
+ { .name = "bma250", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA250] },
+ { .name = "smb380", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA150] },
{ }
};
diff --git a/drivers/iio/accel/bma220_core.c b/drivers/iio/accel/bma220_core.c
index f32d875b994e..b83abfdd84fd 100644
--- a/drivers/iio/accel/bma220_core.c
+++ b/drivers/iio/accel/bma220_core.c
@@ -11,7 +11,6 @@
#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/errno.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm.h>
@@ -545,8 +544,7 @@ int bma220_common_probe(struct device *dev, struct regmap *regmap, int irq)
&bma220_irq_handler, IRQF_ONESHOT,
indio_dev->name, indio_dev);
if (ret)
- return dev_err_probe(dev, ret,
- "request irq %d failed\n", irq);
+ return ret;
}
ret = devm_add_action_or_reset(dev, bma220_deinit, data);
diff --git a/drivers/iio/accel/bma220_i2c.c b/drivers/iio/accel/bma220_i2c.c
index 8b6f8e305c8c..7e850e95cb06 100644
--- a/drivers/iio/accel/bma220_i2c.c
+++ b/drivers/iio/accel/bma220_i2c.c
@@ -10,7 +10,6 @@
#include <linux/bitfield.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/types.h>
@@ -47,7 +46,7 @@ static const struct of_device_id bma220_i2c_match[] = {
MODULE_DEVICE_TABLE(of, bma220_i2c_match);
static const struct i2c_device_id bma220_i2c_id[] = {
- { "bma220" },
+ { .name = "bma220" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bma220_i2c_id);
diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c
index 383ee8a135ee..d6c1087cc3c0 100644
--- a/drivers/iio/accel/bma220_spi.c
+++ b/drivers/iio/accel/bma220_spi.c
@@ -5,7 +5,6 @@
* Copyright (c) 2016,2020 Intel Corporation.
*/
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/types.h>
@@ -26,7 +25,7 @@ static int bma220_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id bma220_spi_id[] = {
- { "bma220", 0 },
+ { .name = "bma220" },
{ }
};
diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
index 05f72707f830..7e3cff4cca91 100644
--- a/drivers/iio/accel/bma400_core.c
+++ b/drivers/iio/accel/bma400_core.c
@@ -1789,8 +1789,7 @@ int bma400_probe(struct device *dev, struct regmap *regmap, int irq,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
indio_dev->name, indio_dev);
if (ret)
- return dev_err_probe(data->dev, ret,
- "request irq %d failed\n", irq);
+ return ret;
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c
index 24a390c3ae66..a3fb3b81b64c 100644
--- a/drivers/iio/accel/bma400_i2c.c
+++ b/drivers/iio/accel/bma400_i2c.c
@@ -7,7 +7,6 @@
* I2C address is either 0x14 or 0x15 depending on SDO
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -28,7 +27,7 @@ static int bma400_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bma400_i2c_ids[] = {
- { "bma400" },
+ { .name = "bma400" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bma400_i2c_ids);
diff --git a/drivers/iio/accel/bma400_spi.c b/drivers/iio/accel/bma400_spi.c
index d386f643515b..7ac0a7881b59 100644
--- a/drivers/iio/accel/bma400_spi.c
+++ b/drivers/iio/accel/bma400_spi.c
@@ -7,7 +7,6 @@
*/
#include <linux/bits.h>
#include <linux/init.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -88,7 +87,7 @@ static int bma400_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id bma400_spi_ids[] = {
- { "bma400", 0 },
+ { .name = "bma400" },
{ }
};
MODULE_DEVICE_TABLE(spi, bma400_spi_ids);
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 42ccf0316ce5..46bb36d9366e 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -851,7 +851,7 @@ static ssize_t bmc150_accel_get_fifo_watermark(struct device *dev,
wm = data->watermark;
mutex_unlock(&data->mutex);
- return sprintf(buf, "%d\n", wm);
+ return sysfs_emit(buf, "%d\n", wm);
}
static ssize_t bmc150_accel_get_fifo_state(struct device *dev,
@@ -866,7 +866,7 @@ static ssize_t bmc150_accel_get_fifo_state(struct device *dev,
state = data->fifo_mode;
mutex_unlock(&data->mutex);
- return sprintf(buf, "%d\n", state);
+ return sysfs_emit(buf, "%d\n", state);
}
static const struct iio_mount_matrix *
@@ -988,8 +988,12 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
do_div(sample_period, count);
tstamp = data->timestamp - (count - 1) * sample_period;
- if (samples && count > samples)
- count = samples;
+ if (samples)
+ count = min3(count, samples, BMC150_ACCEL_FIFO_LENGTH);
+ else
+ count = min(count, BMC150_ACCEL_FIFO_LENGTH);
+
+ count = min_t(u8, count, BMC150_ACCEL_FIFO_LENGTH);
ret = bmc150_accel_fifo_transfer(data, (u8 *)buffer, count);
if (ret)
diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c
index b4604f441553..336866aad20c 100644
--- a/drivers/iio/accel/bmc150-accel-i2c.c
+++ b/drivers/iio/accel/bmc150-accel-i2c.c
@@ -5,7 +5,6 @@
*/
#include <linux/device.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/acpi.h>
@@ -245,16 +244,16 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
static const struct i2c_device_id bmc150_accel_id[] = {
- {"bma222"},
- {"bma222e"},
- {"bma250e"},
- {"bma253"},
- {"bma254"},
- {"bma255"},
- {"bma280"},
- {"bmc150_accel"},
- {"bmc156_accel", BOSCH_BMC156},
- {"bmi055_accel"},
+ { .name = "bma222", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bma222e", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bma250e", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bma253", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bma254", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bma255", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bma280", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bmc150_accel", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bmc156_accel", .driver_data = BOSCH_BMC156 },
+ { .name = "bmi055_accel", .driver_data = BOSCH_UNKNOWN },
{ }
};
diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c
index 26ce50b37716..405bd7b2d199 100644
--- a/drivers/iio/accel/bmc150-accel-spi.c
+++ b/drivers/iio/accel/bmc150-accel-spi.c
@@ -5,7 +5,6 @@
*/
#include <linux/device.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -53,15 +52,15 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
static const struct spi_device_id bmc150_accel_id[] = {
- {"bma222"},
- {"bma222e"},
- {"bma250e"},
- {"bma253"},
- {"bma255"},
- {"bma280"},
- {"bmc150_accel"},
- {"bmc156_accel", BOSCH_BMC156},
- {"bmi055_accel"},
+ { .name = "bma222", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bma222e", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bma250e", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bma253", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bma255", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bma280", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bmc150_accel", .driver_data = BOSCH_UNKNOWN },
+ { .name = "bmc156_accel", .driver_data = BOSCH_BMC156 },
+ { .name = "bmi055_accel", .driver_data = BOSCH_UNKNOWN },
{ }
};
MODULE_DEVICE_TABLE(spi, bmc150_accel_id);
diff --git a/drivers/iio/accel/bmi088-accel-i2c.c b/drivers/iio/accel/bmi088-accel-i2c.c
index 310f863029bb..aecd66e5685e 100644
--- a/drivers/iio/accel/bmi088-accel-i2c.c
+++ b/drivers/iio/accel/bmi088-accel-i2c.c
@@ -9,7 +9,6 @@
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -45,9 +44,9 @@ static const struct of_device_id bmi088_of_match[] = {
MODULE_DEVICE_TABLE(of, bmi088_of_match);
static const struct i2c_device_id bmi088_accel_id[] = {
- { "bmi085-accel", BOSCH_BMI085 },
- { "bmi088-accel", BOSCH_BMI088 },
- { "bmi090l-accel", BOSCH_BMI090L },
+ { .name = "bmi085-accel", .driver_data = BOSCH_BMI085 },
+ { .name = "bmi088-accel", .driver_data = BOSCH_BMI088 },
+ { .name = "bmi090l-accel", .driver_data = BOSCH_BMI090L },
{ }
};
MODULE_DEVICE_TABLE(i2c, bmi088_accel_id);
diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c
index 44cb50c76cb1..ae89e162e097 100644
--- a/drivers/iio/accel/bmi088-accel-spi.c
+++ b/drivers/iio/accel/bmi088-accel-spi.c
@@ -72,9 +72,9 @@ static const struct of_device_id bmi088_of_match[] = {
MODULE_DEVICE_TABLE(of, bmi088_of_match);
static const struct spi_device_id bmi088_accel_id[] = {
- {"bmi085-accel", BOSCH_BMI085},
- {"bmi088-accel", BOSCH_BMI088},
- {"bmi090l-accel", BOSCH_BMI090L},
+ { .name = "bmi085-accel", .driver_data = BOSCH_BMI085 },
+ { .name = "bmi088-accel", .driver_data = BOSCH_BMI088 },
+ { .name = "bmi090l-accel", .driver_data = BOSCH_BMI090L },
{ }
};
MODULE_DEVICE_TABLE(spi, bmi088_accel_id);
diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c
index c2dd123b9021..15acbe1c2cbd 100644
--- a/drivers/iio/accel/da280.c
+++ b/drivers/iio/accel/da280.c
@@ -162,9 +162,9 @@ static const struct acpi_device_id da280_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, da280_acpi_match);
static const struct i2c_device_id da280_i2c_id[] = {
- { "da217", (kernel_ulong_t)&da217_match_data },
- { "da226", (kernel_ulong_t)&da226_match_data },
- { "da280", (kernel_ulong_t)&da280_match_data },
+ { .name = "da217", .driver_data = (kernel_ulong_t)&da217_match_data },
+ { .name = "da226", .driver_data = (kernel_ulong_t)&da226_match_data },
+ { .name = "da280", .driver_data = (kernel_ulong_t)&da280_match_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, da280_i2c_id);
diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c
index e1df7b009d89..dcb69c8eaf09 100644
--- a/drivers/iio/accel/da311.c
+++ b/drivers/iio/accel/da311.c
@@ -268,7 +268,7 @@ static int da311_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume);
static const struct i2c_device_id da311_i2c_id[] = {
- { "da311" },
+ { .name = "da311" },
{ }
};
MODULE_DEVICE_TABLE(i2c, da311_i2c_id);
diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c
index 33f225d73e7b..82816fa44354 100644
--- a/drivers/iio/accel/dmard06.c
+++ b/drivers/iio/accel/dmard06.c
@@ -6,7 +6,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
@@ -199,9 +198,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend,
dmard06_resume);
static const struct i2c_device_id dmard06_id[] = {
- { "dmard05" },
- { "dmard06" },
- { "dmard07" },
+ { .name = "dmard05" },
+ { .name = "dmard06" },
+ { .name = "dmard07" },
{ }
};
MODULE_DEVICE_TABLE(i2c, dmard06_id);
diff --git a/drivers/iio/accel/dmard09.c b/drivers/iio/accel/dmard09.c
index d9290e3b9c46..6f0497ab6133 100644
--- a/drivers/iio/accel/dmard09.c
+++ b/drivers/iio/accel/dmard09.c
@@ -8,6 +8,7 @@
#include <linux/unaligned.h>
#include <linux/module.h>
#include <linux/i2c.h>
+#include <linux/units.h>
#include <linux/iio/iio.h>
#define DMARD09_DRV_NAME "dmard09"
@@ -79,6 +80,12 @@ static int dmard09_read_raw(struct iio_dev *indio_dev,
*val = accel;
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ /* 1 g / 32 LSB, in m/s^2 */
+ *val2 = IIO_G_TO_M_S_2(NANO / 32);
+
+ return IIO_VAL_INT_PLUS_NANO;
default:
return -EINVAL;
}
@@ -123,7 +130,7 @@ static int dmard09_probe(struct i2c_client *client)
}
static const struct i2c_device_id dmard09_id[] = {
- { "dmard09" },
+ { .name = "dmard09" },
{ }
};
diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c
index 575e8510e1bd..8ba00fd57901 100644
--- a/drivers/iio/accel/dmard10.c
+++ b/drivers/iio/accel/dmard10.c
@@ -229,7 +229,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend,
dmard10_resume);
static const struct i2c_device_id dmard10_i2c_id[] = {
- { "dmard10" },
+ { .name = "dmard10" },
{ }
};
MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id);
diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c
index 8763e91c63d2..18d7b09bddd2 100644
--- a/drivers/iio/accel/fxls8962af-core.c
+++ b/drivers/iio/accel/fxls8962af-core.c
@@ -17,7 +17,6 @@
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
@@ -970,6 +969,8 @@ static int fxls8962af_fifo_flush(struct iio_dev *indio_dev)
if (!count)
return 0;
+ count = min(count, FXLS8962AF_FIFO_LENGTH);
+
data->old_timestamp = data->timestamp;
data->timestamp = iio_get_time_ns(indio_dev);
diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c
index 106198a12474..e72842b1459e 100644
--- a/drivers/iio/accel/fxls8962af-i2c.c
+++ b/drivers/iio/accel/fxls8962af-i2c.c
@@ -8,7 +8,6 @@
#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -28,10 +27,10 @@ static int fxls8962af_probe(struct i2c_client *client)
}
static const struct i2c_device_id fxls8962af_id[] = {
- { "fxls8962af", fxls8962af },
- { "fxls8964af", fxls8964af },
- { "fxls8967af", fxls8967af },
- { "fxls8974cf", fxls8974cf },
+ { .name = "fxls8962af", .driver_data = fxls8962af },
+ { .name = "fxls8964af", .driver_data = fxls8964af },
+ { .name = "fxls8967af", .driver_data = fxls8967af },
+ { .name = "fxls8974cf", .driver_data = fxls8974cf },
{ }
};
MODULE_DEVICE_TABLE(i2c, fxls8962af_id);
diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c
index bdafd1f615d9..baf3c4352f14 100644
--- a/drivers/iio/accel/fxls8962af-spi.c
+++ b/drivers/iio/accel/fxls8962af-spi.c
@@ -8,7 +8,6 @@
#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
@@ -35,8 +34,8 @@ static const struct of_device_id fxls8962af_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, fxls8962af_spi_of_match);
static const struct spi_device_id fxls8962af_spi_id_table[] = {
- { "fxls8962af", fxls8962af },
- { "fxls8964af", fxls8964af },
+ { .name = "fxls8962af", .driver_data = fxls8962af },
+ { .name = "fxls8964af", .driver_data = fxls8964af },
{ }
};
MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table);
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 2ff591b3458f..eb521125f4eb 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -3,10 +3,10 @@
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*/
+#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
@@ -119,22 +119,10 @@ static const struct iio_chan_spec gravity_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP),
};
-/* Adjust channel real bits based on report descriptor */
-static void accel_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
- int channel, int size)
-{
- channels[channel].scan_type.sign = 's';
- /* Real storage bits will change based on the report desc. */
- channels[channel].scan_type.realbits = size * 8;
- /* Maximum size of a sample to capture is u32 */
- channels[channel].scan_type.storagebits = sizeof(u32) * 8;
-}
-
/* Channel read_raw handler */
static int accel_3d_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct accel_3d_state *accel_state = iio_priv(indio_dev);
int report_id = -1;
@@ -161,7 +149,7 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev,
else {
*val = 0;
hid_sensor_power_state(&accel_state->common_attributes,
- false);
+ false);
return -EINVAL;
}
hid_sensor_power_state(&accel_state->common_attributes, false);
@@ -194,10 +182,8 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int accel_3d_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct accel_3d_state *accel_state = iio_priv(indio_dev);
int ret = 0;
@@ -233,8 +219,7 @@ static void hid_sensor_push_data(struct iio_dev *indio_dev, void *data,
/* Callback handler to send event after all samples are received and captured */
static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct accel_3d_state *accel_state = iio_priv(indio_dev);
@@ -257,9 +242,9 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct accel_3d_state *accel_state = iio_priv(indio_dev);
@@ -291,31 +276,32 @@ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int accel_3d_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct iio_chan_spec *channels,
- unsigned usage_id,
- struct accel_3d_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ u32 usage_id,
+ struct accel_3d_state *st)
{
int ret;
- int i;
- for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
+ for (unsigned int ch = CHANNEL_SCAN_INDEX_X; ch <= CHANNEL_SCAN_INDEX_Z; ch++) {
ret = sensor_hub_input_get_attribute_info(hsdev,
HID_INPUT_REPORT,
usage_id,
- HID_USAGE_SENSOR_ACCEL_X_AXIS + i,
- &st->accel[CHANNEL_SCAN_INDEX_X + i]);
+ HID_USAGE_SENSOR_ACCEL_X_AXIS + ch,
+ &st->accel[ch]);
if (ret < 0)
break;
- accel_3d_adjust_channel_bit_mask(channels,
- CHANNEL_SCAN_INDEX_X + i,
- st->accel[CHANNEL_SCAN_INDEX_X + i].size);
+ channels[ch].scan_type = (struct iio_scan_type) {
+ .format = 's',
+ .realbits = BYTES_TO_BITS(st->accel[ch].size),
+ .storagebits = BITS_PER_TYPE(u32),
+ };
}
dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n",
- st->accel[0].index,
- st->accel[0].report_id,
- st->accel[1].index, st->accel[1].report_id,
- st->accel[2].index, st->accel[2].report_id);
+ st->accel[0].index,
+ st->accel[0].report_id,
+ st->accel[1].index, st->accel[1].report_id,
+ st->accel[2].index, st->accel[2].report_id);
st->scale_precision = hid_sensor_format_scale(
hsdev->usage,
@@ -338,7 +324,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct accel_3d_state));
- if (indio_dev == NULL)
+ if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -375,8 +361,8 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
return -ENOMEM;
}
ret = accel_3d_parse_report(pdev, hsdev,
- (struct iio_chan_spec *)indio_dev->channels,
- hsdev->usage, accel_state);
+ (struct iio_chan_spec *)indio_dev->channels,
+ hsdev->usage, accel_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
return ret;
@@ -389,32 +375,32 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
atomic_set(&accel_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &accel_state->common_attributes);
+ &accel_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
accel_state->callbacks.send_event = accel_3d_proc_event;
accel_state->callbacks.capture_sample = accel_3d_capture_sample;
accel_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, hsdev->usage,
- &accel_state->callbacks);
+ &accel_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
return ret;
@@ -427,8 +413,8 @@ static void hid_accel_3d_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct accel_3d_state *accel_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
}
diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c
index 39485572a76b..02dd1db7a646 100644
--- a/drivers/iio/accel/kionix-kx022a.c
+++ b/drivers/iio/accel/kionix-kx022a.c
@@ -1435,7 +1435,7 @@ int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chi
&kx022a_irq_thread_handler,
IRQF_ONESHOT, name, idev);
if (ret)
- return dev_err_probe(data->dev, ret, "Could not request IRQ\n");
+ return ret;
ret = devm_iio_trigger_register(dev, indio_trig);
if (ret)
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 2823ddde4bf2..166fb786425f 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -8,7 +8,6 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/bitops.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
@@ -1630,11 +1629,11 @@ static const struct dev_pm_ops kxcjk1013_pm_ops = {
};
static const struct i2c_device_id kxcjk1013_id[] = {
- { "kxcjk1013", (kernel_ulong_t)&kxcjk1013_info },
- { "kxcj91008", (kernel_ulong_t)&kxcj91008_info },
- { "kxtj21009", (kernel_ulong_t)&kxtj21009_info },
- { "kxtf9", (kernel_ulong_t)&kxtf9_info },
- { "kx023-1025", (kernel_ulong_t)&kx0231025_info },
+ { .name = "kxcjk1013", .driver_data = (kernel_ulong_t)&kxcjk1013_info },
+ { .name = "kxcj91008", .driver_data = (kernel_ulong_t)&kxcj91008_info },
+ { .name = "kxtj21009", .driver_data = (kernel_ulong_t)&kxtj21009_info },
+ { .name = "kxtf9", .driver_data = (kernel_ulong_t)&kxtf9_info },
+ { .name = "kx023-1025", .driver_data = (kernel_ulong_t)&kx0231025_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, kxcjk1013_id);
diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c
index 1fa88b99149e..f19626c2f70f 100644
--- a/drivers/iio/accel/kxsd9-i2c.c
+++ b/drivers/iio/accel/kxsd9-i2c.c
@@ -2,7 +2,6 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/delay.h>
@@ -43,7 +42,7 @@ static const struct of_device_id kxsd9_of_match[] = {
MODULE_DEVICE_TABLE(of, kxsd9_of_match);
static const struct i2c_device_id kxsd9_i2c_id[] = {
- { "kxsd9" },
+ { .name = "kxsd9" },
{ }
};
MODULE_DEVICE_TABLE(i2c, kxsd9_i2c_id);
diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c
index cbb6c6412665..71da958d4051 100644
--- a/drivers/iio/accel/kxsd9-spi.c
+++ b/drivers/iio/accel/kxsd9-spi.c
@@ -3,7 +3,6 @@
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@@ -37,7 +36,7 @@ static void kxsd9_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id kxsd9_spi_id[] = {
- {"kxsd9", 0},
+ { .name = "kxsd9" },
{ }
};
MODULE_DEVICE_TABLE(spi, kxsd9_spi_id);
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index 4717d80fc24a..7ac885d94d7f 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -147,8 +147,9 @@ static int kxsd9_write_raw(struct iio_dev *indio_dev,
if (mask == IIO_CHAN_INFO_SCALE) {
/* Check no integer component */
if (val)
- return -EINVAL;
- ret = kxsd9_write_scale(indio_dev, val2);
+ ret = -EINVAL;
+ else
+ ret = kxsd9_write_scale(indio_dev, val2);
}
pm_runtime_put_autosuspend(st->dev);
diff --git a/drivers/iio/accel/mc3230.c b/drivers/iio/accel/mc3230.c
index 3e494f9ddc56..b45897210a62 100644
--- a/drivers/iio/accel/mc3230.c
+++ b/drivers/iio/accel/mc3230.c
@@ -230,8 +230,8 @@ static int mc3230_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume);
static const struct i2c_device_id mc3230_i2c_id[] = {
- { "mc3230", (kernel_ulong_t)&mc3230_chip_info },
- { "mc3510c", (kernel_ulong_t)&mc3510c_chip_info },
+ { .name = "mc3230", .driver_data = (kernel_ulong_t)&mc3230_chip_info },
+ { .name = "mc3510c", .driver_data = (kernel_ulong_t)&mc3510c_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, mc3230_i2c_id);
diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c
index 2ff8eb1f9ce9..9588fd133b1e 100644
--- a/drivers/iio/accel/mma7455_i2c.c
+++ b/drivers/iio/accel/mma7455_i2c.c
@@ -32,8 +32,8 @@ static void mma7455_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id mma7455_i2c_ids[] = {
- { "mma7455" },
- { "mma7456" },
+ { .name = "mma7455" },
+ { .name = "mma7456" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma7455_i2c_ids);
diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c
index aca02e83f789..872c47acf882 100644
--- a/drivers/iio/accel/mma7455_spi.c
+++ b/drivers/iio/accel/mma7455_spi.c
@@ -28,8 +28,8 @@ static void mma7455_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id mma7455_spi_ids[] = {
- { "mma7455", 0 },
- { "mma7456", 0 },
+ { .name = "mma7455" },
+ { .name = "mma7456" },
{ }
};
MODULE_DEVICE_TABLE(spi, mma7455_spi_ids);
diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c
index be3213600cf4..38b4df76cff3 100644
--- a/drivers/iio/accel/mma7660.c
+++ b/drivers/iio/accel/mma7660.c
@@ -8,7 +8,6 @@
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -259,7 +258,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend,
mma7660_resume);
static const struct i2c_device_id mma7660_i2c_id[] = {
- { "mma7660" },
+ { .name = "mma7660" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id);
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 15172ba2972c..7d683686dd9d 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -18,21 +18,21 @@
* TODO: orientation events
*/
+#include <linux/delay.h>
+#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
+#include <linux/pm_runtime.h>
#include <linux/property.h>
-#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
-#include <linux/iio/events.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <linux/regulator/consumer.h>
-#include <linux/types.h>
#define MMA8452_STATUS 0x00
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
@@ -252,6 +252,8 @@ static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
3 * sizeof(__be16), (u8 *)buf);
+ if (ret < 0)
+ return ret;
ret = mma8452_set_runtime_pm_state(data->client, false);
@@ -704,8 +706,8 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
}
static int __mma8452_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct mma8452_data *data = iio_priv(indio_dev);
int i, j, ret;
@@ -786,8 +788,9 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
}
static int mma8452_get_event_regs(struct mma8452_data *data,
- const struct iio_chan_spec *chan, enum iio_event_direction dir,
- const struct mma8452_event_regs **ev_reg)
+ const struct iio_chan_spec *chan,
+ enum iio_event_direction dir,
+ const struct mma8452_event_regs **ev_reg)
{
if (!chan)
return -EINVAL;
@@ -816,11 +819,11 @@ static int mma8452_get_event_regs(struct mma8452_data *data,
}
static int mma8452_read_event_value(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan,
- enum iio_event_type type,
- enum iio_event_direction dir,
- enum iio_event_info info,
- int *val, int *val2)
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
{
struct mma8452_data *data = iio_priv(indio_dev);
int ret, us, power_mode;
@@ -879,11 +882,11 @@ static int mma8452_read_event_value(struct iio_dev *indio_dev,
}
static int mma8452_write_event_value(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan,
- enum iio_event_type type,
- enum iio_event_direction dir,
- enum iio_event_info info,
- int val, int val2)
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
{
struct mma8452_data *data = iio_priv(indio_dev);
int ret, reg, steps;
@@ -953,8 +956,7 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev,
case IIO_EV_DIR_FALLING:
return mma8452_freefall_mode_enabled(data);
case IIO_EV_DIR_RISING:
- ret = i2c_smbus_read_byte_data(data->client,
- ev_regs->ev_cfg);
+ ret = i2c_smbus_read_byte_data(data->client, ev_regs->ev_cfg);
if (ret < 0)
return ret;
@@ -1191,7 +1193,7 @@ static const struct attribute_group mma8452_event_attribute_group = {
static const struct iio_mount_matrix *
mma8452_get_mount_matrix(const struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
+ const struct iio_chan_spec *chan)
{
struct mma8452_data *data = iio_priv(indio_dev);
@@ -1514,8 +1516,9 @@ static int mma8452_reset(struct i2c_client *client)
* The following code will read the reset register, and check whether
* this reset works.
*/
- i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2,
- MMA8452_CTRL_REG2_RST);
+ i2c_smbus_write_byte_data(client,
+ MMA8452_CTRL_REG2,
+ MMA8452_CTRL_REG2_RST);
for (i = 0; i < 10; i++) {
usleep_range(100, 200);
@@ -1544,6 +1547,7 @@ MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
static int mma8452_probe(struct i2c_client *client)
{
+ struct device *dev = &client->dev;
struct mma8452_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -1576,14 +1580,12 @@ static int mma8452_probe(struct i2c_client *client)
"failed to get VDDIO regulator!\n");
ret = regulator_enable(data->vdd_reg);
- if (ret) {
- dev_err(&client->dev, "failed to enable VDD regulator!\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable VDD regulator!\n");
ret = regulator_enable(data->vddio_reg);
if (ret) {
- dev_err(&client->dev, "failed to enable VDDIO regulator!\n");
+ dev_err_probe(dev, ret, "failed to enable VDDIO regulator!\n");
goto disable_regulator_vdd;
}
@@ -1645,8 +1647,8 @@ static int mma8452_probe(struct i2c_client *client)
dev_dbg(&client->dev, "using interrupt line INT2\n");
} else {
ret = i2c_smbus_write_byte_data(client,
- MMA8452_CTRL_REG5,
- data->chip_info->all_events);
+ MMA8452_CTRL_REG5,
+ data->chip_info->all_events);
if (ret < 0)
goto disable_regulators;
@@ -1654,8 +1656,8 @@ static int mma8452_probe(struct i2c_client *client)
}
ret = i2c_smbus_write_byte_data(client,
- MMA8452_CTRL_REG4,
- data->chip_info->enabled_events);
+ MMA8452_CTRL_REG4,
+ data->chip_info->enabled_events);
if (ret < 0)
goto disable_regulators;
@@ -1680,18 +1682,16 @@ static int mma8452_probe(struct i2c_client *client)
goto trigger_cleanup;
if (client->irq) {
- ret = devm_request_threaded_irq(&client->dev,
- client->irq,
- NULL, mma8452_interrupt,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- client->name, indio_dev);
+ ret = request_threaded_irq(client->irq, NULL, mma8452_interrupt,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ client->name, indio_dev);
if (ret)
goto buffer_cleanup;
}
ret = pm_runtime_set_active(&client->dev);
if (ret < 0)
- goto buffer_cleanup;
+ goto free_irq;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
@@ -1700,7 +1700,7 @@ static int mma8452_probe(struct i2c_client *client)
ret = iio_device_register(indio_dev);
if (ret < 0)
- goto buffer_cleanup;
+ goto free_irq;
ret = mma8452_set_freefall_mode(data, false);
if (ret < 0)
@@ -1711,6 +1711,10 @@ static int mma8452_probe(struct i2c_client *client)
unregister_device:
iio_device_unregister(indio_dev);
+free_irq:
+ if (client->irq)
+ free_irq(client->irq, indio_dev);
+
buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
@@ -1736,6 +1740,9 @@ static void mma8452_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
+ if (client->irq)
+ free_irq(client->irq, indio_dev);
+
iio_triggered_buffer_cleanup(indio_dev);
mma8452_trigger_cleanup(indio_dev);
mma8452_standby(iio_priv(indio_dev));
@@ -1821,12 +1828,12 @@ static const struct dev_pm_ops mma8452_pm_ops = {
};
static const struct i2c_device_id mma8452_id[] = {
- { "fxls8471", (kernel_ulong_t)&mma_chip_info_table[fxls8471] },
- { "mma8451", (kernel_ulong_t)&mma_chip_info_table[mma8451] },
- { "mma8452", (kernel_ulong_t)&mma_chip_info_table[mma8452] },
- { "mma8453", (kernel_ulong_t)&mma_chip_info_table[mma8453] },
- { "mma8652", (kernel_ulong_t)&mma_chip_info_table[mma8652] },
- { "mma8653", (kernel_ulong_t)&mma_chip_info_table[mma8653] },
+ { .name = "fxls8471", .driver_data = (kernel_ulong_t)&mma_chip_info_table[fxls8471] },
+ { .name = "mma8451", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8451] },
+ { .name = "mma8452", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8452] },
+ { .name = "mma8453", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8453] },
+ { .name = "mma8652", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8652] },
+ { .name = "mma8653", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8653] },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma8452_id);
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index 02195deada49..7e01427fd9c4 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -6,7 +6,6 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -421,10 +420,8 @@ static int mma9551_gpio_probe(struct iio_dev *indio_dev)
NULL, mma9551_event_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"mma9551_event", indio_dev);
- if (ret < 0) {
- dev_err(dev, "request irq %d failed\n", data->irqs[i]);
+ if (ret)
return ret;
- }
dev_dbg(dev, "gpio resource, no:%d irq:%d\n",
desc_to_gpio(gpio), data->irqs[i]);
@@ -582,7 +579,7 @@ static const struct acpi_device_id mma9551_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match);
static const struct i2c_device_id mma9551_id[] = {
- { "mma9551" },
+ { .name = "mma9551" },
{ }
};
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index f85384a7908f..8e7aaac89d47 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -6,7 +6,6 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
@@ -1100,11 +1099,8 @@ static int mma9553_probe(struct i2c_client *client)
mma9553_event_handler,
IRQF_TRIGGER_RISING,
"mma9553_event", indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "request irq %d failed\n",
- client->irq);
+ if (ret)
goto out_poweroff;
- }
}
ret = pm_runtime_set_active(&client->dev);
@@ -1219,7 +1215,7 @@ static const struct acpi_device_id mma9553_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match);
static const struct i2c_device_id mma9553_id[] = {
- { "mma9553" },
+ { .name = "mma9553" },
{ }
};
diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c
index 5eace0de3750..caf9b1b6397f 100644
--- a/drivers/iio/accel/msa311.c
+++ b/drivers/iio/accel/msa311.c
@@ -28,7 +28,6 @@
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@@ -1060,7 +1059,7 @@ static int msa311_setup_interrupts(struct msa311_priv *msa311)
msa311_irq_thread, IRQF_ONESHOT,
msa311->chip_name, indio_dev);
if (err)
- return dev_err_probe(dev, err, "failed to request IRQ\n");
+ return err;
trig = devm_iio_trigger_alloc(dev, "%s-new-data", msa311->chip_name);
if (!trig)
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index a2c3cf13d098..a66fee828ec1 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/types.h>
#include <linux/iio/sysfs.h>
@@ -490,11 +489,8 @@ static int mxc4005_probe(struct i2c_client *client)
iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_FALLING | IRQF_NO_THREAD,
"mxc4005_event", data->dready_trig);
- if (ret) {
- dev_err(&client->dev,
- "failed to init threaded irq\n");
+ if (ret)
return ret;
- }
data->dready_trig->ops = &mxc4005_trigger_ops;
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
@@ -580,8 +576,8 @@ static const struct of_device_id mxc4005_of_match[] = {
MODULE_DEVICE_TABLE(of, mxc4005_of_match);
static const struct i2c_device_id mxc4005_id[] = {
- { "mxc4005" },
- { "mxc6655" },
+ { .name = "mxc4005" },
+ { .name = "mxc6655" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mxc4005_id);
diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c
index fc3ed84d1933..a9f41cf27ad9 100644
--- a/drivers/iio/accel/mxc6255.c
+++ b/drivers/iio/accel/mxc6255.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/iio/iio.h>
#include <linux/delay.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/iio/sysfs.h>
@@ -171,8 +170,8 @@ static const struct acpi_device_id mxc6255_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match);
static const struct i2c_device_id mxc6255_id[] = {
- { "mxc6225" },
- { "mxc6255" },
+ { .name = "mxc6225" },
+ { .name = "mxc6255" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mxc6255_id);
diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c
index 4a827be439a2..a92a563f6a4b 100644
--- a/drivers/iio/accel/sca3000.c
+++ b/drivers/iio/accel/sca3000.c
@@ -7,6 +7,7 @@
* See industrialio/accels/sca3000.h for comments.
*/
+#include <linux/cleanup.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/device.h>
@@ -171,6 +172,7 @@ struct sca3000_state {
/**
* struct sca3000_chip_info - model dependent parameters
+ * @name: name of the chip
* @scale: scale * 10^-6
* @temp_output: some devices have temperature sensors.
* @measurement_mode_freq: normal mode sampling frequency
@@ -193,6 +195,7 @@ struct sca3000_state {
* sca3000 variant.
**/
struct sca3000_chip_info {
+ const char *name;
unsigned int scale;
bool temp_output;
int measurement_mode_freq;
@@ -207,69 +210,59 @@ struct sca3000_chip_info {
int mot_det_mult_y[7];
};
-enum sca3000_variant {
- d01,
- e02,
- e04,
- e05,
+static const struct sca3000_chip_info sca3000_chip_info_d01 = {
+ .name = "sca3000_d01",
+ .scale = 7357,
+ .temp_output = true,
+ .measurement_mode_freq = 250,
+ .measurement_mode_3db_freq = 45,
+ .option_mode_1 = SCA3000_OP_MODE_BYPASS,
+ .option_mode_1_freq = 250,
+ .option_mode_1_3db_freq = 70,
+ .mot_det_mult_xz = { 50, 100, 200, 350, 650, 1300 },
+ .mot_det_mult_y = { 50, 100, 150, 250, 450, 850, 1750 },
};
-/*
- * Note where option modes are not defined, the chip simply does not
- * support any.
- * Other chips in the sca3000 series use i2c and are not included here.
- *
- * Some of these devices are only listed in the family data sheet and
- * do not actually appear to be available.
- */
-static const struct sca3000_chip_info sca3000_spi_chip_info_tbl[] = {
- [d01] = {
- .scale = 7357,
- .temp_output = true,
- .measurement_mode_freq = 250,
- .measurement_mode_3db_freq = 45,
- .option_mode_1 = SCA3000_OP_MODE_BYPASS,
- .option_mode_1_freq = 250,
- .option_mode_1_3db_freq = 70,
- .mot_det_mult_xz = {50, 100, 200, 350, 650, 1300},
- .mot_det_mult_y = {50, 100, 150, 250, 450, 850, 1750},
- },
- [e02] = {
- .scale = 9810,
- .measurement_mode_freq = 125,
- .measurement_mode_3db_freq = 40,
- .option_mode_1 = SCA3000_OP_MODE_NARROW,
- .option_mode_1_freq = 63,
- .option_mode_1_3db_freq = 11,
- .mot_det_mult_xz = {100, 150, 300, 550, 1050, 2050},
- .mot_det_mult_y = {50, 100, 200, 350, 700, 1350, 2700},
- },
- [e04] = {
- .scale = 19620,
- .measurement_mode_freq = 100,
- .measurement_mode_3db_freq = 38,
- .option_mode_1 = SCA3000_OP_MODE_NARROW,
- .option_mode_1_freq = 50,
- .option_mode_1_3db_freq = 9,
- .option_mode_2 = SCA3000_OP_MODE_WIDE,
- .option_mode_2_freq = 400,
- .option_mode_2_3db_freq = 70,
- .mot_det_mult_xz = {200, 300, 600, 1100, 2100, 4100},
- .mot_det_mult_y = {100, 200, 400, 7000, 1400, 2700, 54000},
- },
- [e05] = {
- .scale = 61313,
- .measurement_mode_freq = 200,
- .measurement_mode_3db_freq = 60,
- .option_mode_1 = SCA3000_OP_MODE_NARROW,
- .option_mode_1_freq = 50,
- .option_mode_1_3db_freq = 9,
- .option_mode_2 = SCA3000_OP_MODE_WIDE,
- .option_mode_2_freq = 400,
- .option_mode_2_3db_freq = 75,
- .mot_det_mult_xz = {600, 900, 1700, 3200, 6100, 11900},
- .mot_det_mult_y = {300, 600, 1200, 2000, 4100, 7800, 15600},
- },
+static const struct sca3000_chip_info sca3000_chip_info_e02 = {
+ .name = "sca3000_e02",
+ .scale = 9810,
+ .measurement_mode_freq = 125,
+ .measurement_mode_3db_freq = 40,
+ .option_mode_1 = SCA3000_OP_MODE_NARROW,
+ .option_mode_1_freq = 63,
+ .option_mode_1_3db_freq = 11,
+ .mot_det_mult_xz = { 100, 150, 300, 550, 1050, 2050 },
+ .mot_det_mult_y = { 50, 100, 200, 350, 700, 1350, 2700 },
+};
+
+static const struct sca3000_chip_info sca3000_chip_info_e04 = {
+ .name = "sca3000_e04",
+ .scale = 19620,
+ .measurement_mode_freq = 100,
+ .measurement_mode_3db_freq = 38,
+ .option_mode_1 = SCA3000_OP_MODE_NARROW,
+ .option_mode_1_freq = 50,
+ .option_mode_1_3db_freq = 9,
+ .option_mode_2 = SCA3000_OP_MODE_WIDE,
+ .option_mode_2_freq = 400,
+ .option_mode_2_3db_freq = 70,
+ .mot_det_mult_xz = { 200, 300, 600, 1100, 2100, 4100 },
+ .mot_det_mult_y = { 100, 200, 400, 7000, 1400, 2700, 54000 },
+};
+
+static const struct sca3000_chip_info sca3000_chip_info_e05 = {
+ .name = "sca3000_e05",
+ .scale = 61313,
+ .measurement_mode_freq = 200,
+ .measurement_mode_3db_freq = 60,
+ .option_mode_1 = SCA3000_OP_MODE_NARROW,
+ .option_mode_1_freq = 50,
+ .option_mode_1_3db_freq = 9,
+ .option_mode_2 = SCA3000_OP_MODE_WIDE,
+ .option_mode_2_freq = 400,
+ .option_mode_2_3db_freq = 75,
+ .mot_det_mult_xz = { 600, 900, 1700, 3200, 6100, 11900 },
+ .mot_det_mult_y = { 300, 600, 1200, 2000, 4100, 7800, 15600 },
};
static int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val)
@@ -1435,24 +1428,42 @@ static const struct iio_info sca3000_info = {
.write_event_config = &sca3000_write_event_config,
};
-static int sca3000_probe(struct spi_device *spi)
+static void sca3000_stop_all_interrupts(void *data)
{
+ struct iio_dev *indio_dev = data;
+ struct sca3000_state *st = iio_priv(indio_dev);
int ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1);
+ if (ret)
+ return;
+
+ sca3000_write_reg(st, SCA3000_REG_INT_MASK_ADDR,
+ (st->rx[0] &
+ ~(SCA3000_REG_INT_MASK_RING_THREE_QUARTER |
+ SCA3000_REG_INT_MASK_RING_HALF |
+ SCA3000_REG_INT_MASK_ALL_INTS)));
+}
+
+static int sca3000_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
struct sca3000_state *st;
struct iio_dev *indio_dev;
+ int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
- spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->lock);
- st->info = &sca3000_spi_chip_info_tbl[spi_get_device_id(spi)
- ->driver_data];
+ st->info = spi_get_device_match_data(spi);
- indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->name = st->info->name;
indio_dev->info = &sca3000_info;
if (st->info->temp_output) {
indio_dev->channels = sca3000_channels_with_temp;
@@ -1464,78 +1475,39 @@ static int sca3000_probe(struct spi_device *spi)
}
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = devm_iio_kfifo_buffer_setup(&spi->dev, indio_dev,
- &sca3000_ring_setup_ops);
+ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &sca3000_ring_setup_ops);
if (ret)
return ret;
if (spi->irq) {
- ret = request_threaded_irq(spi->irq,
- NULL,
- &sca3000_event_handler,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- "sca3000",
- indio_dev);
+ ret = devm_request_threaded_irq(dev, spi->irq, NULL,
+ &sca3000_event_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "sca3000",
+ indio_dev);
if (ret)
return ret;
}
ret = sca3000_clean_setup(st);
if (ret)
- goto error_free_irq;
+ return ret;
ret = sca3000_print_rev(indio_dev);
if (ret)
- goto error_free_irq;
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_free_irq;
-
- return 0;
-
-error_free_irq:
- if (spi->irq)
- free_irq(spi->irq, indio_dev);
-
- return ret;
-}
-
-static int sca3000_stop_all_interrupts(struct sca3000_state *st)
-{
- int ret;
+ return ret;
- mutex_lock(&st->lock);
- ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1);
+ ret = devm_add_action_or_reset(dev, sca3000_stop_all_interrupts, indio_dev);
if (ret)
- goto error_ret;
- ret = sca3000_write_reg(st, SCA3000_REG_INT_MASK_ADDR,
- (st->rx[0] &
- ~(SCA3000_REG_INT_MASK_RING_THREE_QUARTER |
- SCA3000_REG_INT_MASK_RING_HALF |
- SCA3000_REG_INT_MASK_ALL_INTS)));
-error_ret:
- mutex_unlock(&st->lock);
- return ret;
-}
-
-static void sca3000_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct sca3000_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
+ return ret;
- /* Must ensure no interrupts can be generated after this! */
- sca3000_stop_all_interrupts(st);
- if (spi->irq)
- free_irq(spi->irq, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id sca3000_id[] = {
- {"sca3000_d01", d01},
- {"sca3000_e02", e02},
- {"sca3000_e04", e04},
- {"sca3000_e05", e05},
+ { .name = "sca3000_d01", .driver_data = (kernel_ulong_t)&sca3000_chip_info_d01 },
+ { .name = "sca3000_e02", .driver_data = (kernel_ulong_t)&sca3000_chip_info_e02 },
+ { .name = "sca3000_e04", .driver_data = (kernel_ulong_t)&sca3000_chip_info_e04 },
+ { .name = "sca3000_e05", .driver_data = (kernel_ulong_t)&sca3000_chip_info_e05 },
{ }
};
MODULE_DEVICE_TABLE(spi, sca3000_id);
@@ -1545,7 +1517,6 @@ static struct spi_driver sca3000_driver = {
.name = "sca3000",
},
.probe = sca3000_probe,
- .remove = sca3000_remove,
.id_table = sca3000_id,
};
module_spi_driver(sca3000_driver);
diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c
index 8380b237831c..67582cc34149 100644
--- a/drivers/iio/accel/sca3300.c
+++ b/drivers/iio/accel/sca3300.c
@@ -664,8 +664,8 @@ 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" },
+ { .name = "sca3300" },
+ { .name = "scl3300" },
{ }
};
MODULE_DEVICE_TABLE(spi, sca3300_ids);
diff --git a/drivers/iio/accel/ssp_accel_sensor.c b/drivers/iio/accel/ssp_accel_sensor.c
index 3e572af2ec03..d1687cdd33ea 100644
--- a/drivers/iio/accel/ssp_accel_sensor.c
+++ b/drivers/iio/accel/ssp_accel_sensor.c
@@ -76,7 +76,7 @@ static const struct iio_chan_spec ssp_acc_channels[] = {
SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_X, SSP_CHANNEL_SCAN_INDEX_X),
SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_Y, SSP_CHANNEL_SCAN_INDEX_Y),
SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_Z, SSP_CHANNEL_SCAN_INDEX_Z),
- SSP_CHAN_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME),
+ IIO_CHAN_SOFT_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME),
};
static int ssp_process_accel_data(struct iio_dev *indio_dev, void *buf,
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index f24449500533..99522a885d71 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
@@ -138,32 +137,32 @@ static const struct acpi_device_id st_accel_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
static const struct i2c_device_id st_accel_id_table[] = {
- { LSM303DLH_ACCEL_DEV_NAME },
- { LSM303DLHC_ACCEL_DEV_NAME },
- { LIS3DH_ACCEL_DEV_NAME },
- { LSM330D_ACCEL_DEV_NAME },
- { LSM330DL_ACCEL_DEV_NAME },
- { LSM330DLC_ACCEL_DEV_NAME },
- { LIS331DLH_ACCEL_DEV_NAME },
- { LSM303DL_ACCEL_DEV_NAME },
- { LSM303DLM_ACCEL_DEV_NAME },
- { LSM330_ACCEL_DEV_NAME },
- { LSM303AGR_ACCEL_DEV_NAME },
- { LIS2DH12_ACCEL_DEV_NAME },
- { LIS3L02DQ_ACCEL_DEV_NAME },
- { LNG2DM_ACCEL_DEV_NAME },
- { H3LIS331DL_ACCEL_DEV_NAME },
- { LIS331DL_ACCEL_DEV_NAME },
- { LIS3LV02DL_ACCEL_DEV_NAME },
- { LIS2DW12_ACCEL_DEV_NAME },
- { LIS3DE_ACCEL_DEV_NAME },
- { LIS2DE12_ACCEL_DEV_NAME },
- { LIS2DS12_ACCEL_DEV_NAME },
- { LIS2HH12_ACCEL_DEV_NAME },
- { LIS302DL_ACCEL_DEV_NAME },
- { LSM303C_ACCEL_DEV_NAME },
- { SC7A20_ACCEL_DEV_NAME },
- { IIS328DQ_ACCEL_DEV_NAME },
+ { .name = LSM303DLH_ACCEL_DEV_NAME },
+ { .name = LSM303DLHC_ACCEL_DEV_NAME },
+ { .name = LIS3DH_ACCEL_DEV_NAME },
+ { .name = LSM330D_ACCEL_DEV_NAME },
+ { .name = LSM330DL_ACCEL_DEV_NAME },
+ { .name = LSM330DLC_ACCEL_DEV_NAME },
+ { .name = LIS331DLH_ACCEL_DEV_NAME },
+ { .name = LSM303DL_ACCEL_DEV_NAME },
+ { .name = LSM303DLM_ACCEL_DEV_NAME },
+ { .name = LSM330_ACCEL_DEV_NAME },
+ { .name = LSM303AGR_ACCEL_DEV_NAME },
+ { .name = LIS2DH12_ACCEL_DEV_NAME },
+ { .name = LIS3L02DQ_ACCEL_DEV_NAME },
+ { .name = LNG2DM_ACCEL_DEV_NAME },
+ { .name = H3LIS331DL_ACCEL_DEV_NAME },
+ { .name = LIS331DL_ACCEL_DEV_NAME },
+ { .name = LIS3LV02DL_ACCEL_DEV_NAME },
+ { .name = LIS2DW12_ACCEL_DEV_NAME },
+ { .name = LIS3DE_ACCEL_DEV_NAME },
+ { .name = LIS2DE12_ACCEL_DEV_NAME },
+ { .name = LIS2DS12_ACCEL_DEV_NAME },
+ { .name = LIS2HH12_ACCEL_DEV_NAME },
+ { .name = LIS302DL_ACCEL_DEV_NAME },
+ { .name = LSM303C_ACCEL_DEV_NAME },
+ { .name = SC7A20_ACCEL_DEV_NAME },
+ { .name = IIS328DQ_ACCEL_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index d8ec0555f42a..171f241c0a30 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
@@ -147,26 +146,26 @@ static int st_accel_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id st_accel_id_table[] = {
- { LIS3DH_ACCEL_DEV_NAME },
- { LSM330D_ACCEL_DEV_NAME },
- { LSM330DL_ACCEL_DEV_NAME },
- { LSM330DLC_ACCEL_DEV_NAME },
- { LIS331DLH_ACCEL_DEV_NAME },
- { LSM330_ACCEL_DEV_NAME },
- { LSM303AGR_ACCEL_DEV_NAME },
- { LIS2DH12_ACCEL_DEV_NAME },
- { LIS2DS12_ACCEL_DEV_NAME },
- { LIS3L02DQ_ACCEL_DEV_NAME },
- { LNG2DM_ACCEL_DEV_NAME },
- { H3LIS331DL_ACCEL_DEV_NAME },
- { LIS331DL_ACCEL_DEV_NAME },
- { LIS3LV02DL_ACCEL_DEV_NAME },
- { LIS2DW12_ACCEL_DEV_NAME },
- { LIS3DHH_ACCEL_DEV_NAME },
- { LIS3DE_ACCEL_DEV_NAME },
- { LIS302DL_ACCEL_DEV_NAME },
- { LSM303C_ACCEL_DEV_NAME },
- { IIS328DQ_ACCEL_DEV_NAME },
+ { .name = LIS3DH_ACCEL_DEV_NAME },
+ { .name = LSM330D_ACCEL_DEV_NAME },
+ { .name = LSM330DL_ACCEL_DEV_NAME },
+ { .name = LSM330DLC_ACCEL_DEV_NAME },
+ { .name = LIS331DLH_ACCEL_DEV_NAME },
+ { .name = LSM330_ACCEL_DEV_NAME },
+ { .name = LSM303AGR_ACCEL_DEV_NAME },
+ { .name = LIS2DH12_ACCEL_DEV_NAME },
+ { .name = LIS2DS12_ACCEL_DEV_NAME },
+ { .name = LIS3L02DQ_ACCEL_DEV_NAME },
+ { .name = LNG2DM_ACCEL_DEV_NAME },
+ { .name = H3LIS331DL_ACCEL_DEV_NAME },
+ { .name = LIS331DL_ACCEL_DEV_NAME },
+ { .name = LIS3LV02DL_ACCEL_DEV_NAME },
+ { .name = LIS2DW12_ACCEL_DEV_NAME },
+ { .name = LIS3DHH_ACCEL_DEV_NAME },
+ { .name = LIS3DE_ACCEL_DEV_NAME },
+ { .name = LIS302DL_ACCEL_DEV_NAME },
+ { .name = LSM303C_ACCEL_DEV_NAME },
+ { .name = IIS328DQ_ACCEL_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index f31c6ab3392d..50840c3440c4 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -7,12 +7,20 @@
* IIO driver for STK8312; 7-bit I2C address: 0x3D.
*/
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/delay.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/sysfs.h>
#include <linux/types.h>
+
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -542,11 +550,8 @@ static int stk8312_probe(struct i2c_client *client)
IRQF_ONESHOT,
"stk8312_event",
indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "request irq %d failed\n",
- client->irq);
+ if (ret)
goto err_power_off;
- }
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
@@ -630,8 +635,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend,
static const struct i2c_device_id stk8312_i2c_id[] = {
/* Deprecated in favour of lowercase form */
- { "STK8312" },
- { "stk8312" },
+ { .name = "STK8312" },
+ { .name = "stk8312" },
{ }
};
MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id);
diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c
index a9ff2a273fe1..6c1e286c0a1d 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -7,12 +7,18 @@
* STK8BA50 7-bit I2C address: 0x18.
*/
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/dev_printk.h>
+#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/sysfs.h>
#include <linux/types.h>
+
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -432,11 +438,8 @@ static int stk8ba50_probe(struct i2c_client *client)
stk8ba50_data_rdy_trig_poll,
IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
"stk8ba50_event", indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "request irq %d failed\n",
- client->irq);
+ if (ret)
goto err_power_off;
- }
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
@@ -519,7 +522,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend,
stk8ba50_resume);
static const struct i2c_device_id stk8ba50_i2c_id[] = {
- { "stk8ba50" },
+ { .name = "stk8ba50" },
{ }
};
MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id);
diff --git a/drivers/iio/adc/88pm886-gpadc.c b/drivers/iio/adc/88pm886-gpadc.c
index cffe35136685..938ba43c2c35 100644
--- a/drivers/iio/adc/88pm886-gpadc.c
+++ b/drivers/iio/adc/88pm886-gpadc.c
@@ -10,7 +10,6 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/math.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -280,7 +279,7 @@ static int pm886_gpadc_read_raw(struct iio_dev *iio, struct iio_chan_spec const
static int pm886_gpadc_hw_enable(struct regmap *map)
{
- const u8 config[] = {
+ static const u8 config[] = {
PM886_GPADC_CONFIG1_EN_ALL,
PM886_GPADC_CONFIG2_EN_ALL,
PM886_GPADC_GND_DET2_EN,
@@ -373,7 +372,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(pm886_gpadc_pm_ops,
pm886_gpadc_runtime_resume, NULL);
static const struct platform_device_id pm886_gpadc_id[] = {
- { "88pm886-gpadc" },
+ { .name = "88pm886-gpadc" },
{ }
};
MODULE_DEVICE_TABLE(platform, pm886_gpadc_id);
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 60038ae8dfc4..415e519ad4eb 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -33,7 +33,8 @@ config AB8500_GPADC
and USB voltages integral to the U8500 platform.
config AD_SIGMA_DELTA
- tristate
+ tristate "Analog Devices Sigma-Delta Modulator support" if COMPILE_TEST
+ depends on SPI
select IIO_BUFFER
select IIO_BUFFER_DMAENGINE
select IIO_TRIGGERED_BUFFER
@@ -60,9 +61,14 @@ config AD4030
tristate "Analog Devices AD4030 ADC Driver"
depends on SPI
depends on GPIOLIB
+ depends on PWM
select REGMAP
select IIO_BUFFER
+ select IIO_BUFFER_DMA
+ select IIO_BUFFER_DMAENGINE
select IIO_TRIGGERED_BUFFER
+ select SPI_OFFLOAD
+ select SPI_OFFLOAD_TRIGGER_PWM
help
Say yes here to build support for Analog Devices AD4030 and AD4630 high speed
SPI analog to digital converters (ADC).
@@ -73,6 +79,7 @@ config AD4030
config AD4062
tristate "Analog Devices AD4062 Driver"
depends on I3C
+ depends on GPIOLIB
select REGMAP_I3C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
@@ -102,6 +109,7 @@ config AD4130
depends on SPI
depends on GPIOLIB
select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
select IIO_KFIFO_BUF
select REGMAP_SPI
depends on COMMON_CLK
@@ -139,6 +147,22 @@ config AD4170_4
To compile this driver as a module, choose M here: the module will be
called ad4170-4.
+config AD4691
+ tristate "Analog Devices AD4691 Family ADC Driver"
+ depends on SPI
+ depends on REGULATOR || COMPILE_TEST
+ select IIO_BUFFER
+ select IIO_BUFFER_DMAENGINE
+ select IIO_TRIGGERED_BUFFER
+ select REGMAP
+ select SPI_OFFLOAD
+ help
+ Say yes here to build support for Analog Devices AD4691 Family MuxSAR
+ SPI analog to digital converters (ADC).
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad4691.
+
config AD4695
tristate "Analog Device AD4695 ADC Driver"
depends on SPI
@@ -306,6 +330,7 @@ config AD7298
config AD7380
tristate "Analog Devices AD7380 ADC driver"
depends on SPI_MASTER
+ select REGMAP
select SPI_OFFLOAD
select IIO_BUFFER
select IIO_BUFFER_DMAENGINE
@@ -409,12 +434,15 @@ config AD7766
config AD7768_1
tristate "Analog Devices AD7768-1 ADC driver"
depends on SPI
+ select GPIOLIB
select REGULATOR
select REGMAP_SPI
select RATIONAL
select IIO_BUFFER
+ select IIO_BUFFER_DMAENGINE
select IIO_TRIGGER
select IIO_TRIGGERED_BUFFER
+ select SPI_OFFLOAD
help
Say yes here to build support for Analog Devices AD7768-1 SPI
simultaneously sampling sigma-delta analog to digital converter (ADC).
@@ -427,6 +455,7 @@ config AD7779
depends on SPI
select CRC8
select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
select IIO_BACKEND
help
Say yes here to build support for Analog Devices AD777X family
@@ -917,6 +946,25 @@ config LTC2309
This driver can also be built as a module. If so, the module will
be called ltc2309.
+config LTC2378
+ tristate "Analog Devices LTC2378 ADC driver"
+ depends on SPI
+ depends on REGULATOR || COMPILE_TEST
+ depends on GPIOLIB
+ depends on PWM
+ select IIO_BUFFER
+ select IIO_BUFFER_DMA
+ select IIO_BUFFER_DMAENGINE
+ select IIO_TRIGGERED_BUFFER
+ select SPI_OFFLOAD
+ select SPI_OFFLOAD_TRIGGER_PWM
+ help
+ Say yes here to build support for Analog Devices LTC2378-20 and
+ similar analog to digital converters.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc2378.
+
config LTC2471
tristate "Linear Technology LTC2471 and LTC2473 ADC driver"
depends on I2C
@@ -1048,6 +1096,7 @@ config MAX1363
config MAX14001
tristate "Analog Devices MAX14001/MAX14002 ADC driver"
depends on SPI
+ select REGMAP
help
Say yes here to build support for Analog Devices MAX14001/MAX14002
Configurable, Isolated 10-bit ADCs for Multi-Range Binary Inputs.
@@ -1058,6 +1107,7 @@ config MAX14001
config MAX34408
tristate "Maxim max34408/max344089 ADC driver"
depends on I2C
+ select REGMAP_I2C
help
Say yes here to build support for Maxim max34408/max34409 current sense
monitor with 8-bits ADC interface with overcurrent delay/threshold and
@@ -1137,6 +1187,17 @@ config MCP3911
This driver can also be built as a module. If so, the module will be
called mcp3911.
+config MEDIATEK_MT6323_AUXADC
+ tristate "MediaTek MT6323 PMIC AUXADC driver"
+ depends on MFD_MT6397
+ help
+ Say yes here to enable support for MediaTek MT6323 PMIC Auxiliary ADC.
+ This driver provides multiple channels for system monitoring,
+ such as battery voltage, PMIC temperature, and others.
+
+ This driver can also be built as a module. If so, the module will be
+ called mt6323-auxadc.
+
config MEDIATEK_MT6359_AUXADC
tristate "MediaTek MT6359 PMIC AUXADC driver"
depends on MFD_MT6397
@@ -1347,7 +1408,7 @@ config QCOM_SPMI_VADC
be called qcom-spmi-vadc.
config QCOM_SPMI_ADC5
- tristate "Qualcomm Technologies Inc. SPMI PMIC5 ADC"
+ tristate "Qualcomm SPMI PMIC5 ADC"
depends on SPMI
select REGMAP_SPMI
select QCOM_VADC_COMMON
@@ -1366,6 +1427,32 @@ config QCOM_SPMI_ADC5
To compile this driver as a module, choose M here: the module will
be called qcom-spmi-adc5.
+config QCOM_SPMI_ADC5_GEN3
+ tristate "Qualcomm SPMI PMIC5 GEN3 ADC"
+ depends on SPMI && THERMAL
+ select REGMAP_SPMI
+ select QCOM_VADC_COMMON
+ select AUXILIARY_BUS
+ help
+ IIO Voltage PMIC5 Gen3 ADC driver for Qualcomm Technologies Inc.
+
+ The driver supports reading multiple channels. The ADC is a 16-bit
+ sigma-delta ADC. The hardware supports calibrated results for
+ conversion requests and clients include reading phone power supply
+ voltage, on board system thermistors connected to the PMIC ADC,
+ PMIC die temperature, charger temperature, battery current, USB
+ voltage input and voltage signals connected to supported PMIC GPIO
+ pins. The hardware supports internal pull-up for thermistors and can
+ choose between a 30k, 100k or 400k ohm pull up using the ADC channels.
+
+ In addition, the same driver supports ADC thermal monitoring devices
+ too. They appear as thermal zones with multiple trip points. A thermal
+ client sets threshold temperature for both warm and cool trips and
+ gets updated when a threshold is reached.
+
+ To compile this driver as a module, choose M here: the module will
+ be called qcom-spmi-adc5-gen3.
+
config RCAR_GYRO_ADC
tristate "Renesas R-Car GyroADC driver"
depends on ARCH_RCAR_GEN2 || COMPILE_TEST
@@ -1735,6 +1822,18 @@ config TI_ADS1119
This driver can also be built as a module. If so, the module will be
called ti-ads1119.
+config TI_ADS112C14
+ tristate "Texas Instruments ADS112C14/ADS122C14"
+ depends on I2C
+ select CRC8
+ select REGMAP
+ help
+ If you say yes here you get support for Texas Instruments ADS112C14,
+ ADS122C14 ADC chips.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads112c14.
+
config TI_ADS124S08
tristate "Texas Instruments ADS124S08"
depends on SPI
@@ -1910,6 +2009,39 @@ config TWL6030_GPADC
This driver can also be built as a module. If so, the module will be
called twl6030-gpadc.
+config VERSAL_SYSMON_CORE
+ tristate
+ select REGMAP
+
+config VERSAL_SYSMON
+ tristate "AMD Versal SysMon driver"
+ depends on ARCH_ZYNQMP || COMPILE_TEST
+ depends on HAS_IOMEM
+ select VERSAL_SYSMON_CORE
+ help
+ Say yes here to have support for the AMD/Xilinx Versal System
+ Monitor (SysMon). This driver provides voltage and temperature
+ monitoring through the IIO subsystem.
+
+ The SysMon measures up to 160 supply voltages and reads up to
+ 64 temperature satellites distributed across the SoC.
+
+ To compile this driver as a module, choose M here: the module
+ will be called versal-sysmon.
+
+config VERSAL_SYSMON_I2C
+ tristate "AMD Versal SysMon I2C driver"
+ depends on I2C
+ select VERSAL_SYSMON_CORE
+ help
+ Say yes here to have support for the AMD/Xilinx Versal System
+ Monitor (SysMon) via I2C interface. This driver enables voltage
+ and temperature monitoring when the Versal chip has SysMon
+ configured with I2C access.
+
+ To compile this driver as a module, choose M here: the module
+ will be called versal-sysmon-i2c.
+
config VF610_ADC
tristate "Freescale vf610 ADC driver"
depends on HAS_IOMEM
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index c76550415ff1..dcec0abb03b7 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_AD4080) += ad4080.o
obj-$(CONFIG_AD4130) += ad4130.o
obj-$(CONFIG_AD4134) += ad4134.o
obj-$(CONFIG_AD4170_4) += ad4170-4.o
+obj-$(CONFIG_AD4691) += ad4691.o
obj-$(CONFIG_AD4695) += ad4695.o
obj-$(CONFIG_AD4851) += ad4851.o
obj-$(CONFIG_AD7091R) += ad7091r-base.o
@@ -80,6 +81,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
obj-$(CONFIG_LTC2309) += ltc2309.o
+obj-$(CONFIG_LTC2378) += ltc2378.o
obj-$(CONFIG_LTC2471) += ltc2471.o
obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_LTC2496) += ltc2496.o ltc2497-core.o
@@ -99,6 +101,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MCP3564) += mcp3564.o
obj-$(CONFIG_MCP3911) += mcp3911.o
+obj-$(CONFIG_MEDIATEK_MT6323_AUXADC) += mt6323-auxadc.o
obj-$(CONFIG_MEDIATEK_MT6359_AUXADC) += mt6359-auxadc.o
obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
@@ -116,6 +119,7 @@ obj-$(CONFIG_PAC1934) += pac1934.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
+obj-$(CONFIG_QCOM_SPMI_ADC5_GEN3) += qcom-spmi-adc5-gen3.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_SPMI_RRADC) += qcom-spmi-rradc.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
@@ -151,6 +155,7 @@ obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS1018) += ti-ads1018.o
obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o
obj-$(CONFIG_TI_ADS1119) += ti-ads1119.o
+obj-$(CONFIG_TI_ADS112C14) += ti-ads112c14.o
obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o
obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
@@ -166,6 +171,9 @@ obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
obj-$(CONFIG_TI_TSC2046) += ti-tsc2046.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
+obj-$(CONFIG_VERSAL_SYSMON_CORE) += versal-sysmon-core.o
+obj-$(CONFIG_VERSAL_SYSMON) += versal-sysmon.o
+obj-$(CONFIG_VERSAL_SYSMON_I2C) += versal-sysmon-i2c.o
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o
diff --git a/drivers/iio/adc/ad4000.c b/drivers/iio/adc/ad4000.c
index fd3d79fca785..a33896b2cf97 100644
--- a/drivers/iio/adc/ad4000.c
+++ b/drivers/iio/adc/ad4000.c
@@ -12,7 +12,6 @@
#include <linux/err.h>
#include <linux/math.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/offload/consumer.h>
@@ -1177,37 +1176,37 @@ static int ad4000_probe(struct spi_device *spi)
}
static const struct spi_device_id ad4000_id[] = {
- { "ad4000", (kernel_ulong_t)&ad4000_chip_info },
- { "ad4001", (kernel_ulong_t)&ad4001_chip_info },
- { "ad4002", (kernel_ulong_t)&ad4002_chip_info },
- { "ad4003", (kernel_ulong_t)&ad4003_chip_info },
- { "ad4004", (kernel_ulong_t)&ad4004_chip_info },
- { "ad4005", (kernel_ulong_t)&ad4005_chip_info },
- { "ad4006", (kernel_ulong_t)&ad4006_chip_info },
- { "ad4007", (kernel_ulong_t)&ad4007_chip_info },
- { "ad4008", (kernel_ulong_t)&ad4008_chip_info },
- { "ad4010", (kernel_ulong_t)&ad4010_chip_info },
- { "ad4011", (kernel_ulong_t)&ad4011_chip_info },
- { "ad4020", (kernel_ulong_t)&ad4020_chip_info },
- { "ad4021", (kernel_ulong_t)&ad4021_chip_info },
- { "ad4022", (kernel_ulong_t)&ad4022_chip_info },
- { "adaq4001", (kernel_ulong_t)&adaq4001_chip_info },
- { "adaq4003", (kernel_ulong_t)&adaq4003_chip_info },
- { "ad7685", (kernel_ulong_t)&ad7685_chip_info },
- { "ad7686", (kernel_ulong_t)&ad7686_chip_info },
- { "ad7687", (kernel_ulong_t)&ad7687_chip_info },
- { "ad7688", (kernel_ulong_t)&ad7688_chip_info },
- { "ad7690", (kernel_ulong_t)&ad7690_chip_info },
- { "ad7691", (kernel_ulong_t)&ad7691_chip_info },
- { "ad7693", (kernel_ulong_t)&ad7693_chip_info },
- { "ad7942", (kernel_ulong_t)&ad7942_chip_info },
- { "ad7946", (kernel_ulong_t)&ad7946_chip_info },
- { "ad7980", (kernel_ulong_t)&ad7980_chip_info },
- { "ad7982", (kernel_ulong_t)&ad7982_chip_info },
- { "ad7983", (kernel_ulong_t)&ad7983_chip_info },
- { "ad7984", (kernel_ulong_t)&ad7984_chip_info },
- { "ad7988-1", (kernel_ulong_t)&ad7988_1_chip_info },
- { "ad7988-5", (kernel_ulong_t)&ad7988_5_chip_info },
+ { .name = "ad4000", .driver_data = (kernel_ulong_t)&ad4000_chip_info },
+ { .name = "ad4001", .driver_data = (kernel_ulong_t)&ad4001_chip_info },
+ { .name = "ad4002", .driver_data = (kernel_ulong_t)&ad4002_chip_info },
+ { .name = "ad4003", .driver_data = (kernel_ulong_t)&ad4003_chip_info },
+ { .name = "ad4004", .driver_data = (kernel_ulong_t)&ad4004_chip_info },
+ { .name = "ad4005", .driver_data = (kernel_ulong_t)&ad4005_chip_info },
+ { .name = "ad4006", .driver_data = (kernel_ulong_t)&ad4006_chip_info },
+ { .name = "ad4007", .driver_data = (kernel_ulong_t)&ad4007_chip_info },
+ { .name = "ad4008", .driver_data = (kernel_ulong_t)&ad4008_chip_info },
+ { .name = "ad4010", .driver_data = (kernel_ulong_t)&ad4010_chip_info },
+ { .name = "ad4011", .driver_data = (kernel_ulong_t)&ad4011_chip_info },
+ { .name = "ad4020", .driver_data = (kernel_ulong_t)&ad4020_chip_info },
+ { .name = "ad4021", .driver_data = (kernel_ulong_t)&ad4021_chip_info },
+ { .name = "ad4022", .driver_data = (kernel_ulong_t)&ad4022_chip_info },
+ { .name = "adaq4001", .driver_data = (kernel_ulong_t)&adaq4001_chip_info },
+ { .name = "adaq4003", .driver_data = (kernel_ulong_t)&adaq4003_chip_info },
+ { .name = "ad7685", .driver_data = (kernel_ulong_t)&ad7685_chip_info },
+ { .name = "ad7686", .driver_data = (kernel_ulong_t)&ad7686_chip_info },
+ { .name = "ad7687", .driver_data = (kernel_ulong_t)&ad7687_chip_info },
+ { .name = "ad7688", .driver_data = (kernel_ulong_t)&ad7688_chip_info },
+ { .name = "ad7690", .driver_data = (kernel_ulong_t)&ad7690_chip_info },
+ { .name = "ad7691", .driver_data = (kernel_ulong_t)&ad7691_chip_info },
+ { .name = "ad7693", .driver_data = (kernel_ulong_t)&ad7693_chip_info },
+ { .name = "ad7942", .driver_data = (kernel_ulong_t)&ad7942_chip_info },
+ { .name = "ad7946", .driver_data = (kernel_ulong_t)&ad7946_chip_info },
+ { .name = "ad7980", .driver_data = (kernel_ulong_t)&ad7980_chip_info },
+ { .name = "ad7982", .driver_data = (kernel_ulong_t)&ad7982_chip_info },
+ { .name = "ad7983", .driver_data = (kernel_ulong_t)&ad7983_chip_info },
+ { .name = "ad7984", .driver_data = (kernel_ulong_t)&ad7984_chip_info },
+ { .name = "ad7988-1", .driver_data = (kernel_ulong_t)&ad7988_1_chip_info },
+ { .name = "ad7988-5", .driver_data = (kernel_ulong_t)&ad7988_5_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad4000_id);
diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c
index 68446db9bef1..e97400a1aa48 100644
--- a/drivers/iio/adc/ad4030.c
+++ b/drivers/iio/adc/ad4030.c
@@ -14,15 +14,26 @@
*/
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/trigger_consumer.h>
-#include <linux/iio/triggered_buffer.h>
+#include <linux/dmaengine.h>
+#include <linux/limits.h>
+#include <linux/log2.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
+#include <linux/pwm.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/spi/offload/consumer.h>
#include <linux/spi/spi.h>
#include <linux/unaligned.h>
#include <linux/units.h>
+#include <linux/types.h>
+
+#include <linux/iio/buffer-dmaengine.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
#define AD4030_REG_INTERFACE_CONFIG_A 0x00
#define AD4030_REG_INTERFACE_CONFIG_A_SW_RESET (BIT(0) | BIT(7))
@@ -37,6 +48,8 @@
#define AD4030_REG_CHIP_GRADE_AD4630_24_GRADE 0x00
#define AD4030_REG_CHIP_GRADE_AD4632_16_GRADE 0x05
#define AD4030_REG_CHIP_GRADE_AD4632_24_GRADE 0x02
+#define AD4030_REG_CHIP_GRADE_ADAQ4216_GRADE 0x1E
+#define AD4030_REG_CHIP_GRADE_ADAQ4224_GRADE 0x1C
#define AD4030_REG_CHIP_GRADE_MASK_CHIP_GRADE GENMASK(7, 3)
#define AD4030_REG_SCRATCH_PAD 0x0A
#define AD4030_REG_SPI_REVISION 0x0B
@@ -111,6 +124,12 @@
#define AD4632_TCYC_NS 2000
#define AD4632_TCYC_ADJUSTED_NS (AD4632_TCYC_NS - AD4030_TCNVL_NS)
#define AD4030_TRESET_COM_DELAY_MS 750
+/* Datasheet says 9.8ns, so use the closest integer value */
+#define AD4030_TQUIET_CNV_DELAY_NS 10
+
+/* HARDWARE_GAIN */
+#define ADAQ4616_PGA_PINS 2
+#define ADAQ4616_PGA_GAIN_MAX_NANO (NANO * 2 / 3)
enum ad4030_out_mode {
AD4030_OUT_DATA_MD_DIFF,
@@ -132,15 +151,35 @@ enum {
AD4030_SCAN_TYPE_AVG,
};
+/*
+ * Gains computed as fractions of 1000 so they can be expressed by integers.
+ */
+static const int adaq4216_hw_gains_vpv[] = {
+ 1 * MILLI / 3, /* 0.333 */
+ 5 * MILLI / 9, /* 0.555 */
+ 20 * MILLI / 9, /* 0.2222 */
+ 20 * MILLI / 3, /* 0.6666 */
+};
+
+static const int adaq4216_hw_gains_frac[][2] = {
+ { 1, 3 }, /* 1/3 V/V gain */
+ { 5, 9 }, /* 5/9 V/V gain */
+ { 20, 9 }, /* 20/9 V/V gain */
+ { 20, 3 }, /* 20/3 V/V gain */
+};
+
struct ad4030_chip_info {
const char *name;
const unsigned long *available_masks;
const struct iio_chan_spec channels[AD4030_MAX_IIO_CHANNEL_NB];
+ const struct iio_chan_spec offload_channels[AD4030_MAX_IIO_CHANNEL_NB];
u8 grade;
u8 precision_bits;
+ bool has_pga;
/* Number of hardware channels */
int num_voltage_inputs;
unsigned int tcyc_ns;
+ unsigned int max_sample_rate_hz;
};
struct ad4030_state {
@@ -153,6 +192,18 @@ struct ad4030_state {
int offset_avail[3];
unsigned int avg_log2;
enum ad4030_out_mode mode;
+ /* Offload sampling */
+ struct spi_transfer offload_xfer;
+ struct spi_message offload_msg;
+ struct spi_offload *offload;
+ struct spi_offload_trigger *offload_trigger;
+ struct spi_offload_trigger_config offload_trigger_config;
+ struct pwm_device *cnv_trigger;
+ size_t scale_avail_size;
+ struct pwm_waveform cnv_wf;
+ unsigned int scale_avail[ARRAY_SIZE(adaq4216_hw_gains_vpv)][2];
+ struct gpio_descs *pga_gpios;
+ unsigned int pga_index;
/*
* DMA (thus cache coherency maintenance) requires the transfer buffers
@@ -209,8 +260,9 @@ struct ad4030_state {
* - voltage0-voltage1
* - voltage2-voltage3
*/
-#define AD4030_CHAN_DIFF(_idx, _scan_type) { \
+#define __AD4030_CHAN_DIFF(_idx, _scan_type, _offload, _pga) { \
.info_mask_shared_by_all = \
+ (_offload ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.info_mask_shared_by_all_available = \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
@@ -219,6 +271,7 @@ struct ad4030_state {
BIT(IIO_CHAN_INFO_CALIBBIAS) | \
BIT(IIO_CHAN_INFO_RAW), \
.info_mask_separate_available = BIT(IIO_CHAN_INFO_CALIBBIAS) | \
+ (_pga ? BIT(IIO_CHAN_INFO_SCALE) : 0) | \
BIT(IIO_CHAN_INFO_CALIBSCALE), \
.type = IIO_VOLTAGE, \
.indexed = 1, \
@@ -232,10 +285,33 @@ struct ad4030_state {
.num_ext_scan_type = ARRAY_SIZE(_scan_type), \
}
+#define AD4030_CHAN_DIFF(_idx, _scan_type) \
+ __AD4030_CHAN_DIFF(_idx, _scan_type, 0, 0)
+
+#define AD4030_OFFLOAD_CHAN_DIFF(_idx, _scan_type) \
+ __AD4030_CHAN_DIFF(_idx, _scan_type, 1, 0)
+
+#define ADAQ4216_CHAN_DIFF(_idx, _scan_type) \
+ __AD4030_CHAN_DIFF(_idx, _scan_type, 0, 1)
+
+#define ADAQ4216_OFFLOAD_CHAN_DIFF(_idx, _scan_type) \
+ __AD4030_CHAN_DIFF(_idx, _scan_type, 1, 1)
+
+/*
+ * AD4030 can average over 2^N samples, where N = 1, 2, 3, ..., 16.
+ * We use N = 0 to mean no sample averaging.
+ */
static const int ad4030_average_modes[] = {
- 1, 2, 4, 8, 16, 32, 64, 128,
- 256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
- 65536,
+ BIT(0), /* No sampling average */
+ BIT(1), BIT(2), BIT(3), BIT(4),
+ BIT(5), BIT(6), BIT(7), BIT(8),
+ BIT(9), BIT(10), BIT(11), BIT(12),
+ BIT(13), BIT(14), BIT(15), BIT(16),
+};
+
+static const struct spi_offload_config ad4030_offload_config = {
+ .capability_flags = SPI_OFFLOAD_CAP_TRIGGER |
+ SPI_OFFLOAD_CAP_RX_STREAM_DMA,
};
static int ad4030_enter_config_mode(struct ad4030_state *st)
@@ -377,6 +453,65 @@ static const struct regmap_config ad4030_regmap_config = {
.max_register = AD4030_REG_DIG_ERR,
};
+static void ad4030_fill_scale_avail(struct ad4030_state *st)
+{
+ unsigned int mag_bits, int_part, fract_part;
+ u64 range;
+
+ /*
+ * The maximum precision of differential channels is retrieved from the
+ * chip properties. The output code of differential channels is in two's
+ * complement format (i.e. signed), so the MSB is the sign bit and only
+ * (precision_bits - 1) bits express voltage magnitude.
+ */
+ mag_bits = st->chip->precision_bits - 1;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(adaq4216_hw_gains_frac); i++) {
+ range = mult_frac(st->vref_uv, adaq4216_hw_gains_frac[i][1],
+ adaq4216_hw_gains_frac[i][0]);
+ /*
+ * If range were in mV, we would multiply it by NANO below.
+ * Though, range is in µV so multiply it by MICRO only so the
+ * result after right shift and division scales output codes to
+ * millivolts.
+ */
+ int_part = div_u64_rem((range * MICRO) >> mag_bits, NANO, &fract_part);
+ st->scale_avail[i][0] = int_part;
+ st->scale_avail[i][1] = fract_part;
+ }
+}
+
+static int ad4030_set_pga_gain(struct ad4030_state *st)
+{
+ DECLARE_BITMAP(bitmap, ADAQ4616_PGA_PINS) = { };
+
+ bitmap_write(bitmap, st->pga_index, 0, ADAQ4616_PGA_PINS);
+
+ return gpiod_multi_set_value_cansleep(st->pga_gpios, bitmap);
+}
+
+static int ad4030_set_pga(struct iio_dev *indio_dev, int gain_int, int gain_fract)
+{
+ struct ad4030_state *st = iio_priv(indio_dev);
+ unsigned int mag_bits = st->chip->precision_bits - 1;
+ unsigned int tmp;
+ u64 gain_nano;
+
+ if (!st->pga_gpios)
+ return -EINVAL;
+
+ gain_nano = gain_int * NANO + gain_fract;
+ if (!in_range(gain_nano, 1, ADAQ4616_PGA_GAIN_MAX_NANO))
+ return -EINVAL;
+
+ tmp = DIV_ROUND_CLOSEST_ULL(gain_nano << mag_bits, NANO);
+ gain_nano = DIV_ROUND_CLOSEST(st->vref_uv, tmp);
+ st->pga_index = find_closest(gain_nano, adaq4216_hw_gains_vpv,
+ ARRAY_SIZE(adaq4216_hw_gains_vpv));
+
+ return ad4030_set_pga_gain(st);
+}
+
static int ad4030_get_chan_scale(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
@@ -389,6 +524,13 @@ static int ad4030_get_chan_scale(struct iio_dev *indio_dev,
if (IS_ERR(scan_type))
return PTR_ERR(scan_type);
+ /* The LSB of the 8-bit common-mode data is always vref/256. */
+ if (st->chip->has_pga && scan_type->realbits != 8) {
+ *val = st->scale_avail[st->pga_index][0];
+ *val2 = st->scale_avail[st->pga_index][1];
+ return IIO_VAL_INT_PLUS_NANO;
+ }
+
if (chan->differential)
*val = (st->vref_uv * 2) / MILLI;
else
@@ -451,6 +593,102 @@ static int ad4030_get_chan_calibbias(struct iio_dev *indio_dev,
}
}
+static void ad4030_get_sampling_freq(struct ad4030_state *st, int *freq)
+{
+ struct spi_offload_trigger_config *config = &st->offload_trigger_config;
+
+ /*
+ * Conversion data is fetched from the device when the offload transfer
+ * is triggered. Thus, provide the SPI offload trigger frequency as the
+ * sampling frequency.
+ */
+ *freq = config->periodic.frequency_hz;
+}
+
+static int ad4030_update_conversion_rate(struct ad4030_state *st,
+ unsigned int freq_hz, unsigned int avg_log2)
+{
+ struct spi_offload_trigger_config *config = &st->offload_trigger_config;
+ unsigned int offload_period_ns, cnv_rate_hz;
+ struct pwm_waveform cnv_wf = { };
+ u64 target = AD4030_TCNVH_NS;
+ u64 offload_offset_ns;
+ int ret;
+
+ /*
+ * When averaging/oversampling over N samples, we fire the offload
+ * trigger once at every N pulses of the CNV signal. Conversely, the CNV
+ * signal needs to be N times faster than the offload trigger. Take that
+ * into account to correctly re-evaluate both the PWM waveform connected
+ * to CNV and the SPI offload trigger.
+ */
+ cnv_rate_hz = freq_hz << avg_log2;
+
+ cnv_wf.period_length_ns = DIV_ROUND_CLOSEST(NSEC_PER_SEC, cnv_rate_hz);
+ /*
+ * The datasheet lists a minimum time of 9.8 ns, but no maximum. If the
+ * rounded PWM's value is less than 10, increase the target value by 10
+ * and attempt to round the waveform again, until the value is at least
+ * 10 ns. Use a separate variable to represent the target in case the
+ * rounding is severe enough to keep putting the first few results under
+ * the minimum 10ns condition checked by the while loop.
+ */
+ do {
+ cnv_wf.duty_length_ns = target;
+ ret = pwm_round_waveform_might_sleep(st->cnv_trigger, &cnv_wf);
+ if (ret)
+ return ret;
+ target += AD4030_TCNVH_NS;
+ } while (cnv_wf.duty_length_ns < AD4030_TCNVH_NS);
+
+ /*
+ * The CNV waveform period (period_length_ns) might get rounded down by
+ * pwm_round_waveform_might_sleep(). Check the resultant PWM period
+ * is not smaller than the minimum data conversion cycle time.
+ */
+ if (!in_range(cnv_wf.period_length_ns, AD4030_TCYC_NS, INT_MAX))
+ return -EINVAL;
+
+ offload_period_ns = DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq_hz);
+
+ config->periodic.frequency_hz = DIV_ROUND_UP(HZ_PER_GHZ, offload_period_ns);
+
+ /*
+ * The hardware does the capture on zone 2 (when SPI trigger PWM
+ * is used). This means that the SPI trigger signal should happen at
+ * tsync + tquiet_con_delay being tsync the conversion signal period
+ * and tquiet_con_delay 9.8ns. Hence set the PWM phase accordingly.
+ *
+ * The PWM waveform API only supports nanosecond resolution right now,
+ * so round this setting to the closest available value.
+ */
+ offload_offset_ns = AD4030_TQUIET_CNV_DELAY_NS;
+ do {
+ config->periodic.offset_ns = offload_offset_ns;
+ ret = spi_offload_trigger_validate(st->offload_trigger, config);
+ if (ret)
+ return ret;
+ offload_offset_ns += AD4030_TQUIET_CNV_DELAY_NS;
+ } while (config->periodic.offset_ns < AD4030_TQUIET_CNV_DELAY_NS);
+
+ st->cnv_wf = cnv_wf;
+
+ return 0;
+}
+
+static int ad4030_set_sampling_freq(struct iio_dev *indio_dev, int freq_hz)
+{
+ struct ad4030_state *st = iio_priv(indio_dev);
+
+ if (freq_hz == 0)
+ return -EINVAL;
+
+ if (!in_range(freq_hz, 0, st->chip->max_sample_rate_hz))
+ return -ERANGE;
+
+ return ad4030_update_conversion_rate(st, freq_hz, st->avg_log2);
+}
+
static int ad4030_set_chan_calibscale(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int gain_int,
@@ -510,11 +748,30 @@ static int ad4030_set_avg_frame_len(struct iio_dev *dev, int avg_val)
struct ad4030_state *st = iio_priv(dev);
unsigned int avg_log2 = ilog2(avg_val);
unsigned int last_avg_idx = ARRAY_SIZE(ad4030_average_modes) - 1;
+ int freq_hz;
int ret;
if (avg_val < 0 || avg_val > ad4030_average_modes[last_avg_idx])
return -EINVAL;
+ if (st->offload_trigger) {
+ /*
+ * The sample averaging and sampling frequency configurations
+ * are mutually dependent on each other. That's because the
+ * effective data sample rate is fCNV / 2^N, where N is the
+ * number of samples being averaged.
+ *
+ * When SPI offload is supported and we have control over the
+ * sample rate, the conversion start signal (CNV) and the SPI
+ * offload trigger frequencies must be re-evaluated so data is
+ * fetched only after 'avg_val' conversions.
+ */
+ ad4030_get_sampling_freq(st, &freq_hz);
+ ret = ad4030_update_conversion_rate(st, freq_hz, avg_log2);
+ if (ret)
+ return ret;
+ }
+
ret = regmap_write(st->regmap, AD4030_REG_AVG,
AD4030_REG_AVG_MASK_AVG_SYNC |
FIELD_PREP(AD4030_REG_AVG_MASK_AVG_VAL, avg_log2));
@@ -623,7 +880,7 @@ static int ad4030_conversion(struct iio_dev *indio_dev)
/* Add one byte if we are using a differential + common byte mode */
bytes_to_read += (st->mode == AD4030_OUT_DATA_MD_24_DIFF_8_COM ||
st->mode == AD4030_OUT_DATA_MD_16_DIFF_8_COM) ? 1 : 0;
- /* Mulitiply by the number of hardware channels */
+ /* Multiply by the number of hardware channels */
bytes_to_read *= st->chip->num_voltage_inputs;
for (i = 0; i < cnv_nb; i++) {
@@ -742,6 +999,15 @@ static int ad4030_read_avail(struct iio_dev *indio_dev,
*length = ARRAY_SIZE(ad4030_average_modes);
return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ if (st->scale_avail_size == 1)
+ *vals = (int *)st->scale_avail[st->pga_index];
+ else
+ *vals = (int *)st->scale_avail;
+ *length = st->scale_avail_size * 2; /* print int and nano part */
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_LIST;
+
default:
return -EINVAL;
}
@@ -767,6 +1033,10 @@ static int ad4030_read_raw_dispatch(struct iio_dev *indio_dev,
*val = BIT(st->avg_log2);
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ad4030_get_sampling_freq(st, val);
+ return IIO_VAL_INT;
+
default:
return -EINVAL;
}
@@ -807,6 +1077,12 @@ static int ad4030_write_raw_dispatch(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
return ad4030_set_avg_frame_len(indio_dev, val);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ad4030_set_sampling_freq(indio_dev, val);
+
+ case IIO_CHAN_INFO_SCALE:
+ return ad4030_set_pga(indio_dev, val, val2);
+
default:
return -EINVAL;
}
@@ -828,6 +1104,17 @@ static int ad4030_write_raw(struct iio_dev *indio_dev,
return ret;
}
+static int ad4030_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+}
+
static int ad4030_reg_access(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval)
{
@@ -874,6 +1161,7 @@ static const struct iio_info ad4030_iio_info = {
.read_avail = ad4030_read_avail,
.read_raw = ad4030_read_raw,
.write_raw = ad4030_write_raw,
+ .write_raw_get_fmt = &ad4030_write_raw_get_fmt,
.debugfs_reg_access = ad4030_reg_access,
.read_label = ad4030_read_label,
.get_current_scan_type = ad4030_get_current_scan_type,
@@ -896,6 +1184,86 @@ static const struct iio_buffer_setup_ops ad4030_buffer_setup_ops = {
.validate_scan_mask = ad4030_validate_scan_mask,
};
+static void ad4030_prepare_offload_msg(struct iio_dev *indio_dev)
+{
+ struct ad4030_state *st = iio_priv(indio_dev);
+ u8 offload_bpw;
+
+ if (st->mode == AD4030_OUT_DATA_MD_30_AVERAGED_DIFF)
+ offload_bpw = 32;
+ else
+ offload_bpw = st->chip->precision_bits;
+
+ st->offload_xfer.bits_per_word = offload_bpw;
+ st->offload_xfer.len = spi_bpw_to_bytes(offload_bpw);
+ st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
+ spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1);
+}
+
+static int ad4030_offload_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad4030_state *st = iio_priv(indio_dev);
+ unsigned int reg_modes;
+ int ret;
+
+ /*
+ * When data from 2 analog input channels is output through a single
+ * bus line (interleaved mode (LANE_MD == 0b11)) and gets pushed through
+ * DMA, extra hardware is required to do the de-interleaving. While we
+ * don't support such hardware configurations, disallow interleaved mode
+ * when using SPI offload.
+ */
+ ret = regmap_read(st->regmap, AD4030_REG_MODES, &reg_modes);
+ if (ret)
+ return ret;
+
+ if (st->chip->num_voltage_inputs > 1 &&
+ FIELD_GET(AD4030_REG_MODES_MASK_LANE_MODE, reg_modes) == AD4030_LANE_MD_INTERLEAVED)
+ return -EINVAL;
+
+ ad4030_prepare_offload_msg(indio_dev);
+ st->offload_msg.offload = st->offload;
+ ret = spi_optimize_message(st->spi, &st->offload_msg);
+ if (ret)
+ return ret;
+
+ ret = pwm_set_waveform_might_sleep(st->cnv_trigger, &st->cnv_wf, false);
+ if (ret)
+ goto out_unoptimize;
+
+ ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
+ &st->offload_trigger_config);
+ if (ret)
+ goto out_pwm_disable;
+
+ return 0;
+
+out_pwm_disable:
+ pwm_disable(st->cnv_trigger);
+out_unoptimize:
+ spi_unoptimize_message(&st->offload_msg);
+
+ return ret;
+}
+
+static int ad4030_offload_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad4030_state *st = iio_priv(indio_dev);
+
+ spi_offload_trigger_disable(st->offload, st->offload_trigger);
+
+ pwm_disable(st->cnv_trigger);
+
+ spi_unoptimize_message(&st->offload_msg);
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ad4030_offload_buffer_setup_ops = {
+ .postenable = &ad4030_offload_buffer_postenable,
+ .predisable = &ad4030_offload_buffer_predisable,
+};
+
static int ad4030_regulators_get(struct ad4030_state *st)
{
struct device *dev = &st->spi->dev;
@@ -965,6 +1333,24 @@ static int ad4030_detect_chip_info(const struct ad4030_state *st)
return 0;
}
+static int ad4030_pwm_get(struct ad4030_state *st)
+{
+ struct device *dev = &st->spi->dev;
+
+ st->cnv_trigger = devm_pwm_get(dev, NULL);
+ if (IS_ERR(st->cnv_trigger))
+ return dev_err_probe(dev, PTR_ERR(st->cnv_trigger),
+ "Failed to get CNV PWM\n");
+
+ /*
+ * Preemptively disable the PWM, since we only want to enable it with
+ * the buffer.
+ */
+ pwm_disable(st->cnv_trigger);
+
+ return 0;
+}
+
static int ad4030_config(struct ad4030_state *st)
{
int ret;
@@ -992,6 +1378,51 @@ static int ad4030_config(struct ad4030_state *st)
return 0;
}
+static int ad4030_spi_offload_setup(struct iio_dev *indio_dev,
+ struct ad4030_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ struct dma_chan *rx_dma;
+
+ indio_dev->setup_ops = &ad4030_offload_buffer_setup_ops;
+
+ st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload,
+ SPI_OFFLOAD_TRIGGER_PERIODIC);
+ if (IS_ERR(st->offload_trigger))
+ return dev_err_probe(dev, PTR_ERR(st->offload_trigger),
+ "failed to get offload trigger\n");
+
+ st->offload_trigger_config.type = SPI_OFFLOAD_TRIGGER_PERIODIC;
+
+ rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload);
+ if (IS_ERR(rx_dma))
+ return dev_err_probe(dev, PTR_ERR(rx_dma),
+ "failed to get offload RX DMA\n");
+
+ return devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma,
+ IIO_BUFFER_DIRECTION_IN);
+}
+
+static int ad4030_setup_pga(struct device *dev, struct iio_dev *indio_dev,
+ struct ad4030_state *st)
+{
+ /* Setup GPIOs for PGA control */
+ st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW);
+ if (IS_ERR(st->pga_gpios))
+ return dev_err_probe(dev, PTR_ERR(st->pga_gpios),
+ "Failed to get PGA gpios.\n");
+
+ if (st->pga_gpios->ndescs != ADAQ4616_PGA_PINS)
+ return dev_err_probe(dev, -EINVAL,
+ "Expected %d GPIOs for PGA control.\n",
+ ADAQ4616_PGA_PINS);
+
+ st->scale_avail_size = ARRAY_SIZE(adaq4216_hw_gains_vpv);
+ st->pga_index = 0;
+
+ return 0;
+}
+
static int ad4030_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
@@ -1034,6 +1465,14 @@ static int ad4030_probe(struct spi_device *spi)
if (ret)
return ret;
+ if (st->chip->has_pga) {
+ ret = ad4030_setup_pga(dev, indio_dev, st);
+ if (ret)
+ return ret;
+
+ ad4030_fill_scale_avail(st);
+ }
+
ret = ad4030_config(st);
if (ret)
return ret;
@@ -1043,24 +1482,58 @@ static int ad4030_probe(struct spi_device *spi)
return dev_err_probe(dev, PTR_ERR(st->cnv_gpio),
"Failed to get cnv gpio\n");
- /*
- * One hardware channel is split in two software channels when using
- * common byte mode. Add one more channel for the timestamp.
- */
- indio_dev->num_channels = 2 * st->chip->num_voltage_inputs + 1;
indio_dev->name = st->chip->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ad4030_iio_info;
- indio_dev->channels = st->chip->channels;
indio_dev->available_scan_masks = st->chip->available_masks;
- ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
- iio_pollfunc_store_time,
- ad4030_trigger_handler,
- &ad4030_buffer_setup_ops);
- if (ret)
- return dev_err_probe(dev, ret,
- "Failed to setup triggered buffer\n");
+ st->offload = devm_spi_offload_get(dev, spi, &ad4030_offload_config);
+ ret = PTR_ERR_OR_ZERO(st->offload);
+ /* Fall back to low speed usage when no SPI offload is available. */
+ if (ret == -ENODEV) {
+ /*
+ * One hardware channel is split in two software channels when
+ * using common byte mode. Add one more channel for the timestamp.
+ */
+ indio_dev->num_channels = 2 * st->chip->num_voltage_inputs + 1;
+ indio_dev->channels = st->chip->channels;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ iio_pollfunc_store_time,
+ ad4030_trigger_handler,
+ &ad4030_buffer_setup_ops);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to setup triggered buffer\n");
+ } else if (ret) {
+ return dev_err_probe(dev, ret, "failed to get offload\n");
+ } else {
+ /*
+ * Offloaded SPI transfers can't support software timestamp so
+ * no additional timestamp channel is added.
+ */
+ indio_dev->num_channels = st->chip->num_voltage_inputs;
+ indio_dev->channels = st->chip->offload_channels;
+ ret = ad4030_spi_offload_setup(indio_dev, st);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to setup SPI offload\n");
+
+ ret = ad4030_pwm_get(st);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get PWM\n");
+
+ /*
+ * Start with a slower sampling rate so there is some room for
+ * adjusting the sample averaging and the sampling frequency
+ * without hitting the maximum conversion rate.
+ */
+ ret = ad4030_update_conversion_rate(st, st->chip->max_sample_rate_hz >> 4,
+ st->avg_log2);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to set offload samp freq\n");
+ }
return devm_iio_device_register(dev, indio_dev);
}
@@ -1098,11 +1571,28 @@ static const struct iio_scan_type ad4030_24_scan_types[] = {
},
};
-static const struct iio_scan_type ad4030_16_scan_types[] = {
+static const struct iio_scan_type ad4030_24_offload_scan_types[] = {
[AD4030_SCAN_TYPE_NORMAL] = {
.sign = 's',
+ .realbits = 24,
.storagebits = 32,
+ .shift = 0,
+ .endianness = IIO_CPU,
+ },
+ [AD4030_SCAN_TYPE_AVG] = {
+ .sign = 's',
+ .realbits = 30,
+ .storagebits = 32,
+ .shift = 2,
+ .endianness = IIO_CPU,
+ },
+};
+
+static const struct iio_scan_type ad4030_16_scan_types[] = {
+ [AD4030_SCAN_TYPE_NORMAL] = {
+ .sign = 's',
.realbits = 16,
+ .storagebits = 32,
.shift = 16,
.endianness = IIO_BE,
},
@@ -1115,6 +1605,23 @@ static const struct iio_scan_type ad4030_16_scan_types[] = {
}
};
+static const struct iio_scan_type ad4030_16_offload_scan_types[] = {
+ [AD4030_SCAN_TYPE_NORMAL] = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 32,
+ .shift = 0,
+ .endianness = IIO_CPU,
+ },
+ [AD4030_SCAN_TYPE_AVG] = {
+ .sign = 's',
+ .realbits = 30,
+ .storagebits = 32,
+ .shift = 2,
+ .endianness = IIO_CPU,
+ },
+};
+
static const struct ad4030_chip_info ad4030_24_chip_info = {
.name = "ad4030-24",
.available_masks = ad4030_channel_masks,
@@ -1123,10 +1630,14 @@ static const struct ad4030_chip_info ad4030_24_chip_info = {
AD4030_CHAN_CMO(1, 0),
IIO_CHAN_SOFT_TIMESTAMP(2),
},
+ .offload_channels = {
+ AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types),
+ },
.grade = AD4030_REG_CHIP_GRADE_AD4030_24_GRADE,
.precision_bits = 24,
.num_voltage_inputs = 1,
.tcyc_ns = AD4030_TCYC_ADJUSTED_NS,
+ .max_sample_rate_hz = 2 * HZ_PER_MHZ,
};
static const struct ad4030_chip_info ad4630_16_chip_info = {
@@ -1139,10 +1650,15 @@ static const struct ad4030_chip_info ad4630_16_chip_info = {
AD4030_CHAN_CMO(3, 1),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
+ .offload_channels = {
+ AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_16_offload_scan_types),
+ AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_16_offload_scan_types),
+ },
.grade = AD4030_REG_CHIP_GRADE_AD4630_16_GRADE,
.precision_bits = 16,
.num_voltage_inputs = 2,
.tcyc_ns = AD4030_TCYC_ADJUSTED_NS,
+ .max_sample_rate_hz = 2 * HZ_PER_MHZ,
};
static const struct ad4030_chip_info ad4630_24_chip_info = {
@@ -1155,10 +1671,15 @@ static const struct ad4030_chip_info ad4630_24_chip_info = {
AD4030_CHAN_CMO(3, 1),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
+ .offload_channels = {
+ AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types),
+ AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_24_offload_scan_types),
+ },
.grade = AD4030_REG_CHIP_GRADE_AD4630_24_GRADE,
.precision_bits = 24,
.num_voltage_inputs = 2,
.tcyc_ns = AD4030_TCYC_ADJUSTED_NS,
+ .max_sample_rate_hz = 2 * HZ_PER_MHZ,
};
static const struct ad4030_chip_info ad4632_16_chip_info = {
@@ -1171,10 +1692,15 @@ static const struct ad4030_chip_info ad4632_16_chip_info = {
AD4030_CHAN_CMO(3, 1),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
+ .offload_channels = {
+ AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_16_offload_scan_types),
+ AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_16_offload_scan_types),
+ },
.grade = AD4030_REG_CHIP_GRADE_AD4632_16_GRADE,
.precision_bits = 16,
.num_voltage_inputs = 2,
.tcyc_ns = AD4632_TCYC_ADJUSTED_NS,
+ .max_sample_rate_hz = 500 * HZ_PER_KHZ,
};
static const struct ad4030_chip_info ad4632_24_chip_info = {
@@ -1187,18 +1713,63 @@ static const struct ad4030_chip_info ad4632_24_chip_info = {
AD4030_CHAN_CMO(3, 1),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
+ .offload_channels = {
+ AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types),
+ AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_24_offload_scan_types),
+ },
.grade = AD4030_REG_CHIP_GRADE_AD4632_24_GRADE,
.precision_bits = 24,
.num_voltage_inputs = 2,
.tcyc_ns = AD4632_TCYC_ADJUSTED_NS,
+ .max_sample_rate_hz = 500 * HZ_PER_KHZ,
+};
+
+static const struct ad4030_chip_info adaq4216_chip_info = {
+ .name = "adaq4216",
+ .available_masks = ad4030_channel_masks,
+ .channels = {
+ ADAQ4216_CHAN_DIFF(0, ad4030_16_scan_types),
+ AD4030_CHAN_CMO(1, 0),
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+ },
+ .offload_channels = {
+ ADAQ4216_OFFLOAD_CHAN_DIFF(0, ad4030_16_offload_scan_types),
+ },
+ .grade = AD4030_REG_CHIP_GRADE_ADAQ4216_GRADE,
+ .precision_bits = 16,
+ .has_pga = true,
+ .num_voltage_inputs = 1,
+ .tcyc_ns = AD4030_TCYC_ADJUSTED_NS,
+ .max_sample_rate_hz = 2 * HZ_PER_MHZ,
+};
+
+static const struct ad4030_chip_info adaq4224_chip_info = {
+ .name = "adaq4224",
+ .available_masks = ad4030_channel_masks,
+ .channels = {
+ ADAQ4216_CHAN_DIFF(0, ad4030_24_scan_types),
+ AD4030_CHAN_CMO(1, 0),
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+ },
+ .offload_channels = {
+ ADAQ4216_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types),
+ },
+ .grade = AD4030_REG_CHIP_GRADE_ADAQ4224_GRADE,
+ .precision_bits = 24,
+ .has_pga = true,
+ .num_voltage_inputs = 1,
+ .tcyc_ns = AD4030_TCYC_ADJUSTED_NS,
+ .max_sample_rate_hz = 2 * HZ_PER_MHZ,
};
static const struct spi_device_id ad4030_id_table[] = {
- { "ad4030-24", (kernel_ulong_t)&ad4030_24_chip_info },
- { "ad4630-16", (kernel_ulong_t)&ad4630_16_chip_info },
- { "ad4630-24", (kernel_ulong_t)&ad4630_24_chip_info },
- { "ad4632-16", (kernel_ulong_t)&ad4632_16_chip_info },
- { "ad4632-24", (kernel_ulong_t)&ad4632_24_chip_info },
+ { .name = "ad4030-24", .driver_data = (kernel_ulong_t)&ad4030_24_chip_info },
+ { .name = "ad4630-16", .driver_data = (kernel_ulong_t)&ad4630_16_chip_info },
+ { .name = "ad4630-24", .driver_data = (kernel_ulong_t)&ad4630_24_chip_info },
+ { .name = "ad4632-16", .driver_data = (kernel_ulong_t)&ad4632_16_chip_info },
+ { .name = "ad4632-24", .driver_data = (kernel_ulong_t)&ad4632_24_chip_info },
+ { .name = "adaq4216", .driver_data = (kernel_ulong_t)&adaq4216_chip_info },
+ { .name = "adaq4224", .driver_data = (kernel_ulong_t)&adaq4224_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad4030_id_table);
@@ -1209,6 +1780,8 @@ static const struct of_device_id ad4030_of_match[] = {
{ .compatible = "adi,ad4630-24", .data = &ad4630_24_chip_info },
{ .compatible = "adi,ad4632-16", .data = &ad4632_16_chip_info },
{ .compatible = "adi,ad4632-24", .data = &ad4632_24_chip_info },
+ { .compatible = "adi,adaq4216", .data = &adaq4216_chip_info },
+ { .compatible = "adi,adaq4224", .data = &adaq4224_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad4030_of_match);
@@ -1226,3 +1799,4 @@ module_spi_driver(ad4030_driver);
MODULE_AUTHOR("Esteban Blanc <eblanc@baylibre.com>");
MODULE_DESCRIPTION("Analog Devices AD4630 ADC family driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
diff --git a/drivers/iio/adc/ad4062.c b/drivers/iio/adc/ad4062.c
index dd4ad32aa6f5..8e5984055b15 100644
--- a/drivers/iio/adc/ad4062.c
+++ b/drivers/iio/adc/ad4062.c
@@ -436,10 +436,9 @@ static int ad4062_check_ids(struct ad4062_state *st)
return ret;
val = be16_to_cpu(st->buf.be16);
- if (val != AD4062_I3C_VENDOR) {
- dev_err(dev, "Vendor ID x%x does not match expected value\n", val);
- return -ENODEV;
- }
+ if (val != AD4062_I3C_VENDOR)
+ return dev_err_probe(dev, -ENODEV,
+ "Vendor ID x%x does not match expected value\n", val);
return 0;
}
@@ -719,10 +718,8 @@ static int ad4062_request_irq(struct iio_dev *indio_dev)
}
st->gpo_irq[1] = true;
- return devm_request_threaded_irq(dev, ret,
- ad4062_irq_handler_drdy,
- NULL, IRQF_ONESHOT, indio_dev->name,
- indio_dev);
+ return devm_request_irq(dev, ret, ad4062_irq_handler_drdy,
+ IRQF_NO_THREAD, indio_dev->name, indio_dev);
}
static const struct iio_trigger_ops ad4062_trigger_ops = {
@@ -955,7 +952,7 @@ static int ad4062_write_raw_dispatch(struct ad4062_state *st, int val, int val2,
default:
return -EINVAL;
}
-};
+}
static int ad4062_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
@@ -1199,11 +1196,14 @@ static int ad4062_write_event_value(struct iio_dev *indio_dev,
* The AD4062 in burst averaging mode increases realbits from 16-bits to
* 20-bits, increasing the storagebits from 16-bits to 32-bits.
*/
-static inline size_t ad4062_sizeof_storagebits(struct ad4062_state *st)
+static inline int ad4062_sizeof_storagebits(struct ad4062_state *st)
{
const struct iio_scan_type *scan_type =
iio_get_current_scan_type(st->indio_dev, st->chip->channels);
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
+
return BITS_TO_BYTES(scan_type->storagebits);
}
@@ -1233,7 +1233,12 @@ static int pm_ad4062_triggered_buffer_postenable(struct ad4062_state *st)
if (ret)
return ret;
- st->conv_sizeof = ad4062_sizeof_storagebits(st);
+ ret = ad4062_sizeof_storagebits(st);
+ if (ret < 0)
+ return ret;
+
+ st->conv_sizeof = ret;
+
st->conv_addr = ad4062_get_conv_addr(st, st->conv_sizeof);
/* CONV_READ requires read to trigger first sample. */
struct i3c_xfer xfer_sample[2] = {
diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c
index 7cf3b6ed7940..04cd6628ebff 100644
--- a/drivers/iio/adc/ad4080.c
+++ b/drivers/iio/adc/ad4080.c
@@ -13,9 +13,9 @@
#include <linux/err.h>
#include <linux/iio/backend.h>
#include <linux/iio/iio.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
@@ -127,10 +127,18 @@
#define AD4080_SPI_READ BIT(7)
#define AD4080_CHIP_ID 0x0050
#define AD4081_CHIP_ID 0x0051
+#define AD4082_CHIP_ID 0x0052
#define AD4083_CHIP_ID 0x0053
#define AD4084_CHIP_ID 0x0054
+#define AD4085_CHIP_ID 0x0055
#define AD4086_CHIP_ID 0x0056
#define AD4087_CHIP_ID 0x0057
+#define AD4088_CHIP_ID 0x0058
+#define AD4880_CHIP_ID 0x0059
+#define AD4883_CHIP_ID 0x005B
+#define AD4884_CHIP_ID 0x005C
+
+#define AD4080_MAX_CHANNELS 2
#define AD4080_LVDS_CNV_CLK_CNT_MAX 7
@@ -176,8 +184,9 @@ struct ad4080_chip_info {
};
struct ad4080_state {
- struct regmap *regmap;
- struct iio_backend *back;
+ struct spi_device *spi[AD4080_MAX_CHANNELS];
+ struct regmap *regmap[AD4080_MAX_CHANNELS];
+ struct iio_backend *back[AD4080_MAX_CHANNELS];
const struct ad4080_chip_info *info;
/*
* Synchronize access to members the of driver state, and ensure
@@ -185,9 +194,8 @@ struct ad4080_state {
*/
struct mutex lock;
unsigned int num_lanes;
- unsigned int dec_rate;
unsigned long clk_rate;
- enum ad4080_filter_type filter_type;
+ enum ad4080_filter_type filter_type[AD4080_MAX_CHANNELS];
bool lvds_cnv_en;
};
@@ -204,9 +212,9 @@ static int ad4080_reg_access(struct iio_dev *indio_dev, unsigned int reg,
struct ad4080_state *st = iio_priv(indio_dev);
if (readval)
- return regmap_read(st->regmap, reg, readval);
+ return regmap_read(st->regmap[0], reg, readval);
- return regmap_write(st->regmap, reg, writeval);
+ return regmap_write(st->regmap[0], reg, writeval);
}
static int ad4080_get_scale(struct ad4080_state *st, int *val, int *val2)
@@ -227,8 +235,9 @@ static unsigned int ad4080_get_dec_rate(struct iio_dev *dev,
struct ad4080_state *st = iio_priv(dev);
int ret;
unsigned int data;
+ unsigned int ch = chan->channel;
- ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data);
+ ret = regmap_read(st->regmap[ch], AD4080_REG_FILTER_CONFIG, &data);
if (ret)
return ret;
@@ -240,13 +249,14 @@ static int ad4080_set_dec_rate(struct iio_dev *dev,
unsigned int mode)
{
struct ad4080_state *st = iio_priv(dev);
+ unsigned int ch = chan->channel;
guard(mutex)(&st->lock);
- if ((st->filter_type >= SINC_5 && mode >= 512) || mode < 2)
+ if ((st->filter_type[ch] >= SINC_5 && mode >= 512) || mode < 2)
return -EINVAL;
- return regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG,
+ return regmap_update_bits(st->regmap[ch], AD4080_REG_FILTER_CONFIG,
AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK,
FIELD_PREP(AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK,
(ilog2(mode) - 1)));
@@ -266,15 +276,15 @@ static int ad4080_read_raw(struct iio_dev *indio_dev,
dec_rate = ad4080_get_dec_rate(indio_dev, chan);
if (dec_rate < 0)
return dec_rate;
- if (st->filter_type == SINC_5_COMP)
+ if (st->filter_type[chan->channel] == SINC_5_COMP)
dec_rate *= 2;
- if (st->filter_type)
+ if (st->filter_type[chan->channel])
*val = DIV_ROUND_CLOSEST(st->clk_rate, dec_rate);
else
*val = st->clk_rate;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
- if (st->filter_type == FILTER_NONE) {
+ if (st->filter_type[chan->channel] == FILTER_NONE) {
*val = 1;
} else {
*val = ad4080_get_dec_rate(indio_dev, chan);
@@ -295,7 +305,7 @@ static int ad4080_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
- if (st->filter_type == FILTER_NONE && val > 1)
+ if (st->filter_type[chan->channel] == FILTER_NONE && val > 1)
return -EINVAL;
return ad4080_set_dec_rate(indio_dev, chan, val);
@@ -304,23 +314,23 @@ static int ad4080_write_raw(struct iio_dev *indio_dev,
}
}
-static int ad4080_lvds_sync_write(struct ad4080_state *st)
+static int ad4080_lvds_sync_write(struct ad4080_state *st, unsigned int ch)
{
- struct device *dev = regmap_get_device(st->regmap);
+ struct device *dev = regmap_get_device(st->regmap[ch]);
int ret;
- ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
+ ret = regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A,
AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN);
if (ret)
return ret;
- ret = iio_backend_interface_data_align(st->back, 10000);
+ ret = iio_backend_interface_data_align(st->back[ch], 10000);
if (ret)
return dev_err_probe(dev, ret,
"Data alignment process failed\n");
dev_dbg(dev, "Success: Pattern correct and Locked!\n");
- return regmap_clear_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
+ return regmap_clear_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A,
AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN);
}
@@ -329,9 +339,10 @@ static int ad4080_get_filter_type(struct iio_dev *dev,
{
struct ad4080_state *st = iio_priv(dev);
unsigned int data;
+ unsigned int ch = chan->channel;
int ret;
- ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data);
+ ret = regmap_read(st->regmap[ch], AD4080_REG_FILTER_CONFIG, &data);
if (ret)
return ret;
@@ -343,6 +354,7 @@ static int ad4080_set_filter_type(struct iio_dev *dev,
unsigned int mode)
{
struct ad4080_state *st = iio_priv(dev);
+ unsigned int ch = chan->channel;
int dec_rate;
int ret;
@@ -355,18 +367,18 @@ static int ad4080_set_filter_type(struct iio_dev *dev,
if (mode >= SINC_5 && dec_rate >= 512)
return -EINVAL;
- ret = iio_backend_filter_type_set(st->back, mode);
+ ret = iio_backend_filter_type_set(st->back[ch], mode);
if (ret)
return ret;
- ret = regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG,
+ ret = regmap_update_bits(st->regmap[ch], AD4080_REG_FILTER_CONFIG,
AD4080_FILTER_CONFIG_FILTER_SEL_MSK,
FIELD_PREP(AD4080_FILTER_CONFIG_FILTER_SEL_MSK,
mode));
if (ret)
return ret;
- st->filter_type = mode;
+ st->filter_type[ch] = mode;
return 0;
}
@@ -380,14 +392,14 @@ static int ad4080_read_avail(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
- switch (st->filter_type) {
+ switch (st->filter_type[chan->channel]) {
case FILTER_NONE:
*vals = ad4080_dec_rate_none;
*length = ARRAY_SIZE(ad4080_dec_rate_none);
break;
default:
*vals = ad4080_dec_rate_avail;
- *length = st->filter_type >= SINC_5 ?
+ *length = st->filter_type[chan->channel] >= SINC_5 ?
(ARRAY_SIZE(ad4080_dec_rate_avail) - 2) :
ARRAY_SIZE(ad4080_dec_rate_avail);
break;
@@ -399,6 +411,28 @@ static int ad4080_read_avail(struct iio_dev *indio_dev,
}
}
+static int ad4880_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct ad4080_state *st = iio_priv(indio_dev);
+ int ret;
+
+ for (unsigned int ch = 0; ch < st->info->num_channels; ch++) {
+ /*
+ * Each backend has a single channel (channel 0 from the
+ * backend's perspective), so always use channel index 0.
+ */
+ if (test_bit(ch, scan_mask))
+ ret = iio_backend_chan_enable(st->back[ch], 0);
+ else
+ ret = iio_backend_chan_disable(st->back[ch], 0);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static const struct iio_info ad4080_iio_info = {
.debugfs_reg_access = ad4080_reg_access,
.read_raw = ad4080_read_raw,
@@ -406,6 +440,19 @@ static const struct iio_info ad4080_iio_info = {
.read_avail = ad4080_read_avail,
};
+/*
+ * AD4880 needs update_scan_mode to enable/disable individual backend channels.
+ * Single-channel devices don't need this as their backends may not implement
+ * chan_enable/chan_disable operations.
+ */
+static const struct iio_info ad4880_iio_info = {
+ .debugfs_reg_access = ad4080_reg_access,
+ .read_raw = ad4080_read_raw,
+ .write_raw = ad4080_write_raw,
+ .read_avail = ad4080_read_avail,
+ .update_scan_mode = ad4880_update_scan_mode,
+};
+
static const struct iio_enum ad4080_filter_type_enum = {
.items = ad4080_filter_type_iio_enum,
.num_items = ARRAY_SIZE(ad4080_filter_type_iio_enum),
@@ -420,17 +467,28 @@ static struct iio_chan_spec_ext_info ad4080_ext_info[] = {
{ }
};
-#define AD4080_CHANNEL_DEFINE(bits, storage) { \
+/*
+ * AD4880 needs per-channel filter configuration since each channel has
+ * its own independent ADC with separate SPI interface.
+ */
+static struct iio_chan_spec_ext_info ad4880_ext_info[] = {
+ IIO_ENUM("filter_type", IIO_SEPARATE, &ad4080_filter_type_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SEPARATE,
+ &ad4080_filter_type_enum),
+ { }
+};
+
+#define AD4080_CHANNEL_DEFINE(bits, storage, idx) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
- .channel = 0, \
+ .channel = (idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.info_mask_shared_by_all_available = \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.ext_info = ad4080_ext_info, \
- .scan_index = 0, \
+ .scan_index = (idx), \
.scan_type = { \
.sign = 's', \
.realbits = (bits), \
@@ -438,17 +496,61 @@ static struct iio_chan_spec_ext_info ad4080_ext_info[] = {
}, \
}
-static const struct iio_chan_spec ad4080_channel = AD4080_CHANNEL_DEFINE(20, 32);
+/*
+ * AD4880 has per-channel attributes (filter_type, oversampling_ratio,
+ * sampling_frequency) since each channel has its own independent ADC
+ * with separate SPI configuration interface.
+ */
+#define AD4880_CHANNEL_DEFINE(bits, storage, idx) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (idx), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_separate_available = \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .ext_info = ad4880_ext_info, \
+ .scan_index = (idx), \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = (storage), \
+ }, \
+}
+
+static const struct iio_chan_spec ad4080_channel = AD4080_CHANNEL_DEFINE(20, 32, 0);
-static const struct iio_chan_spec ad4081_channel = AD4080_CHANNEL_DEFINE(20, 32);
+static const struct iio_chan_spec ad4081_channel = AD4080_CHANNEL_DEFINE(20, 32, 0);
-static const struct iio_chan_spec ad4083_channel = AD4080_CHANNEL_DEFINE(16, 16);
+static const struct iio_chan_spec ad4082_channel = AD4080_CHANNEL_DEFINE(20, 32, 0);
-static const struct iio_chan_spec ad4084_channel = AD4080_CHANNEL_DEFINE(16, 16);
+static const struct iio_chan_spec ad4083_channel = AD4080_CHANNEL_DEFINE(16, 16, 0);
-static const struct iio_chan_spec ad4086_channel = AD4080_CHANNEL_DEFINE(14, 16);
+static const struct iio_chan_spec ad4084_channel = AD4080_CHANNEL_DEFINE(16, 16, 0);
-static const struct iio_chan_spec ad4087_channel = AD4080_CHANNEL_DEFINE(14, 16);
+static const struct iio_chan_spec ad4085_channel = AD4080_CHANNEL_DEFINE(16, 16, 0);
+
+static const struct iio_chan_spec ad4086_channel = AD4080_CHANNEL_DEFINE(14, 16, 0);
+
+static const struct iio_chan_spec ad4087_channel = AD4080_CHANNEL_DEFINE(14, 16, 0);
+
+static const struct iio_chan_spec ad4088_channel = AD4080_CHANNEL_DEFINE(14, 16, 0);
+
+static const struct iio_chan_spec ad4880_channels[] = {
+ AD4880_CHANNEL_DEFINE(20, 32, 0),
+ AD4880_CHANNEL_DEFINE(20, 32, 1),
+};
+
+static const struct iio_chan_spec ad4883_channels[] = {
+ AD4880_CHANNEL_DEFINE(16, 16, 0),
+ AD4880_CHANNEL_DEFINE(16, 16, 1),
+};
+
+static const struct iio_chan_spec ad4884_channels[] = {
+ AD4880_CHANNEL_DEFINE(16, 16, 0),
+ AD4880_CHANNEL_DEFINE(16, 16, 1),
+};
static const struct ad4080_chip_info ad4080_chip_info = {
.name = "ad4080",
@@ -470,6 +572,16 @@ static const struct ad4080_chip_info ad4081_chip_info = {
.lvds_cnv_clk_cnt_max = 2,
};
+static const struct ad4080_chip_info ad4082_chip_info = {
+ .name = "ad4082",
+ .product_id = AD4082_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 1,
+ .channels = &ad4082_channel,
+ .lvds_cnv_clk_cnt_max = 8,
+};
+
static const struct ad4080_chip_info ad4083_chip_info = {
.name = "ad4083",
.product_id = AD4083_CHIP_ID,
@@ -490,6 +602,16 @@ static const struct ad4080_chip_info ad4084_chip_info = {
.lvds_cnv_clk_cnt_max = 2,
};
+static const struct ad4080_chip_info ad4085_chip_info = {
+ .name = "ad4085",
+ .product_id = AD4085_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 1,
+ .channels = &ad4085_channel,
+ .lvds_cnv_clk_cnt_max = 8,
+};
+
static const struct ad4080_chip_info ad4086_chip_info = {
.name = "ad4086",
.product_id = AD4086_CHIP_ID,
@@ -510,25 +632,64 @@ static const struct ad4080_chip_info ad4087_chip_info = {
.lvds_cnv_clk_cnt_max = 1,
};
-static int ad4080_setup(struct iio_dev *indio_dev)
+static const struct ad4080_chip_info ad4088_chip_info = {
+ .name = "ad4088",
+ .product_id = AD4088_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 1,
+ .channels = &ad4088_channel,
+ .lvds_cnv_clk_cnt_max = 8,
+};
+
+static const struct ad4080_chip_info ad4880_chip_info = {
+ .name = "ad4880",
+ .product_id = AD4880_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 2,
+ .channels = ad4880_channels,
+ .lvds_cnv_clk_cnt_max = AD4080_LVDS_CNV_CLK_CNT_MAX,
+};
+
+static const struct ad4080_chip_info ad4883_chip_info = {
+ .name = "ad4883",
+ .product_id = AD4883_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 2,
+ .channels = ad4883_channels,
+ .lvds_cnv_clk_cnt_max = 5,
+};
+
+static const struct ad4080_chip_info ad4884_chip_info = {
+ .name = "ad4884",
+ .product_id = AD4884_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 2,
+ .channels = ad4884_channels,
+ .lvds_cnv_clk_cnt_max = 2,
+};
+
+static int ad4080_setup_channel(struct ad4080_state *st, unsigned int ch)
{
- struct ad4080_state *st = iio_priv(indio_dev);
- struct device *dev = regmap_get_device(st->regmap);
+ struct device *dev = regmap_get_device(st->regmap[ch]);
__le16 id_le;
u16 id;
int ret;
- ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A,
+ ret = regmap_write(st->regmap[ch], AD4080_REG_INTERFACE_CONFIG_A,
AD4080_INTERFACE_CONFIG_A_SW_RESET);
if (ret)
return ret;
- ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A,
+ ret = regmap_write(st->regmap[ch], AD4080_REG_INTERFACE_CONFIG_A,
AD4080_INTERFACE_CONFIG_A_SDO_ENABLE);
if (ret)
return ret;
- ret = regmap_bulk_read(st->regmap, AD4080_REG_PRODUCT_ID_L, &id_le,
+ ret = regmap_bulk_read(st->regmap[ch], AD4080_REG_PRODUCT_ID_L, &id_le,
sizeof(id_le));
if (ret)
return ret;
@@ -537,18 +698,23 @@ static int ad4080_setup(struct iio_dev *indio_dev)
if (id != st->info->product_id)
dev_info(dev, "Unrecognized CHIP_ID 0x%X\n", id);
- ret = regmap_set_bits(st->regmap, AD4080_REG_GPIO_CONFIG_A,
+ ret = regmap_set_bits(st->regmap[ch], AD4080_REG_GPIO_CONFIG_A,
AD4080_GPIO_CONFIG_A_GPO_1_EN);
if (ret)
return ret;
- ret = regmap_write(st->regmap, AD4080_REG_GPIO_CONFIG_B,
+ ret = regmap_write(st->regmap[ch], AD4080_REG_GPIO_CONFIG_B,
FIELD_PREP(AD4080_GPIO_CONFIG_B_GPIO_1_SEL_MSK,
AD4080_GPIO_CONFIG_B_GPIO_FILTER_RES_RDY));
if (ret)
return ret;
- ret = iio_backend_num_lanes_set(st->back, st->num_lanes);
+ ret = iio_backend_num_lanes_set(st->back[ch], st->num_lanes);
+ if (ret)
+ return ret;
+
+ ret = iio_backend_data_size_set(st->back[ch],
+ st->info->channels[0].scan_type.realbits);
if (ret)
return ret;
@@ -556,7 +722,7 @@ static int ad4080_setup(struct iio_dev *indio_dev)
return 0;
/* Set maximum LVDS Data Transfer Latency */
- ret = regmap_update_bits(st->regmap,
+ ret = regmap_update_bits(st->regmap[ch],
AD4080_REG_ADC_DATA_INTF_CONFIG_B,
AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK,
FIELD_PREP(AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK,
@@ -565,24 +731,38 @@ static int ad4080_setup(struct iio_dev *indio_dev)
return ret;
if (st->num_lanes > 1) {
- ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
+ ret = regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A,
AD4080_ADC_DATA_INTF_CONFIG_A_SPI_LVDS_LANES);
if (ret)
return ret;
}
- ret = regmap_set_bits(st->regmap,
+ ret = regmap_set_bits(st->regmap[ch],
AD4080_REG_ADC_DATA_INTF_CONFIG_B,
AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_EN);
if (ret)
return ret;
- return ad4080_lvds_sync_write(st);
+ return ad4080_lvds_sync_write(st, ch);
+}
+
+static int ad4080_setup(struct iio_dev *indio_dev)
+{
+ struct ad4080_state *st = iio_priv(indio_dev);
+ int ret;
+
+ for (unsigned int ch = 0; ch < st->info->num_channels; ch++) {
+ ret = ad4080_setup_channel(st, ch);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
-static int ad4080_properties_parse(struct ad4080_state *st)
+static int ad4080_properties_parse(struct ad4080_state *st,
+ struct device *dev)
{
- struct device *dev = regmap_get_device(st->regmap);
st->lvds_cnv_en = device_property_read_bool(dev, "adi,lvds-cnv-enable");
@@ -617,14 +797,28 @@ static int ad4080_probe(struct spi_device *spi)
return dev_err_probe(dev, ret,
"failed to get and enable supplies\n");
- st->regmap = devm_regmap_init_spi(spi, &ad4080_regmap_config);
- if (IS_ERR(st->regmap))
- return PTR_ERR(st->regmap);
+ /* Setup primary SPI device (channel 0) */
+ st->spi[0] = spi;
+ st->regmap[0] = devm_regmap_init_spi(spi, &ad4080_regmap_config);
+ if (IS_ERR(st->regmap[0]))
+ return PTR_ERR(st->regmap[0]);
st->info = spi_get_device_match_data(spi);
if (!st->info)
return -ENODEV;
+ /* Setup ancillary SPI devices for additional channels */
+ for (unsigned int ch = 1; ch < st->info->num_channels; ch++) {
+ st->spi[ch] = devm_spi_new_ancillary_device(spi, spi_get_chipselect(spi, ch));
+ if (IS_ERR(st->spi[ch]))
+ return dev_err_probe(dev, PTR_ERR(st->spi[ch]),
+ "failed to register ancillary device\n");
+
+ st->regmap[ch] = devm_regmap_init_spi(st->spi[ch], &ad4080_regmap_config);
+ if (IS_ERR(st->regmap[ch]))
+ return PTR_ERR(st->regmap[ch]);
+ }
+
ret = devm_mutex_init(dev, &st->lock);
if (ret)
return ret;
@@ -632,9 +826,10 @@ static int ad4080_probe(struct spi_device *spi)
indio_dev->name = st->info->name;
indio_dev->channels = st->info->channels;
indio_dev->num_channels = st->info->num_channels;
- indio_dev->info = &ad4080_iio_info;
+ indio_dev->info = st->info->num_channels > 1 ?
+ &ad4880_iio_info : &ad4080_iio_info;
- ret = ad4080_properties_parse(st);
+ ret = ad4080_properties_parse(st, dev);
if (ret)
return ret;
@@ -644,15 +839,25 @@ static int ad4080_probe(struct spi_device *spi)
st->clk_rate = clk_get_rate(clk);
- st->back = devm_iio_backend_get(dev, NULL);
- if (IS_ERR(st->back))
- return PTR_ERR(st->back);
+ /* Get backends for all channels */
+ for (unsigned int ch = 0; ch < st->info->num_channels; ch++) {
+ st->back[ch] = devm_iio_backend_get_by_index(dev, ch);
+ if (IS_ERR(st->back[ch]))
+ return PTR_ERR(st->back[ch]);
- ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
- if (ret)
- return ret;
+ ret = devm_iio_backend_enable(dev, st->back[ch]);
+ if (ret)
+ return ret;
+ }
- ret = devm_iio_backend_enable(dev, st->back);
+ /*
+ * Request buffer from the first backend only. For multi-channel
+ * devices (e.g., AD4880), the FPGA uses two axi_ad408x IP instances
+ * (one per ADC channel) whose outputs are combined by a packer block
+ * that interleaves all channel data into a single DMA stream routed
+ * through the first backend's clock domain.
+ */
+ ret = devm_iio_backend_request_buffer(dev, st->back[0], indio_dev);
if (ret)
return ret;
@@ -664,12 +869,18 @@ static int ad4080_probe(struct spi_device *spi)
}
static const struct spi_device_id ad4080_id[] = {
- { "ad4080", (kernel_ulong_t)&ad4080_chip_info },
- { "ad4081", (kernel_ulong_t)&ad4081_chip_info },
- { "ad4083", (kernel_ulong_t)&ad4083_chip_info },
- { "ad4084", (kernel_ulong_t)&ad4084_chip_info },
- { "ad4086", (kernel_ulong_t)&ad4086_chip_info },
- { "ad4087", (kernel_ulong_t)&ad4087_chip_info },
+ { .name = "ad4080", .driver_data = (kernel_ulong_t)&ad4080_chip_info },
+ { .name = "ad4081", .driver_data = (kernel_ulong_t)&ad4081_chip_info },
+ { .name = "ad4082", .driver_data = (kernel_ulong_t)&ad4082_chip_info },
+ { .name = "ad4083", .driver_data = (kernel_ulong_t)&ad4083_chip_info },
+ { .name = "ad4084", .driver_data = (kernel_ulong_t)&ad4084_chip_info },
+ { .name = "ad4085", .driver_data = (kernel_ulong_t)&ad4085_chip_info },
+ { .name = "ad4086", .driver_data = (kernel_ulong_t)&ad4086_chip_info },
+ { .name = "ad4087", .driver_data = (kernel_ulong_t)&ad4087_chip_info },
+ { .name = "ad4088", .driver_data = (kernel_ulong_t)&ad4088_chip_info },
+ { .name = "ad4880", .driver_data = (kernel_ulong_t)&ad4880_chip_info },
+ { .name = "ad4883", .driver_data = (kernel_ulong_t)&ad4883_chip_info },
+ { .name = "ad4884", .driver_data = (kernel_ulong_t)&ad4884_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad4080_id);
@@ -677,10 +888,16 @@ MODULE_DEVICE_TABLE(spi, ad4080_id);
static const struct of_device_id ad4080_of_match[] = {
{ .compatible = "adi,ad4080", &ad4080_chip_info },
{ .compatible = "adi,ad4081", &ad4081_chip_info },
+ { .compatible = "adi,ad4082", &ad4082_chip_info },
{ .compatible = "adi,ad4083", &ad4083_chip_info },
{ .compatible = "adi,ad4084", &ad4084_chip_info },
+ { .compatible = "adi,ad4085", &ad4085_chip_info },
{ .compatible = "adi,ad4086", &ad4086_chip_info },
{ .compatible = "adi,ad4087", &ad4087_chip_info },
+ { .compatible = "adi,ad4088", &ad4088_chip_info },
+ { .compatible = "adi,ad4880", &ad4880_chip_info },
+ { .compatible = "adi,ad4883", &ad4883_chip_info },
+ { .compatible = "adi,ad4884", &ad4884_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad4080_of_match);
diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c
index 5567ae5dee88..3ffc4b765e0e 100644
--- a/drivers/iio/adc/ad4130.c
+++ b/drivers/iio/adc/ad4130.c
@@ -9,6 +9,7 @@
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -21,6 +22,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
+#include <linux/types.h>
#include <linux/units.h>
#include <asm/div64.h>
@@ -30,6 +32,9 @@
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
#define AD4130_NAME "ad4130"
@@ -40,6 +45,7 @@
#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_ADC_CONTROL_CONT_READ_MASK BIT(11)
#define AD4130_INT_REF_2_5V 2500000
#define AD4130_INT_REF_1_25V 1250000
#define AD4130_ADC_CONTROL_CSB_EN_MASK BIT(9)
@@ -54,7 +60,9 @@
#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_4_IO_CONTROL_GPIO_DATA_MASK GENMASK(7, 6)
#define AD4130_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 0)
+#define AD4130_4_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 2)
#define AD4130_VBIAS_REG 0x04
@@ -125,6 +133,28 @@
#define AD4130_INVALID_SLOT -1
+static const unsigned int ad4129_reg_size[] = {
+ [AD4130_STATUS_REG] = 1,
+ [AD4130_ADC_CONTROL_REG] = 2,
+ [AD4130_DATA_REG] = 2,
+ [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)] = 2,
+ [AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 2,
+ [AD4130_MISC_REG] = 2,
+ [AD4130_FIFO_CONTROL_REG] = 3,
+ [AD4130_FIFO_STATUS_REG] = 1,
+ [AD4130_FIFO_THRESHOLD_REG] = 3,
+ [AD4130_FIFO_DATA_REG] = 2,
+};
+
static const unsigned int ad4130_reg_size[] = {
[AD4130_STATUS_REG] = 1,
[AD4130_ADC_CONTROL_REG] = 2,
@@ -147,6 +177,24 @@ static const unsigned int ad4130_reg_size[] = {
[AD4130_FIFO_DATA_REG] = 3,
};
+static const unsigned int ad4131_reg_size[] = {
+ [AD4130_STATUS_REG] = 1,
+ [AD4130_ADC_CONTROL_REG] = 2,
+ [AD4130_DATA_REG] = 2,
+ [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)] = 2,
+ [AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 2,
+ [AD4130_MISC_REG] = 2,
+};
+
enum ad4130_int_ref_val {
AD4130_INT_REF_VAL_2_5V,
AD4130_INT_REF_VAL_1_25V,
@@ -224,6 +272,28 @@ enum ad4130_pin_function {
AD4130_PIN_FN_VBIAS = BIT(3),
};
+/* Pin mapping for AIN0..AIN7, VBIAS_0..VBIAS_7 */
+static const u8 ad4130_4_pin_map[] = {
+ 0x00, 0x01, 0x04, 0x05, 0x0A, 0x0B, 0x0E, 0x0F, /* 0 - 7 */
+};
+
+/* Pin mapping for AIN0..AIN15, VBIAS_0..VBIAS_15 */
+static const u8 ad4130_8_pin_map[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0 - 7 */
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 8 - 15 */
+};
+
+struct ad4130_chip_info {
+ const char *name;
+ unsigned int max_analog_pins;
+ unsigned int num_gpios;
+ const struct iio_info *info;
+ const unsigned int *reg_size;
+ const unsigned int reg_size_length;
+ const u8 *pin_map;
+ bool has_fifo;
+};
+
/*
* If you make adaptations in this struct, you most likely also have to adapt
* ad4130_setup_info_eq(), too.
@@ -268,6 +338,7 @@ struct ad4130_state {
struct regmap *regmap;
struct spi_device *spi;
struct clk *mclk;
+ const struct ad4130_chip_info *chip_info;
struct regulator_bulk_data regulators[4];
u32 irq_trigger;
u32 inv_irq_trigger;
@@ -294,6 +365,7 @@ struct ad4130_state {
u32 mclk_sel;
bool int_ref_en;
bool bipolar;
+ bool buffer_wait_for_irq;
unsigned int num_enabled_channels;
unsigned int effective_watermark;
@@ -301,6 +373,7 @@ struct ad4130_state {
struct spi_message fifo_msg;
struct spi_transfer fifo_xfer[2];
+ struct iio_trigger *trig;
/*
* DMA (thus cache coherency maintenance) requires any transfer
@@ -312,9 +385,13 @@ struct ad4130_state {
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];
+ union {
+ struct {
+ u8 fifo_tx_buf[2];
+ u8 fifo_rx_buf[AD4130_FIFO_SIZE * AD4130_FIFO_MAX_SAMPLE_SIZE];
+ };
+ IIO_DECLARE_BUFFER_WITH_TS(u32, scan_channels, AD4130_MAX_CHANNELS);
+ };
};
static const char * const ad4130_int_pin_names[] = {
@@ -394,10 +471,10 @@ static const char * const ad4130_filter_types_str[] = {
static int ad4130_get_reg_size(struct ad4130_state *st, unsigned int reg,
unsigned int *size)
{
- if (reg >= ARRAY_SIZE(ad4130_reg_size))
+ if (reg >= st->chip_info->reg_size_length)
return -EINVAL;
- *size = ad4130_reg_size[reg];
+ *size = st->chip_info->reg_size[reg];
return 0;
}
@@ -505,7 +582,8 @@ static int ad4130_gpio_init_valid_mask(struct gpio_chip *gc,
/*
* Output-only GPIO functionality is available on pins AIN2 through
- * AIN5. If these pins are used for anything else, do not expose them.
+ * AIN5 for some parts and AIN2 through AIN3 for others. 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;
@@ -526,8 +604,14 @@ static int 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));
+ unsigned int mask;
+
+ if (st->chip_info->num_gpios == AD4130_MAX_GPIOS)
+ mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK,
+ BIT(offset));
+ else
+ mask = FIELD_PREP(AD4130_4_IO_CONTROL_GPIO_DATA_MASK,
+ BIT(offset));
return regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask,
value ? mask : 0);
@@ -588,10 +672,43 @@ 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
+ if (iio_buffer_enabled(indio_dev)) {
+ if (st->chip_info->has_fifo)
+ ad4130_push_fifo_data(indio_dev);
+ else if (st->buffer_wait_for_irq)
+ complete(&st->completion);
+ else
+ iio_trigger_poll(st->trig);
+ } else {
complete(&st->completion);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ad4130_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad4130_state *st = iio_priv(indio_dev);
+ unsigned int data_reg_size = ad4130_data_reg_size(st);
+ struct spi_transfer xfer = { };
+ unsigned int num_en_chn;
+ int ret;
+
+ num_en_chn = bitmap_weight(indio_dev->active_scan_mask,
+ iio_get_masklength(indio_dev));
+ xfer.rx_buf = st->scan_channels;
+ xfer.len = data_reg_size * num_en_chn;
+ ret = spi_sync_transfer(st->spi, &xfer, 1);
+ if (ret < 0)
+ goto err_out;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->scan_channels,
+ iio_get_time_ns(indio_dev));
+
+err_out:
+ iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
@@ -1291,6 +1408,79 @@ static const struct iio_info ad4130_info = {
.debugfs_reg_access = ad4130_reg_access,
};
+static const struct iio_info ad4131_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,
+ .debugfs_reg_access = ad4130_reg_access,
+};
+
+static const struct ad4130_chip_info ad4129_4_chip_info = {
+ .name = "ad4129-4",
+ .max_analog_pins = 8,
+ .num_gpios = 2,
+ .info = &ad4130_info,
+ .reg_size = ad4129_reg_size,
+ .reg_size_length = ARRAY_SIZE(ad4129_reg_size),
+ .has_fifo = true,
+ .pin_map = ad4130_4_pin_map,
+};
+
+static const struct ad4130_chip_info ad4129_8_chip_info = {
+ .name = "ad4129-8",
+ .max_analog_pins = 16,
+ .num_gpios = 4,
+ .info = &ad4130_info,
+ .reg_size = ad4129_reg_size,
+ .reg_size_length = ARRAY_SIZE(ad4129_reg_size),
+ .has_fifo = true,
+ .pin_map = ad4130_8_pin_map,
+};
+
+static const struct ad4130_chip_info ad4130_4_chip_info = {
+ .name = "ad4130-4",
+ .max_analog_pins = 16,
+ .num_gpios = 2,
+ .info = &ad4130_info,
+ .reg_size = ad4130_reg_size,
+ .reg_size_length = ARRAY_SIZE(ad4130_reg_size),
+ .has_fifo = true,
+ .pin_map = ad4130_4_pin_map,
+};
+
+static const struct ad4130_chip_info ad4130_8_chip_info = {
+ .name = "ad4130-8",
+ .max_analog_pins = 16,
+ .num_gpios = 4,
+ .info = &ad4130_info,
+ .reg_size = ad4130_reg_size,
+ .reg_size_length = ARRAY_SIZE(ad4130_reg_size),
+ .has_fifo = true,
+ .pin_map = ad4130_8_pin_map,
+};
+
+static const struct ad4130_chip_info ad4131_4_chip_info = {
+ .name = "ad4131-4",
+ .max_analog_pins = 8,
+ .num_gpios = 2,
+ .info = &ad4131_info,
+ .reg_size = ad4131_reg_size,
+ .reg_size_length = ARRAY_SIZE(ad4131_reg_size),
+ .pin_map = ad4130_4_pin_map,
+};
+
+static const struct ad4130_chip_info ad4131_8_chip_info = {
+ .name = "ad4131-8",
+ .max_analog_pins = 16,
+ .num_gpios = 4,
+ .info = &ad4131_info,
+ .reg_size = ad4131_reg_size,
+ .reg_size_length = ARRAY_SIZE(ad4131_reg_size),
+ .pin_map = ad4130_8_pin_map,
+};
+
static int ad4130_buffer_postenable(struct iio_dev *indio_dev)
{
struct ad4130_state *st = iio_priv(indio_dev);
@@ -1298,44 +1488,89 @@ static int ad4130_buffer_postenable(struct iio_dev *indio_dev)
guard(mutex)(&st->lock);
- ret = ad4130_set_watermark_interrupt_en(st, true);
- if (ret)
- return ret;
+ if (st->chip_info->has_fifo) {
+ ret = ad4130_set_watermark_interrupt_en(st, true);
+ if (ret)
+ return ret;
- ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger);
- if (ret)
- return ret;
+ ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger);
+ if (ret)
+ return ret;
+
+ ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM);
+ if (ret)
+ return ret;
+ }
- ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM);
+ ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
if (ret)
return ret;
- return ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
+ /*
+ * When using triggered buffer, Entering continuous read mode must
+ * be the last command sent. No configuration changes are allowed until
+ * exiting this mode.
+ */
+ if (!st->chip_info->has_fifo) {
+ ret = regmap_update_bits(st->regmap, AD4130_ADC_CONTROL_REG,
+ AD4130_ADC_CONTROL_CONT_READ_MASK,
+ FIELD_PREP(AD4130_ADC_CONTROL_CONT_READ_MASK, 1));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static int ad4130_buffer_predisable(struct iio_dev *indio_dev)
{
struct ad4130_state *st = iio_priv(indio_dev);
unsigned int i;
+ u32 temp;
int ret;
guard(mutex)(&st->lock);
+ if (!st->chip_info->has_fifo) {
+ temp = 0x42;
+ reinit_completion(&st->completion);
+
+ /*
+ * In continuous read mode, when all samples are read, the data
+ * ready signal returns high until the next conversion result is
+ * ready. To exit this mode, the command must be sent when data
+ * ready is low. In order to ensure that condition, wait for the
+ * next interrupt (when the new conversion is finished), allowing
+ * data ready to return low before sending the exit command.
+ */
+ st->buffer_wait_for_irq = true;
+ if (!wait_for_completion_timeout(&st->completion, msecs_to_jiffies(1000)))
+ dev_warn(&st->spi->dev, "Conversion timed out\n");
+ st->buffer_wait_for_irq = false;
+
+ /* Perform a read data command to exit continuous read mode (0x42) */
+ ret = spi_write(st->spi, &temp, 1);
+ if (ret)
+ return ret;
+ }
+
ret = ad4130_set_mode(st, AD4130_MODE_IDLE);
if (ret)
return ret;
- ret = irq_set_irq_type(st->spi->irq, st->irq_trigger);
- if (ret)
- return ret;
+ if (st->chip_info->has_fifo) {
+ ret = irq_set_irq_type(st->spi->irq, st->irq_trigger);
+ if (ret)
+ return ret;
- ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED);
- if (ret)
- return ret;
+ ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED);
+ if (ret)
+ return ret;
- ret = ad4130_set_watermark_interrupt_en(st, false);
- if (ret)
- return ret;
+ ret = ad4130_set_watermark_interrupt_en(st, false);
+ if (ret)
+ return ret;
+ }
/*
* update_scan_mode() is not called in the disable path, disable all
@@ -1410,6 +1645,34 @@ static const struct iio_dev_attr *ad4130_fifo_attributes[] = {
NULL
};
+static const struct iio_trigger_ops ad4130_trigger_ops = {
+ .validate_device = iio_trigger_validate_own_device,
+};
+
+static int ad4130_triggered_buffer_setup(struct iio_dev *indio_dev)
+{
+ struct ad4130_state *st = iio_priv(indio_dev);
+ int ret;
+
+ st->trig = devm_iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d",
+ indio_dev->name, iio_device_id(indio_dev));
+ if (!st->trig)
+ return -ENOMEM;
+
+ st->trig->ops = &ad4130_trigger_ops;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
+ ret = devm_iio_trigger_register(indio_dev->dev.parent, st->trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(st->trig);
+
+ return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad4130_trigger_handler,
+ &ad4130_buffer_ops);
+}
+
static int _ad4130_find_table_index(const unsigned int *tbl, size_t len,
unsigned int val)
{
@@ -1496,6 +1759,17 @@ static int ad4130_parse_fw_setup(struct ad4130_state *st,
return 0;
}
+static unsigned int ad4130_translate_pin(struct ad4130_state *st,
+ unsigned int logical_pin)
+{
+ /* For analog input pins, use the chip-specific pin mapping */
+ if (logical_pin < st->chip_info->max_analog_pins)
+ return st->chip_info->pin_map[logical_pin];
+
+ /* For internal channels, pass through unchanged */
+ return logical_pin;
+}
+
static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin)
{
struct device *dev = &st->spi->dev;
@@ -1504,7 +1778,7 @@ static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin)
return dev_err_probe(dev, -EINVAL,
"Invalid differential channel %u\n", pin);
- if (pin >= AD4130_MAX_ANALOG_PINS)
+ if (pin >= st->chip_info->max_analog_pins)
return 0;
if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL)
@@ -1536,7 +1810,7 @@ static int ad4130_validate_excitation_pin(struct ad4130_state *st, u32 pin)
{
struct device *dev = &st->spi->dev;
- if (pin >= AD4130_MAX_ANALOG_PINS)
+ if (pin >= st->chip_info->max_analog_pins)
return dev_err_probe(dev, -EINVAL,
"Invalid excitation pin %u\n", pin);
@@ -1554,7 +1828,7 @@ static int ad4130_validate_vbias_pin(struct ad4130_state *st, u32 pin)
{
struct device *dev = &st->spi->dev;
- if (pin >= AD4130_MAX_ANALOG_PINS)
+ if (pin >= st->chip_info->max_analog_pins)
return dev_err_probe(dev, -EINVAL, "Invalid vbias pin %u\n",
pin);
@@ -1730,7 +2004,7 @@ static int ad4310_parse_fw(struct iio_dev *indio_dev)
ret = device_property_count_u32(dev, "adi,vbias-pins");
if (ret > 0) {
- if (ret > AD4130_MAX_ANALOG_PINS)
+ if (ret > st->chip_info->max_analog_pins)
return dev_err_probe(dev, -EINVAL,
"Too many vbias pins %u\n", ret);
@@ -1914,9 +2188,14 @@ static int ad4130_setup(struct iio_dev *indio_dev)
* function of P2 takes priority over the GPIO out function.
*/
val = 0;
- for (i = 0; i < AD4130_MAX_GPIOS; i++)
- if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE)
- val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i));
+ for (i = 0; i < st->chip_info->num_gpios; i++) {
+ if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE) {
+ if (st->chip_info->num_gpios == 2)
+ val |= FIELD_PREP(AD4130_4_IO_CONTROL_GPIO_CTRL_MASK, BIT(i));
+ else
+ val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i));
+ }
+ }
val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel);
@@ -1926,21 +2205,23 @@ static int ad4130_setup(struct iio_dev *indio_dev)
val = 0;
for (i = 0; i < st->num_vbias_pins; i++)
- val |= BIT(st->vbias_pins[i]);
+ val |= BIT(ad4130_translate_pin(st, st->vbias_pins[i]));
ret = regmap_write(st->regmap, AD4130_VBIAS_REG, val);
if (ret)
return ret;
- ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
- AD4130_FIFO_CONTROL_HEADER_MASK);
- if (ret)
- return ret;
+ if (st->chip_info->has_fifo) {
+ ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+ AD4130_FIFO_CONTROL_HEADER_MASK);
+ 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;
+ /* 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++) {
@@ -1948,10 +2229,14 @@ static int ad4130_setup(struct iio_dev *indio_dev)
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);
+ val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK,
+ ad4130_translate_pin(st, chan->channel)) |
+ FIELD_PREP(AD4130_CHANNEL_AINM_MASK,
+ ad4130_translate_pin(st, chan->channel2)) |
+ FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK,
+ ad4130_translate_pin(st, chan_info->iout0)) |
+ FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK,
+ ad4130_translate_pin(st, chan_info->iout1));
ret = regmap_write(st->regmap, AD4130_CHANNEL_X_REG(i), val);
if (ret)
@@ -1994,26 +2279,30 @@ static int ad4130_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
+ st->chip_info = device_get_match_data(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;
+ if (st->chip_info->has_fifo) {
+ /*
+ * 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 = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->info = &ad4130_info;
+ indio_dev->info = st->chip_info->info;
st->regmap = devm_regmap_init(dev, NULL, st, &ad4130_regmap_config);
if (IS_ERR(st->regmap))
@@ -2056,9 +2345,9 @@ static int ad4130_probe(struct spi_device *spi)
ad4130_fill_scale_tbls(st);
st->gc.owner = THIS_MODULE;
- st->gc.label = AD4130_NAME;
+ st->gc.label = st->chip_info->name;
st->gc.base = -1;
- st->gc.ngpio = AD4130_MAX_GPIOS;
+ st->gc.ngpio = st->chip_info->num_gpios;
st->gc.parent = dev;
st->gc.can_sleep = true;
st->gc.init_valid_mask = ad4130_gpio_init_valid_mask;
@@ -2069,9 +2358,12 @@ static int ad4130_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
- &ad4130_buffer_ops,
- ad4130_fifo_attributes);
+ if (st->chip_info->has_fifo)
+ ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
+ &ad4130_buffer_ops,
+ ad4130_fifo_attributes);
+ else
+ ret = ad4130_triggered_buffer_setup(indio_dev);
if (ret)
return ret;
@@ -2081,40 +2373,75 @@ static int ad4130_probe(struct spi_device *spi)
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);
+ if (st->chip_info->has_fifo) {
+ /*
+ * 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,ad4129-4",
+ .data = &ad4129_4_chip_info
+ },
+ {
+ .compatible = "adi,ad4129-8",
+ .data = &ad4129_8_chip_info
+ },
+ {
+ .compatible = "adi,ad4130-4",
+ .data = &ad4130_4_chip_info
+ },
+ {
.compatible = "adi,ad4130",
+ .data = &ad4130_8_chip_info
+ },
+ {
+ .compatible = "adi,ad4131-4",
+ .data = &ad4131_4_chip_info
+ },
+ {
+ .compatible = "adi,ad4131-8",
+ .data = &ad4131_8_chip_info
},
{ }
};
MODULE_DEVICE_TABLE(of, ad4130_of_match);
+static const struct spi_device_id ad4130_id_table[] = {
+ { .name = "ad4129-4", .driver_data = (kernel_ulong_t)&ad4129_4_chip_info },
+ { .name = "ad4129-8", .driver_data = (kernel_ulong_t)&ad4129_8_chip_info },
+ { .name = "ad4130-4", .driver_data = (kernel_ulong_t)&ad4130_4_chip_info },
+ { .name = "ad4130", .driver_data = (kernel_ulong_t)&ad4130_8_chip_info },
+ { .name = "ad4131-4", .driver_data = (kernel_ulong_t)&ad4131_4_chip_info },
+ { .name = "ad4131-8", .driver_data = (kernel_ulong_t)&ad4131_8_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad4130_id_table);
+
static struct spi_driver ad4130_driver = {
.driver = {
.name = AD4130_NAME,
.of_match_table = ad4130_of_match,
},
.probe = ad4130_probe,
+ .id_table = ad4130_id_table,
};
module_spi_driver(ad4130_driver);
diff --git a/drivers/iio/adc/ad4134.c b/drivers/iio/adc/ad4134.c
index e42ee328fcbf..0490218bb0e9 100644
--- a/drivers/iio/adc/ad4134.c
+++ b/drivers/iio/adc/ad4134.c
@@ -17,7 +17,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@@ -473,7 +472,7 @@ static int ad4134_probe(struct spi_device *spi)
}
static const struct spi_device_id ad4134_id[] = {
- { "ad4134" },
+ { .name = "ad4134" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad4134_id);
diff --git a/drivers/iio/adc/ad4170-4.c b/drivers/iio/adc/ad4170-4.c
index 82205bfae531..f7757b3a931c 100644
--- a/drivers/iio/adc/ad4170-4.c
+++ b/drivers/iio/adc/ad4170-4.c
@@ -275,9 +275,9 @@ static const unsigned int ad4170_reg_size[] = {
};
enum ad4170_ref_buf {
- AD4170_REF_BUF_PRE, /* Pre-charge referrence buffer */
- AD4170_REF_BUF_FULL, /* Full referrence buffering */
- AD4170_REF_BUF_BYPASS, /* Bypass referrence buffering */
+ AD4170_REF_BUF_PRE, /* Pre-charge reference buffer */
+ AD4170_REF_BUF_FULL, /* Full reference buffering */
+ AD4170_REF_BUF_BYPASS, /* Bypass reference buffering */
};
/* maps adi,positive/negative-reference-buffer property values to enum */
@@ -1699,34 +1699,29 @@ err_release:
return ret;
}
+static const unsigned long gpio_masks[] = {
+ AD4170_GPIO_MODE_GPIO0_MSK,
+ AD4170_GPIO_MODE_GPIO1_MSK,
+ AD4170_GPIO_MODE_GPIO2_MSK,
+ AD4170_GPIO_MODE_GPIO3_MSK,
+};
+
static int ad4170_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
{
struct iio_dev *indio_dev = gpiochip_get_data(gc);
struct ad4170_state *st = iio_priv(indio_dev);
- unsigned long gpio_mask;
int ret;
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
- switch (offset) {
- case 0:
- gpio_mask = AD4170_GPIO_MODE_GPIO0_MSK;
- break;
- case 1:
- gpio_mask = AD4170_GPIO_MODE_GPIO1_MSK;
- break;
- case 2:
- gpio_mask = AD4170_GPIO_MODE_GPIO2_MSK;
- break;
- case 3:
- gpio_mask = AD4170_GPIO_MODE_GPIO3_MSK;
- break;
- default:
+ if (offset >= ARRAY_SIZE(gpio_masks)) {
ret = -EINVAL;
goto err_release;
}
- ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, gpio_mask,
+
+ ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG,
+ gpio_masks[offset],
AD4170_GPIO_MODE_GPIO_INPUT << (2 * offset));
err_release:
@@ -1740,7 +1735,6 @@ static int ad4170_gpio_direction_output(struct gpio_chip *gc,
{
struct iio_dev *indio_dev = gpiochip_get_data(gc);
struct ad4170_state *st = iio_priv(indio_dev);
- unsigned long gpio_mask;
int ret;
ret = ad4170_gpio_set(gc, offset, value);
@@ -1750,24 +1744,13 @@ static int ad4170_gpio_direction_output(struct gpio_chip *gc,
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
- switch (offset) {
- case 0:
- gpio_mask = AD4170_GPIO_MODE_GPIO0_MSK;
- break;
- case 1:
- gpio_mask = AD4170_GPIO_MODE_GPIO1_MSK;
- break;
- case 2:
- gpio_mask = AD4170_GPIO_MODE_GPIO2_MSK;
- break;
- case 3:
- gpio_mask = AD4170_GPIO_MODE_GPIO3_MSK;
- break;
- default:
+ if (offset >= ARRAY_SIZE(gpio_masks)) {
ret = -EINVAL;
goto err_release;
}
- ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, gpio_mask,
+
+ ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG,
+ gpio_masks[offset],
AD4170_GPIO_MODE_GPIO_OUTPUT << (2 * offset));
err_release:
@@ -2996,9 +2979,9 @@ static int ad4170_probe(struct spi_device *spi)
}
static const struct spi_device_id ad4170_id_table[] = {
- { "ad4170-4", (kernel_ulong_t)&ad4170_chip_info },
- { "ad4190-4", (kernel_ulong_t)&ad4190_chip_info },
- { "ad4195-4", (kernel_ulong_t)&ad4195_chip_info },
+ { .name = "ad4170-4", .driver_data = (kernel_ulong_t)&ad4170_chip_info },
+ { .name = "ad4190-4", .driver_data = (kernel_ulong_t)&ad4190_chip_info },
+ { .name = "ad4195-4", .driver_data = (kernel_ulong_t)&ad4195_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad4170_id_table);
diff --git a/drivers/iio/adc/ad4691.c b/drivers/iio/adc/ad4691.c
new file mode 100644
index 000000000000..f2f7c4c6424a
--- /dev/null
+++ b/drivers/iio/adc/ad4691.c
@@ -0,0 +1,2083 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024-2026 Analog Devices, Inc.
+ * Author: Radu Sabau <radu.sabau@analog.com>
+ */
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/device/devres.h>
+#include <linux/dmaengine.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kstrtox.h>
+#include <linux/limits.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/string.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/offload/consumer.h>
+#include <linux/spi/offload/provider.h>
+#include <linux/types.h>
+#include <linux/units.h>
+#include <linux/unaligned.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/buffer-dma.h>
+#include <linux/iio/buffer-dmaengine.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define AD4691_VREF_uV_MIN 2400000
+#define AD4691_VREF_uV_MAX 5250000
+#define AD4691_VREF_2P5_uV_MAX 2750000
+#define AD4691_VREF_3P0_uV_MAX 3250000
+#define AD4691_VREF_3P3_uV_MAX 3750000
+#define AD4691_VREF_4P096_uV_MAX 4500000
+
+#define AD4691_CNV_DUTY_CYCLE_NS 380
+#define AD4691_CNV_HIGH_TIME_NS 430
+/*
+ * Conservative default for the manual offload periodic trigger. Low enough
+ * to work safely out of the box across all OSR and channel count combinations.
+ */
+#define AD4691_OFFLOAD_INITIAL_TRIGGER_HZ (100 * HZ_PER_KHZ)
+
+#define AD4691_SPI_CONFIG_A_REG 0x000
+#define AD4691_SW_RESET (BIT(7) | BIT(0))
+
+#define AD4691_STATUS_REG 0x014
+#define AD4691_CLAMP_STATUS1_REG 0x01A
+#define AD4691_CLAMP_STATUS2_REG 0x01B
+#define AD4691_DEVICE_SETUP 0x020
+#define AD4691_MANUAL_MODE BIT(2)
+#define AD4691_LDO_EN BIT(4)
+#define AD4691_REF_CTRL 0x021
+#define AD4691_REF_CTRL_MASK GENMASK(4, 2)
+#define AD4691_REFBUF_EN BIT(0)
+#define AD4691_OSC_FREQ_REG 0x023
+#define AD4691_OSC_FREQ_MASK GENMASK(3, 0)
+#define AD4691_STD_SEQ_CONFIG 0x025
+#define AD4691_SEQ_ALL_CHANNELS_OFF 0x00
+#define AD4691_SPARE_CONTROL 0x02A
+
+#define AD4691_MAX_CHANNELS 16
+
+#define AD4691_NOOP 0x00
+#define AD4691_ADC_CHAN(ch) ((0x10 + (ch)) << 3)
+#define AD4691_EXIT_COMMAND 0x5000
+
+#define AD4691_OSC_EN_REG 0x180
+#define AD4691_STATE_RESET_REG 0x181
+#define AD4691_STATE_RESET_ALL BIT(0)
+#define AD4691_ADC_SETUP 0x182
+#define AD4691_ADC_MODE_MASK GENMASK(1, 0)
+#define AD4691_CNV_BURST_MODE 0x01
+#define AD4691_AUTONOMOUS_MODE 0x02
+/*
+ * ACC_MASK_REG covers both mask bytes via ADDR_DESCENDING SPI: writing a
+ * 16-bit BE value to 0x185 auto-decrements to 0x184 for the second byte.
+ */
+#define AD4691_ACC_MASK_REG 0x185
+#define AD4691_ACC_DEPTH_IN(n) (0x186 + (n))
+#define AD4691_GPIO_MODE1_REG 0x196
+#define AD4691_GPIO_MODE2_REG 0x197
+#define AD4691_GP_MODE_MASK GENMASK(3, 0)
+#define AD4691_GP_MODE_DATA_READY 0x06
+#define AD4691_GPIO_READ 0x1A0
+#define AD4691_ACC_STATUS_FULL1_REG 0x1B0
+#define AD4691_ACC_STATUS_FULL2_REG 0x1B1
+#define AD4691_ACC_STATUS_OVERRUN1_REG 0x1B2
+#define AD4691_ACC_STATUS_OVERRUN2_REG 0x1B3
+#define AD4691_ACC_STATUS_SAT1_REG 0x1B4
+#define AD4691_ACC_STATUS_SAT2_REG 0x1BE
+#define AD4691_ACC_SAT_OVR_REG(n) (0x1C0 + (n))
+#define AD4691_AVG_IN(n) (0x201 + (2 * (n)))
+#define AD4691_AVG_STS_IN(n) (0x222 + (3 * (n)))
+#define AD4691_ACC_IN(n) (0x252 + (3 * (n)))
+#define AD4691_ACC_STS_DATA(n) (0x283 + (4 * (n)))
+
+
+static const char * const ad4691_supplies[] = { "avdd", "vio" };
+
+enum ad4691_ref_ctrl {
+ AD4691_VREF_2P5,
+ AD4691_VREF_3P0,
+ AD4691_VREF_3P3,
+ AD4691_VREF_4P096,
+ AD4691_VREF_5P0
+};
+
+struct ad4691_channel_info {
+ const struct iio_chan_spec *channels __counted_by_ptr(num_channels);
+ const struct iio_chan_spec *manual_channels __counted_by_ptr(num_channels);
+ unsigned int num_channels;
+};
+
+struct ad4691_chip_info {
+ const char *name;
+ unsigned int max_rate;
+ const struct ad4691_channel_info *sw_info;
+ const struct ad4691_channel_info *offload_info;
+};
+
+/* CNV burst mode channel — exposes oversampling ratio. */
+#define AD4691_CHANNEL(ch) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_SAMP_FREQ) \
+ | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) \
+ | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .channel = ch, \
+ .scan_index = ch, \
+ .scan_type = { \
+ .format = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+/*
+ * Manual mode channel — no oversampling ratio attribute. OSR is not
+ * supported in manual mode; ACC_DEPTH_IN is not configured during manual
+ * buffer enable.
+ */
+#define AD4691_MANUAL_CHANNEL(ch) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .channel = ch, \
+ .scan_index = ch, \
+ .scan_type = { \
+ .format = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+/*
+ * Offload path (bits_per_word=16): the SPI Engine assembles received
+ * bits into native 16-bit words before DMA, so samples are in
+ * CPU-native byte order (IIO_CPU). storagebits=16 matches the 16-bit
+ * DMA word size.
+ *
+ * CNV burst offload configures ACC_DEPTH_IN per channel, so the
+ * oversampling_ratio attribute is exposed. Manual offload does not;
+ * use AD4691_OFFLOAD_MANUAL_CHANNEL for that path.
+ */
+#define AD4691_OFFLOAD_CHANNEL(ch) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_SAMP_FREQ) \
+ | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) \
+ | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .channel = ch, \
+ .scan_index = ch, \
+ .scan_type = { \
+ .format = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ }, \
+ }
+
+/* Manual offload — same IIO_CPU layout but no oversampling_ratio attribute. */
+#define AD4691_OFFLOAD_MANUAL_CHANNEL(ch) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .channel = ch, \
+ .scan_index = ch, \
+ .scan_type = { \
+ .format = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ }, \
+ }
+
+static const struct iio_chan_spec ad4691_channels[] = {
+ AD4691_CHANNEL(0),
+ AD4691_CHANNEL(1),
+ AD4691_CHANNEL(2),
+ AD4691_CHANNEL(3),
+ AD4691_CHANNEL(4),
+ AD4691_CHANNEL(5),
+ AD4691_CHANNEL(6),
+ AD4691_CHANNEL(7),
+ AD4691_CHANNEL(8),
+ AD4691_CHANNEL(9),
+ AD4691_CHANNEL(10),
+ AD4691_CHANNEL(11),
+ AD4691_CHANNEL(12),
+ AD4691_CHANNEL(13),
+ AD4691_CHANNEL(14),
+ AD4691_CHANNEL(15),
+ IIO_CHAN_SOFT_TIMESTAMP(16),
+};
+
+static const struct iio_chan_spec ad4693_channels[] = {
+ AD4691_CHANNEL(0),
+ AD4691_CHANNEL(1),
+ AD4691_CHANNEL(2),
+ AD4691_CHANNEL(3),
+ AD4691_CHANNEL(4),
+ AD4691_CHANNEL(5),
+ AD4691_CHANNEL(6),
+ AD4691_CHANNEL(7),
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+/*
+ * Offload channel arrays: no IIO_CHAN_SOFT_TIMESTAMP because DMA delivers
+ * data directly to userspace without a software timestamp.
+ */
+static const struct iio_chan_spec ad4691_offload_channels[] = {
+ AD4691_OFFLOAD_CHANNEL(0),
+ AD4691_OFFLOAD_CHANNEL(1),
+ AD4691_OFFLOAD_CHANNEL(2),
+ AD4691_OFFLOAD_CHANNEL(3),
+ AD4691_OFFLOAD_CHANNEL(4),
+ AD4691_OFFLOAD_CHANNEL(5),
+ AD4691_OFFLOAD_CHANNEL(6),
+ AD4691_OFFLOAD_CHANNEL(7),
+ AD4691_OFFLOAD_CHANNEL(8),
+ AD4691_OFFLOAD_CHANNEL(9),
+ AD4691_OFFLOAD_CHANNEL(10),
+ AD4691_OFFLOAD_CHANNEL(11),
+ AD4691_OFFLOAD_CHANNEL(12),
+ AD4691_OFFLOAD_CHANNEL(13),
+ AD4691_OFFLOAD_CHANNEL(14),
+ AD4691_OFFLOAD_CHANNEL(15),
+};
+
+static const struct iio_chan_spec ad4693_offload_channels[] = {
+ AD4691_OFFLOAD_CHANNEL(0),
+ AD4691_OFFLOAD_CHANNEL(1),
+ AD4691_OFFLOAD_CHANNEL(2),
+ AD4691_OFFLOAD_CHANNEL(3),
+ AD4691_OFFLOAD_CHANNEL(4),
+ AD4691_OFFLOAD_CHANNEL(5),
+ AD4691_OFFLOAD_CHANNEL(6),
+ AD4691_OFFLOAD_CHANNEL(7),
+};
+
+static const struct iio_chan_spec ad4691_manual_channels[] = {
+ AD4691_MANUAL_CHANNEL(0),
+ AD4691_MANUAL_CHANNEL(1),
+ AD4691_MANUAL_CHANNEL(2),
+ AD4691_MANUAL_CHANNEL(3),
+ AD4691_MANUAL_CHANNEL(4),
+ AD4691_MANUAL_CHANNEL(5),
+ AD4691_MANUAL_CHANNEL(6),
+ AD4691_MANUAL_CHANNEL(7),
+ AD4691_MANUAL_CHANNEL(8),
+ AD4691_MANUAL_CHANNEL(9),
+ AD4691_MANUAL_CHANNEL(10),
+ AD4691_MANUAL_CHANNEL(11),
+ AD4691_MANUAL_CHANNEL(12),
+ AD4691_MANUAL_CHANNEL(13),
+ AD4691_MANUAL_CHANNEL(14),
+ AD4691_MANUAL_CHANNEL(15),
+ IIO_CHAN_SOFT_TIMESTAMP(16),
+};
+
+static const struct iio_chan_spec ad4693_manual_channels[] = {
+ AD4691_MANUAL_CHANNEL(0),
+ AD4691_MANUAL_CHANNEL(1),
+ AD4691_MANUAL_CHANNEL(2),
+ AD4691_MANUAL_CHANNEL(3),
+ AD4691_MANUAL_CHANNEL(4),
+ AD4691_MANUAL_CHANNEL(5),
+ AD4691_MANUAL_CHANNEL(6),
+ AD4691_MANUAL_CHANNEL(7),
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+static const struct iio_chan_spec ad4691_offload_manual_channels[] = {
+ AD4691_OFFLOAD_MANUAL_CHANNEL(0),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(1),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(2),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(3),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(4),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(5),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(6),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(7),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(8),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(9),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(10),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(11),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(12),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(13),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(14),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(15),
+};
+
+static const struct iio_chan_spec ad4693_offload_manual_channels[] = {
+ AD4691_OFFLOAD_MANUAL_CHANNEL(0),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(1),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(2),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(3),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(4),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(5),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(6),
+ AD4691_OFFLOAD_MANUAL_CHANNEL(7),
+};
+
+static const int ad4691_oversampling_ratios[] = { 1, 2, 4, 8, 16, 32 };
+
+static const struct ad4691_channel_info ad4691_sw_info = {
+ .channels = ad4691_channels,
+ .manual_channels = ad4691_manual_channels,
+ .num_channels = ARRAY_SIZE(ad4691_channels),
+};
+
+static const struct ad4691_channel_info ad4693_sw_info = {
+ .channels = ad4693_channels,
+ .manual_channels = ad4693_manual_channels,
+ .num_channels = ARRAY_SIZE(ad4693_channels),
+};
+
+static const struct ad4691_channel_info ad4691_offload_info = {
+ .channels = ad4691_offload_channels,
+ .manual_channels = ad4691_offload_manual_channels,
+ .num_channels = ARRAY_SIZE(ad4691_offload_channels),
+};
+
+static const struct ad4691_channel_info ad4693_offload_info = {
+ .channels = ad4693_offload_channels,
+ .manual_channels = ad4693_offload_manual_channels,
+ .num_channels = ARRAY_SIZE(ad4693_offload_channels),
+};
+
+/*
+ * Internal oscillator frequency table. Index is the OSC_FREQ_REG[3:0] value.
+ * Index 0 (1 MHz) is only valid for AD4692/AD4694; AD4691/AD4693 support
+ * up to 500 kHz and use index 1 as their highest valid rate.
+ */
+static const int ad4691_osc_freqs_Hz[] = {
+ [0x0] = 1000000,
+ [0x1] = 500000,
+ [0x2] = 400000,
+ [0x3] = 250000,
+ [0x4] = 200000,
+ [0x5] = 167000,
+ [0x6] = 133000,
+ [0x7] = 125000,
+ [0x8] = 100000,
+ [0x9] = 50000,
+ [0xA] = 25000,
+ [0xB] = 12500,
+ [0xC] = 10000,
+ [0xD] = 5000,
+ [0xE] = 2500,
+ [0xF] = 1250,
+};
+
+static const char * const ad4691_gp_names[] = { "gp0", "gp1", "gp2", "gp3" };
+
+static const struct ad4691_chip_info ad4691_chip_info = {
+ .name = "ad4691",
+ .max_rate = 500 * HZ_PER_KHZ,
+ .sw_info = &ad4691_sw_info,
+ .offload_info = &ad4691_offload_info,
+};
+
+static const struct ad4691_chip_info ad4692_chip_info = {
+ .name = "ad4692",
+ .max_rate = 1 * HZ_PER_MHZ,
+ .sw_info = &ad4691_sw_info,
+ .offload_info = &ad4691_offload_info,
+};
+
+static const struct ad4691_chip_info ad4693_chip_info = {
+ .name = "ad4693",
+ .max_rate = 500 * HZ_PER_KHZ,
+ .sw_info = &ad4693_sw_info,
+ .offload_info = &ad4693_offload_info,
+};
+
+static const struct ad4691_chip_info ad4694_chip_info = {
+ .name = "ad4694",
+ .max_rate = 1 * HZ_PER_MHZ,
+ .sw_info = &ad4693_sw_info,
+ .offload_info = &ad4693_offload_info,
+};
+
+struct ad4691_state {
+ const struct ad4691_chip_info *info;
+ struct regmap *regmap;
+ struct spi_device *spi;
+
+ struct pwm_device *conv_trigger;
+ int irq;
+ int vref_uV;
+ u32 cnv_period_ns;
+ /*
+ * Snapped oscillator frequency (Hz) shared by all channels. Set when
+ * sampling_frequency or oversampling_ratio is written; written to
+ * OSC_FREQ_REG at buffer enable and single-shot time so both attributes
+ * can be set in any order. Reading in_voltage_sampling_frequency
+ * returns target_osc_freq_Hz / osr — the effective rate given the
+ * shared oversampling ratio.
+ */
+ u32 target_osc_freq_Hz;
+ /* Shared oversampling ratio across all channels; always 1 in manual mode. */
+ unsigned int osr;
+ /*
+ * Precomputed effective-rate lists, one row per entry in
+ * ad4691_oversampling_ratios[]. Populated at probe; read_avail picks
+ * the row for the current shared OSR. The tables are stable after
+ * probe so returning a pointer into them from read_avail is race-free.
+ */
+ int samp_freq_avail[ARRAY_SIZE(ad4691_oversampling_ratios)][ARRAY_SIZE(ad4691_osc_freqs_Hz)];
+ int samp_freq_avail_len[ARRAY_SIZE(ad4691_oversampling_ratios)];
+
+ bool manual_mode;
+ bool irq_enabled;
+ bool refbuf_en;
+ bool ldo_en;
+ /*
+ * Synchronize access to members of the driver state, and ensure
+ * atomicity of consecutive SPI operations.
+ */
+ struct mutex lock;
+ /* NULL when no SPI offload hardware is present. */
+ struct spi_offload *offload;
+ struct spi_offload_trigger *offload_trigger;
+ u64 trigger_hz;
+ /*
+ * Per-buffer-enable lifetime resources:
+ * Manual Mode - a pre-built SPI message that clocks out N+1
+ * transfers in one go.
+ * CNV Burst Mode - a pre-built SPI message that clocks out 2*N
+ * transfers in one go.
+ */
+ struct spi_message scan_msg;
+ /*
+ * max 16 + 1 NOOP (manual) or 2*16 + 1 state-reset (CNV burst).
+ */
+ struct spi_transfer scan_xfers[34];
+ /*
+ * CNV burst: 16 AVG_IN addresses = 16. Manual: 16 channel cmds +
+ * 1 NOOP = 17. Stored as native u16. The non-offload path fills slots
+ * with put_unaligned_be16() (bits_per_word=8, bytes go out in memory
+ * order). The offload path assigns native values directly
+ * (bits_per_word=bpw, SPI reads each slot as a native 16-bit word and
+ * shifts it out MSB-first).
+ */
+ u16 scan_tx[17] __aligned(IIO_DMA_MINALIGN);
+ /*
+ * CNV burst state-reset: 4-byte write [addr_hi, addr_lo,
+ * STATE_RESET_ALL, OSC_EN=1]. CS is asserted throughout, so
+ * ADDR_DESCENDING writes byte[3]=1 to OSC_EN_REG (0x180) as a
+ * deliberate side-write, keeping the oscillator enabled. Shared
+ * with the offload path (mutually exclusive at probe).
+ */
+ u8 scan_tx_reset[4] __aligned(IIO_DMA_MINALIGN);
+ /*
+ * Scan buffer: one BE16 slot per active channel, plus timestamp.
+ * DMA-aligned because scan_xfers point rx_buf directly into vals[].
+ */
+ IIO_DECLARE_DMA_BUFFER_WITH_TS(__be16, vals, 16);
+};
+
+/*
+ * Configure the given GP pin (0-3) as DATA_READY output.
+ * GP0/GP1 → GPIO_MODE1_REG, GP2/GP3 → GPIO_MODE2_REG.
+ * Even pins occupy bits [3:0], odd pins bits [7:4].
+ */
+static int ad4691_gpio_setup(struct ad4691_state *st, unsigned int gp_num)
+{
+ unsigned int bit_off = gp_num % 2;
+ unsigned int reg_off = gp_num / 2;
+ unsigned int shift = 4 * bit_off;
+
+ return regmap_update_bits(st->regmap,
+ AD4691_GPIO_MODE1_REG + reg_off,
+ AD4691_GP_MODE_MASK << shift,
+ AD4691_GP_MODE_DATA_READY << shift);
+}
+
+static const struct spi_offload_config ad4691_offload_config = {
+ .capability_flags = SPI_OFFLOAD_CAP_TRIGGER |
+ SPI_OFFLOAD_CAP_RX_STREAM_DMA,
+};
+
+static bool ad4691_offload_trigger_match(struct spi_offload_trigger *trigger,
+ enum spi_offload_trigger_type type,
+ u64 *args, u32 nargs)
+{
+ return type == SPI_OFFLOAD_TRIGGER_DATA_READY && nargs == 1 && args[0] <= 3;
+}
+
+static int ad4691_offload_trigger_request(struct spi_offload_trigger *trigger,
+ enum spi_offload_trigger_type type,
+ u64 *args, u32 nargs)
+{
+ struct ad4691_state *st = spi_offload_trigger_get_priv(trigger);
+
+ if (nargs != 1 || args[0] > 3)
+ return -EINVAL;
+
+ return ad4691_gpio_setup(st, args[0]);
+}
+
+static int ad4691_offload_trigger_validate(struct spi_offload_trigger *trigger,
+ struct spi_offload_trigger_config *config)
+{
+ if (config->type != SPI_OFFLOAD_TRIGGER_DATA_READY)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct spi_offload_trigger_ops ad4691_offload_trigger_ops = {
+ .match = ad4691_offload_trigger_match,
+ .request = ad4691_offload_trigger_request,
+ .validate = ad4691_offload_trigger_validate,
+};
+
+static int ad4691_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct spi_device *spi = context;
+ u8 tx[2], rx[4];
+ int ret;
+
+ /* Set bit 15 to mark the operation as READ. */
+ put_unaligned_be16(0x8000 | reg, tx);
+
+ switch (reg) {
+ case 0 ... AD4691_OSC_FREQ_REG:
+ case AD4691_SPARE_CONTROL ... AD4691_ACC_MASK_REG - 1:
+ case AD4691_ACC_MASK_REG + 1 ... AD4691_ACC_SAT_OVR_REG(15):
+ ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 1);
+ if (ret)
+ return ret;
+ *val = rx[0];
+ return 0;
+ case AD4691_ACC_MASK_REG:
+ case AD4691_STD_SEQ_CONFIG:
+ case AD4691_AVG_IN(0) ... AD4691_AVG_IN(15):
+ ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 2);
+ if (ret)
+ return ret;
+ *val = get_unaligned_be16(rx);
+ return 0;
+ case AD4691_AVG_STS_IN(0) ... AD4691_AVG_STS_IN(15):
+ case AD4691_ACC_IN(0) ... AD4691_ACC_IN(15):
+ ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 3);
+ if (ret)
+ return ret;
+ *val = get_unaligned_be24(rx);
+ return 0;
+ case AD4691_ACC_STS_DATA(0) ... AD4691_ACC_STS_DATA(15):
+ ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 4);
+ if (ret)
+ return ret;
+ *val = get_unaligned_be32(rx);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4691_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct spi_device *spi = context;
+ u8 tx[4];
+
+ put_unaligned_be16(reg, tx);
+
+ switch (reg) {
+ case 0 ... AD4691_OSC_FREQ_REG:
+ case AD4691_SPARE_CONTROL ... AD4691_ACC_MASK_REG - 1:
+ case AD4691_ACC_MASK_REG + 1 ... AD4691_GPIO_MODE2_REG:
+ if (val > U8_MAX)
+ return -EINVAL;
+ tx[2] = val;
+ return spi_write_then_read(spi, tx, 3, NULL, 0);
+ case AD4691_ACC_MASK_REG:
+ case AD4691_STD_SEQ_CONFIG:
+ if (val > U16_MAX)
+ return -EINVAL;
+ put_unaligned_be16(val, &tx[2]);
+ return spi_write_then_read(spi, tx, 4, NULL, 0);
+ default:
+ return -EINVAL;
+ }
+}
+
+static bool ad4691_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AD4691_STATUS_REG:
+ case AD4691_CLAMP_STATUS1_REG:
+ case AD4691_CLAMP_STATUS2_REG:
+ case AD4691_GPIO_READ:
+ case AD4691_ACC_STATUS_FULL1_REG ... AD4691_ACC_STATUS_SAT2_REG:
+ case AD4691_ACC_SAT_OVR_REG(0) ... AD4691_ACC_SAT_OVR_REG(15):
+ case AD4691_AVG_IN(0) ... AD4691_AVG_IN(15):
+ case AD4691_AVG_STS_IN(0) ... AD4691_AVG_STS_IN(15):
+ case AD4691_ACC_IN(0) ... AD4691_ACC_IN(15):
+ case AD4691_ACC_STS_DATA(0) ... AD4691_ACC_STS_DATA(15):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool ad4691_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0 ... AD4691_OSC_FREQ_REG:
+ case AD4691_SPARE_CONTROL ... AD4691_ACC_SAT_OVR_REG(15):
+ case AD4691_STD_SEQ_CONFIG:
+ return true;
+ default:
+ break;
+ }
+
+ /*
+ * Multi-byte result registers have non-unit strides; only the base
+ * address of each entry is a valid single-register read.
+ */
+ if (reg >= AD4691_AVG_IN(0) && reg <= AD4691_AVG_IN(15))
+ return (reg - AD4691_AVG_IN(0)) % 2 == 0;
+ if (reg >= AD4691_AVG_STS_IN(0) && reg <= AD4691_AVG_STS_IN(15))
+ return (reg - AD4691_AVG_STS_IN(0)) % 3 == 0;
+ if (reg >= AD4691_ACC_IN(0) && reg <= AD4691_ACC_IN(15))
+ return (reg - AD4691_ACC_IN(0)) % 3 == 0;
+ if (reg >= AD4691_ACC_STS_DATA(0) && reg <= AD4691_ACC_STS_DATA(15))
+ return (reg - AD4691_ACC_STS_DATA(0)) % 4 == 0;
+
+ return false;
+}
+
+static bool ad4691_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0 ... AD4691_OSC_FREQ_REG:
+ case AD4691_STD_SEQ_CONFIG:
+ case AD4691_SPARE_CONTROL ... AD4691_GPIO_MODE2_REG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config ad4691_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 32,
+ .reg_read = ad4691_reg_read,
+ .reg_write = ad4691_reg_write,
+ .volatile_reg = ad4691_volatile_reg,
+ .readable_reg = ad4691_readable_reg,
+ .writeable_reg = ad4691_writeable_reg,
+ .max_register = AD4691_ACC_STS_DATA(15),
+ .cache_type = REGCACHE_MAPLE,
+};
+
+/*
+ * Index 0 in ad4691_osc_freqs_Hz is 1 MHz — valid only for AD4692/AD4694
+ * (max_rate == 1 MHz). AD4691/AD4693 cap at 500 kHz so their valid range
+ * starts at index 1.
+ */
+static unsigned int ad4691_samp_freq_start(const struct ad4691_chip_info *info)
+{
+ return (info->max_rate == 1 * HZ_PER_MHZ) ? 0 : 1;
+}
+
+/*
+ * Find the largest oscillator table entry that is both <= needed_osc and
+ * evenly divisible by osr (guaranteeing an integer effective rate on
+ * read-back). Returns 0 if no such entry exists in the chip's valid range.
+ */
+static unsigned int ad4691_find_osc_freq(struct ad4691_state *st,
+ unsigned int needed_osc,
+ unsigned int osr)
+{
+ unsigned int start = ad4691_samp_freq_start(st->info);
+
+ for (unsigned int i = start; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) {
+ if ((unsigned int)ad4691_osc_freqs_Hz[i] > needed_osc)
+ continue;
+ if (ad4691_osc_freqs_Hz[i] % osr)
+ continue;
+ return ad4691_osc_freqs_Hz[i];
+ }
+ return 0;
+}
+
+/* Write target_osc_freq_Hz to OSC_FREQ_REG. Called at use time. */
+static int ad4691_write_osc_freq(struct ad4691_state *st)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) {
+ if (ad4691_osc_freqs_Hz[i] == st->target_osc_freq_Hz)
+ return regmap_write(st->regmap, AD4691_OSC_FREQ_REG, i);
+ }
+ return -EINVAL;
+}
+
+/* Return the index of osr in ad4691_oversampling_ratios[], defaulting to 0. */
+static unsigned int ad4691_osr_index(unsigned int osr)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(ad4691_oversampling_ratios) - 1; i++) {
+ if ((unsigned int)ad4691_oversampling_ratios[i] == osr)
+ return i;
+ }
+ return ARRAY_SIZE(ad4691_oversampling_ratios) - 1;
+}
+
+/*
+ * Precompute samp_freq_avail[][]: for each OSR value, list the oscillator
+ * table entries that divide evenly by that OSR, expressed as effective rates
+ * (osc_freq / osr). Called once at probe after st->info is set.
+ */
+static void ad4691_precompute_samp_freq_avail(struct ad4691_state *st)
+{
+ unsigned int start = ad4691_samp_freq_start(st->info);
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(ad4691_oversampling_ratios); i++) {
+ unsigned int osr = ad4691_oversampling_ratios[i];
+ int n = 0;
+
+ for (unsigned int j = start; j < ARRAY_SIZE(ad4691_osc_freqs_Hz); j++) {
+ if (ad4691_osc_freqs_Hz[j] % osr)
+ continue;
+ st->samp_freq_avail[i][n++] = ad4691_osc_freqs_Hz[j] / osr;
+ }
+ st->samp_freq_avail_len[i] = n;
+ }
+}
+
+static int ad4691_set_sampling_freq(struct ad4691_state *st, int freq)
+{
+ unsigned int osr, found;
+
+ /*
+ * Read osr under st->lock: osr and target_osc_freq_Hz are modified
+ * together under the lock; reading after acquiring it ensures we see
+ * a consistent snapshot with no concurrent write racing us.
+ */
+ guard(mutex)(&st->lock);
+ osr = st->osr;
+
+ if (freq <= 0 || (unsigned int)freq > st->info->max_rate / osr)
+ return -EINVAL;
+
+ found = ad4691_find_osc_freq(st, (unsigned int)freq * osr, osr);
+ if (!found)
+ return -EINVAL;
+
+ /*
+ * Store the snapped oscillator frequency; OSC_FREQ_REG is written at
+ * buffer enable and single-shot time so that sampling_frequency and
+ * oversampling_ratio can be set in any order.
+ */
+ st->target_osc_freq_Hz = found;
+ return 0;
+}
+
+static int ad4691_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type,
+ int *length, long mask)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ unsigned int osr_idx;
+
+ /*
+ * The precomputed tables are stable after probe; only the
+ * current OSR needs to be read under the lock to pick the
+ * right row atomically.
+ */
+ guard(mutex)(&st->lock);
+ osr_idx = ad4691_osr_index(st->osr);
+ *vals = st->samp_freq_avail[osr_idx];
+ *type = IIO_VAL_INT;
+ *length = st->samp_freq_avail_len[osr_idx];
+ return IIO_AVAIL_LIST;
+ }
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = ad4691_oversampling_ratios;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(ad4691_oversampling_ratios);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4691_single_shot_read(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+ unsigned int reg_val, period_us;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ /* Use AUTONOMOUS mode for single-shot reads. */
+ ret = regmap_write(st->regmap, AD4691_STATE_RESET_REG, AD4691_STATE_RESET_ALL);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4691_STD_SEQ_CONFIG,
+ BIT(chan->channel));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4691_ACC_MASK_REG,
+ ~BIT(chan->channel) & GENMASK(15, 0));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(0), st->osr);
+ if (ret)
+ return ret;
+
+ ret = ad4691_write_osc_freq(st);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4691_OSC_EN_REG, 1);
+ if (ret)
+ return ret;
+
+ /*
+ * Wait osr + 1 oscillator periods: osr for accumulation, +1 for the
+ * pipeline margin (one extra period ensures the final result is ready).
+ */
+ period_us = DIV_ROUND_UP((st->osr + 1) * USEC_PER_SEC,
+ st->target_osc_freq_Hz);
+ fsleep(period_us);
+
+ ret = regmap_write(st->regmap, AD4691_OSC_EN_REG, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(st->regmap, AD4691_AVG_IN(chan->channel), &reg_val);
+ if (ret)
+ return ret;
+
+ *val = reg_val;
+
+ ret = regmap_write(st->regmap, AD4691_STATE_RESET_REG, AD4691_STATE_RESET_ALL);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+}
+
+static int ad4691_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long info)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW: {
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
+
+ return ad4691_single_shot_read(indio_dev, chan, val);
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ /*
+ * Read target_osc_freq_Hz and osr under st->lock to get a
+ * consistent snapshot: write_raw for SAMP_FREQ or OSR modifies
+ * both fields under the lock, so a concurrent read without the
+ * lock could observe a new oscillator frequency with the old OSR.
+ */
+ guard(mutex)(&st->lock);
+ *val = st->target_osc_freq_Hz / st->osr;
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: {
+ guard(mutex)(&st->lock);
+ *val = st->osr;
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ *val = st->vref_uV / (MICRO / MILLI);
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4691_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ad4691_set_sampling_freq(st, val);
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: {
+ unsigned int old_effective, found, osr_idx;
+
+ osr_idx = ad4691_osr_index(val);
+ if (ad4691_oversampling_ratios[osr_idx] != val)
+ return -EINVAL;
+
+ /*
+ * Hold st->lock while computing the new oscillator frequency
+ * and updating both target_osc_freq_Hz and osr atomically:
+ * read_raw for SAMP_FREQ reads both fields under the lock and
+ * must see a consistent pair (new osc ↔ new osr).
+ *
+ * Snap target_osc_freq_Hz to the largest table entry that is
+ * both <= old_effective * new_osr and evenly divisible by
+ * new_osr, preserving an integer read-back of
+ * in_voltage_sampling_frequency after the OSR change.
+ */
+ guard(mutex)(&st->lock);
+ old_effective = st->target_osc_freq_Hz / st->osr;
+ found = ad4691_find_osc_freq(st, old_effective * (unsigned int)val, val);
+ if (!found)
+ return -EINVAL;
+ st->target_osc_freq_Hz = found;
+ st->osr = val;
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4691_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+
+ guard(mutex)(&st->lock);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static int ad4691_set_pwm_freq(struct ad4691_state *st, unsigned int freq)
+{
+ if (!freq)
+ return -EINVAL;
+
+ st->cnv_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, freq);
+ return 0;
+}
+
+static int ad4691_sampling_enable(struct ad4691_state *st, bool enable)
+{
+ struct pwm_state conv_state = {
+ .period = st->cnv_period_ns,
+ .duty_cycle = AD4691_CNV_DUTY_CYCLE_NS,
+ .polarity = PWM_POLARITY_NORMAL,
+ .enabled = enable,
+ };
+
+ return pwm_apply_might_sleep(st->conv_trigger, &conv_state);
+}
+
+/*
+ * ad4691_enter_conversion_mode - Switch the chip to its buffer conversion mode.
+ *
+ * Configures the ADC hardware registers for the mode selected at probe
+ * (CNV_BURST or MANUAL). Called from buffer preenable before starting
+ * sampling. The chip is in AUTONOMOUS mode during idle (for read_raw).
+ */
+static int ad4691_enter_conversion_mode(struct ad4691_state *st)
+{
+ int ret;
+
+ if (st->manual_mode)
+ return regmap_update_bits(st->regmap, AD4691_DEVICE_SETUP,
+ AD4691_MANUAL_MODE, AD4691_MANUAL_MODE);
+
+ ret = ad4691_write_osc_freq(st);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AD4691_ADC_SETUP,
+ AD4691_ADC_MODE_MASK, AD4691_CNV_BURST_MODE);
+ if (ret)
+ return ret;
+
+ return regmap_write(st->regmap, AD4691_STATE_RESET_REG,
+ AD4691_STATE_RESET_ALL);
+}
+
+static int ad4691_transfer(struct ad4691_state *st, u16 cmd)
+{
+ u8 buf[2];
+
+ put_unaligned_be16(cmd, buf);
+
+ return spi_write_then_read(st->spi, buf, sizeof(buf), NULL, 0);
+}
+
+/*
+ * ad4691_exit_conversion_mode - Return the chip to AUTONOMOUS mode.
+ *
+ * Called from buffer postdisable to restore the chip to the
+ * idle state used by read_raw. Clears the sequencer and resets state.
+ */
+static int ad4691_exit_conversion_mode(struct ad4691_state *st)
+{
+ if (st->manual_mode)
+ return ad4691_transfer(st, AD4691_EXIT_COMMAND);
+
+ return regmap_update_bits(st->regmap, AD4691_ADC_SETUP,
+ AD4691_ADC_MODE_MASK, AD4691_AUTONOMOUS_MODE);
+}
+
+static int ad4691_manual_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+ unsigned int k, i;
+ int ret;
+
+ memset(st->scan_xfers, 0, sizeof(st->scan_xfers));
+ memset(st->scan_tx, 0, sizeof(st->scan_tx));
+
+ spi_message_init(&st->scan_msg);
+
+ k = 0;
+ iio_for_each_active_channel(indio_dev, i) {
+ /*
+ * Channel-select command occupies the first (high) byte of the
+ * 16-bit DIN frame; the second byte is a don't-care zero pad.
+ * put_unaligned_be16() writes [cmd, 0x00] in memory so the
+ * SPI controller sends the command byte first on the wire.
+ */
+ put_unaligned_be16((u16)(AD4691_ADC_CHAN(i) << 8), &st->scan_tx[k]);
+ st->scan_xfers[k].tx_buf = &st->scan_tx[k];
+ /*
+ * The pipeline means xfer[0] receives the residual from the
+ * previous sequence, not a valid sample. Discard it (rx_buf=NULL)
+ * to avoid aliasing vals[0] across two concurrent DMA mappings.
+ * xfer[1] (or the NOOP when only one channel is active) writes
+ * the real ch[0] result to vals[0]. Subsequent transfers write
+ * into vals[k-1] so each result lands at the next dense slot.
+ */
+ st->scan_xfers[k].rx_buf = (k == 0) ? NULL : &st->vals[k - 1];
+ st->scan_xfers[k].len = sizeof(*st->scan_tx);
+ st->scan_xfers[k].cs_change = 1;
+ st->scan_xfers[k].cs_change_delay.value = AD4691_CNV_HIGH_TIME_NS;
+ st->scan_xfers[k].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
+ spi_message_add_tail(&st->scan_xfers[k], &st->scan_msg);
+ k++;
+ }
+
+ /* Final NOOP transfer retrieves the last channel's result. */
+ st->scan_xfers[k].tx_buf = &st->scan_tx[k]; /* scan_tx[k] == 0 == NOOP */
+ st->scan_xfers[k].rx_buf = &st->vals[k - 1];
+ st->scan_xfers[k].len = sizeof(*st->scan_tx);
+ spi_message_add_tail(&st->scan_xfers[k], &st->scan_msg);
+
+ ret = spi_optimize_message(st->spi, &st->scan_msg);
+ if (ret)
+ return ret;
+
+ ret = ad4691_enter_conversion_mode(st);
+ if (ret) {
+ spi_unoptimize_message(&st->scan_msg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad4691_manual_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = ad4691_exit_conversion_mode(st);
+ spi_unoptimize_message(&st->scan_msg);
+ return ret;
+}
+
+static const struct iio_buffer_setup_ops ad4691_manual_buffer_setup_ops = {
+ .preenable = ad4691_manual_buffer_preenable,
+ .postdisable = ad4691_manual_buffer_postdisable,
+};
+
+static int ad4691_cnv_burst_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+ unsigned int acc_mask, std_seq_config;
+ unsigned int k, i;
+ int ret;
+
+ memset(st->scan_xfers, 0, sizeof(st->scan_xfers));
+ memset(st->scan_tx, 0, sizeof(st->scan_tx));
+
+ spi_message_init(&st->scan_msg);
+
+ /*
+ * Each AVG_IN read needs two transfers: a 2-byte address write phase
+ * followed by a 2-byte data read phase. CS toggles between channels
+ * (cs_change=1 on the read phase of all but the last channel).
+ */
+ k = 0;
+ iio_for_each_active_channel(indio_dev, i) {
+ put_unaligned_be16(0x8000 | AD4691_AVG_IN(i), &st->scan_tx[k]);
+ st->scan_xfers[2 * k].tx_buf = &st->scan_tx[k];
+ st->scan_xfers[2 * k].len = sizeof(*st->scan_tx);
+ spi_message_add_tail(&st->scan_xfers[2 * k], &st->scan_msg);
+ st->scan_xfers[2 * k + 1].rx_buf = &st->vals[k];
+ st->scan_xfers[2 * k + 1].len = sizeof(*st->scan_tx);
+ st->scan_xfers[2 * k + 1].cs_change = 1;
+ spi_message_add_tail(&st->scan_xfers[2 * k + 1], &st->scan_msg);
+ k++;
+ }
+
+ /*
+ * Append a 4-byte state-reset transfer [addr_hi, addr_lo,
+ * STATE_RESET_ALL, OSC_EN=1]. CS is asserted throughout, so
+ * ADDR_DESCENDING writes byte[3]=1 to OSC_EN_REG (0x180) as a
+ * deliberate side-write, keeping the oscillator enabled.
+ * STATE_RESET_ALL starts the next burst; the hardware does not
+ * accumulate new conversions until after a STATE_RESET pulse, so
+ * no in-progress data is lost. No cs_change here — CS must
+ * deassert normally at end of message to frame the next command.
+ */
+ put_unaligned_be16(AD4691_STATE_RESET_REG, st->scan_tx_reset);
+ st->scan_tx_reset[2] = AD4691_STATE_RESET_ALL;
+ st->scan_tx_reset[3] = 1;
+ st->scan_xfers[2 * k].tx_buf = st->scan_tx_reset;
+ st->scan_xfers[2 * k].len = sizeof(st->scan_tx_reset);
+ spi_message_add_tail(&st->scan_xfers[2 * k], &st->scan_msg);
+
+ ret = spi_optimize_message(st->spi, &st->scan_msg);
+ if (ret)
+ return ret;
+
+ std_seq_config = bitmap_read(indio_dev->active_scan_mask, 0,
+ iio_get_masklength(indio_dev)) & GENMASK(15, 0);
+ ret = regmap_write(st->regmap, AD4691_STD_SEQ_CONFIG, std_seq_config);
+ if (ret)
+ goto err_unoptimize;
+
+ acc_mask = ~std_seq_config & GENMASK(15, 0);
+ ret = regmap_write(st->regmap, AD4691_ACC_MASK_REG, acc_mask);
+ if (ret)
+ goto err_unoptimize;
+
+ ret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(0), st->osr);
+ if (ret)
+ goto err_unoptimize;
+
+ ret = ad4691_enter_conversion_mode(st);
+ if (ret)
+ goto err_unoptimize;
+
+ return 0;
+
+err_unoptimize:
+ spi_unoptimize_message(&st->scan_msg);
+ return ret;
+}
+
+static int ad4691_cnv_burst_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+ int ret;
+
+ /*
+ * Start the PWM and unmask the IRQ here in postenable, not in
+ * preenable. The IIO core attaches the trigger poll function between
+ * preenable and postenable; enabling sampling or unmasking the IRQ
+ * before that point risks a DATA_READY assertion landing before the
+ * poll function is registered. iio_trigger_poll() would drop the
+ * event, disable_irq_nosync() would fire, and enable_irq() would
+ * never be called, leaving the IRQ permanently masked.
+ */
+ ret = ad4691_sampling_enable(st, true);
+ if (ret)
+ return ret;
+
+ enable_irq(st->irq);
+ st->irq_enabled = true;
+ return 0;
+}
+
+static int ad4691_cnv_burst_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+
+ if (st->irq_enabled) {
+ disable_irq(st->irq);
+ st->irq_enabled = false;
+ }
+ return ad4691_sampling_enable(st, false);
+}
+
+static int ad4691_cnv_burst_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = ad4691_exit_conversion_mode(st);
+ spi_unoptimize_message(&st->scan_msg);
+ return ret;
+}
+
+static const struct iio_buffer_setup_ops ad4691_cnv_burst_buffer_setup_ops = {
+ .preenable = ad4691_cnv_burst_buffer_preenable,
+ .postenable = ad4691_cnv_burst_buffer_postenable,
+ .predisable = ad4691_cnv_burst_buffer_predisable,
+ .postdisable = ad4691_cnv_burst_buffer_postdisable,
+};
+
+static int ad4691_manual_offload_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+ struct device *dev = regmap_get_device(st->regmap);
+ struct spi_device *spi = to_spi_device(dev);
+ struct spi_offload_trigger_config config = {
+ .type = SPI_OFFLOAD_TRIGGER_PERIODIC,
+ };
+ unsigned int bpw = indio_dev->channels[0].scan_type.realbits;
+ unsigned int bit, k;
+ int ret;
+
+ ret = ad4691_enter_conversion_mode(st);
+ if (ret)
+ return ret;
+
+ memset(st->scan_xfers, 0, sizeof(st->scan_xfers));
+ memset(st->scan_tx, 0, sizeof(st->scan_tx));
+
+ /*
+ * N+1 transfers for N channels. Each CS-low period triggers
+ * a conversion AND returns the previous result (pipelined).
+ * TX: [AD4691_ADC_CHAN(n), 0x00]
+ * RX: [data_hi, data_lo] (storagebits=16, shift=0)
+ * Transfer 0 RX is garbage; transfers 1..N carry real data.
+ * scan_tx is reused for TX commands (mutually exclusive with the
+ * non-offload triggered-buffer path).
+ *
+ * bits_per_word=bpw: the SPI controller reads tx_buf as a native
+ * 16-bit word and shifts it out MSB-first. Store the exact 16-bit
+ * value we want on the wire as a plain native u16 — no endianness
+ * macro — so the wire bytes are correct on both LE and BE hosts.
+ * The channel-select command is a single byte; shift it to the MSB
+ * position so SPI sends it first, with a zero pad in the LSB.
+ */
+ k = 0;
+ iio_for_each_active_channel(indio_dev, bit) {
+ st->scan_tx[k] = AD4691_ADC_CHAN(bit) << 8;
+ st->scan_xfers[k].tx_buf = &st->scan_tx[k];
+ st->scan_xfers[k].len = sizeof(*st->scan_tx);
+ st->scan_xfers[k].bits_per_word = bpw;
+ st->scan_xfers[k].cs_change = 1;
+ st->scan_xfers[k].cs_change_delay.value = AD4691_CNV_HIGH_TIME_NS;
+ st->scan_xfers[k].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
+ /* First transfer RX is garbage — skip it. */
+ if (k > 0)
+ st->scan_xfers[k].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
+ k++;
+ }
+
+ /* Final NOOP transfer retrieves the last channel's result. */
+ st->scan_xfers[k].tx_buf = &st->scan_tx[k]; /* scan_tx[k] == 0 == NOOP */
+ st->scan_xfers[k].len = sizeof(*st->scan_tx);
+ st->scan_xfers[k].bits_per_word = bpw;
+ st->scan_xfers[k].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
+ k++;
+
+ spi_message_init_with_transfers(&st->scan_msg, st->scan_xfers, k);
+ st->scan_msg.offload = st->offload;
+
+ ret = spi_optimize_message(spi, &st->scan_msg);
+ if (ret)
+ goto err_exit_conversion;
+
+ config.periodic.frequency_hz = st->trigger_hz;
+ ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, &config);
+ if (ret)
+ goto err_unoptimize;
+
+ return 0;
+
+err_unoptimize:
+ spi_unoptimize_message(&st->scan_msg);
+err_exit_conversion:
+ ad4691_exit_conversion_mode(st);
+ return ret;
+}
+
+static int ad4691_manual_offload_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+
+ spi_offload_trigger_disable(st->offload, st->offload_trigger);
+ spi_unoptimize_message(&st->scan_msg);
+
+ return ad4691_exit_conversion_mode(st);
+}
+
+static const struct iio_buffer_setup_ops ad4691_manual_offload_buffer_setup_ops = {
+ .postenable = ad4691_manual_offload_buffer_postenable,
+ .predisable = ad4691_manual_offload_buffer_predisable,
+};
+
+static int ad4691_cnv_burst_offload_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+ struct device *dev = regmap_get_device(st->regmap);
+ struct spi_device *spi = to_spi_device(dev);
+ struct spi_offload_trigger_config config = {
+ .type = SPI_OFFLOAD_TRIGGER_DATA_READY,
+ };
+ unsigned int bpw = indio_dev->channels[0].scan_type.realbits;
+ unsigned int acc_mask, std_seq_config;
+ unsigned int bit, k;
+ int ret;
+
+ std_seq_config = bitmap_read(indio_dev->active_scan_mask, 0,
+ iio_get_masklength(indio_dev)) & GENMASK(15, 0);
+ ret = regmap_write(st->regmap, AD4691_STD_SEQ_CONFIG, std_seq_config);
+ if (ret)
+ return ret;
+
+ acc_mask = ~std_seq_config & GENMASK(15, 0);
+ ret = regmap_write(st->regmap, AD4691_ACC_MASK_REG, acc_mask);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(0), st->osr);
+ if (ret)
+ return ret;
+
+ ret = ad4691_enter_conversion_mode(st);
+ if (ret)
+ return ret;
+
+ memset(st->scan_xfers, 0, sizeof(st->scan_xfers));
+ memset(st->scan_tx, 0, sizeof(st->scan_tx));
+
+ /*
+ * Each AVG_IN register read uses two transfers:
+ * TX: [reg_hi | 0x80, reg_lo] (address phase, CS stays asserted)
+ * RX: [data_hi, data_lo] (bpw-wide data phase, storagebits=16)
+ * Both TX and RX use bits_per_word=bpw: the SPI controller reads tx_buf
+ * as a native 16-bit word and shifts it out MSB-first. Store the exact
+ * 16-bit wire value as a plain native u16 — no endianness macro — so the
+ * wire bytes are correct on both LE and BE hosts. The read-address
+ * (0x8000 | reg) is already the 16-bit value we want on the wire.
+ * scan_tx is reused for TX addresses (mutually exclusive with the
+ * non-offload triggered-buffer path).
+ */
+ k = 0;
+ iio_for_each_active_channel(indio_dev, bit) {
+ st->scan_tx[k] = 0x8000 | AD4691_AVG_IN(bit);
+
+ /* TX: address phase, CS stays asserted into data phase */
+ st->scan_xfers[2 * k].tx_buf = &st->scan_tx[k];
+ st->scan_xfers[2 * k].len = sizeof(*st->scan_tx);
+ st->scan_xfers[2 * k].bits_per_word = bpw;
+
+ /* RX: data phase, CS toggles after to delimit the next register op */
+ st->scan_xfers[2 * k + 1].len = sizeof(*st->scan_tx);
+ st->scan_xfers[2 * k + 1].bits_per_word = bpw;
+ st->scan_xfers[2 * k + 1].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
+ st->scan_xfers[2 * k + 1].cs_change = 1;
+ k++;
+ }
+
+ /*
+ * State reset: single 4-byte write [addr_hi, addr_lo, STATE_RESET_ALL,
+ * OSC_EN=1]. ADDR_DESCENDING writes byte[3]=1 to OSC_EN_REG (0x180) as
+ * a deliberate side-write, keeping the oscillator enabled.
+ * scan_tx_reset is shared with the non-offload path (len=4 here vs
+ * len=3 there) since the two paths are mutually exclusive at probe.
+ */
+ put_unaligned_be16(AD4691_STATE_RESET_REG, st->scan_tx_reset);
+ st->scan_tx_reset[2] = AD4691_STATE_RESET_ALL;
+ st->scan_tx_reset[3] = 1;
+ st->scan_xfers[2 * k].tx_buf = st->scan_tx_reset;
+ st->scan_xfers[2 * k].len = sizeof(st->scan_tx_reset);
+ /*
+ * 4-byte u8 buffer assembled with put_unaligned_be16(); leave
+ * bits_per_word at the default (8) so bytes go out in memory order.
+ */
+
+ spi_message_init_with_transfers(&st->scan_msg, st->scan_xfers, 2 * k + 1);
+ st->scan_msg.offload = st->offload;
+
+ ret = spi_optimize_message(spi, &st->scan_msg);
+ if (ret)
+ goto err_exit_conversion;
+
+ ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, &config);
+ if (ret)
+ goto err_unoptimize;
+
+ ret = ad4691_sampling_enable(st, true);
+ if (ret)
+ goto err_disable_trigger;
+
+ return 0;
+
+err_disable_trigger:
+ spi_offload_trigger_disable(st->offload, st->offload_trigger);
+err_unoptimize:
+ spi_unoptimize_message(&st->scan_msg);
+err_exit_conversion:
+ ad4691_exit_conversion_mode(st);
+ return ret;
+}
+
+static int ad4691_cnv_burst_offload_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+
+ ad4691_sampling_enable(st, false);
+ spi_offload_trigger_disable(st->offload, st->offload_trigger);
+ spi_unoptimize_message(&st->scan_msg);
+
+ return ad4691_exit_conversion_mode(st);
+}
+
+static const struct iio_buffer_setup_ops ad4691_cnv_burst_offload_buffer_setup_ops = {
+ .postenable = ad4691_cnv_burst_offload_buffer_postenable,
+ .predisable = ad4691_cnv_burst_offload_buffer_predisable,
+};
+
+static ssize_t sampling_frequency_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ad4691_state *st = iio_priv(indio_dev);
+
+ if (st->manual_mode && st->offload)
+ return sysfs_emit(buf, "%llu\n", READ_ONCE(st->trigger_hz));
+
+ return sysfs_emit(buf, "%lu\n", NSEC_PER_SEC / st->cnv_period_ns);
+}
+
+static ssize_t sampling_frequency_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 ad4691_state *st = iio_priv(indio_dev);
+ unsigned int freq;
+ int ret;
+
+ ret = kstrtouint(buf, 10, &freq);
+ if (ret)
+ return ret;
+
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
+
+ if (st->manual_mode && st->offload) {
+ struct spi_offload_trigger_config config = {
+ .type = SPI_OFFLOAD_TRIGGER_PERIODIC,
+ .periodic = { .frequency_hz = freq },
+ };
+
+ ret = spi_offload_trigger_validate(st->offload_trigger, &config);
+ if (ret)
+ return ret;
+
+ WRITE_ONCE(st->trigger_hz, config.periodic.frequency_hz);
+ return len;
+ }
+
+ ret = ad4691_set_pwm_freq(st, freq);
+ if (ret)
+ return ret;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR_RW(sampling_frequency, 0);
+
+static const struct iio_dev_attr *ad4691_buffer_attrs[] = {
+ &iio_dev_attr_sampling_frequency,
+ NULL
+};
+
+static irqreturn_t ad4691_irq(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct ad4691_state *st = iio_priv(indio_dev);
+
+ /*
+ * Disable the IRQ before calling iio_trigger_poll(). The IRQ is
+ * re-enabled via the trigger .reenable callback, which the IIO core
+ * calls inside iio_trigger_notify_done() once use_count reaches zero.
+ * Re-enabling here (before notify_done) would race: a DATA_READY
+ * between enable_irq() and notify_done() calls iio_trigger_poll()
+ * while use_count > 0, dropping the event and permanently masking
+ * the IRQ.
+ */
+ disable_irq_nosync(st->irq);
+ iio_trigger_poll(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static void ad4691_trigger_reenable(struct iio_trigger *trig)
+{
+ struct ad4691_state *st = iio_trigger_get_drvdata(trig);
+
+ enable_irq(st->irq);
+}
+
+static const struct iio_trigger_ops ad4691_trigger_ops = {
+ .reenable = ad4691_trigger_reenable,
+ .validate_device = iio_trigger_validate_own_device,
+};
+
+static void ad4691_read_scan(struct iio_dev *indio_dev, s64 ts)
+{
+ struct ad4691_state *st = iio_priv(indio_dev);
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = spi_sync(st->spi, &st->scan_msg);
+ if (ret) {
+ dev_err_ratelimited(regmap_get_device(st->regmap),
+ "SPI scan failed: %d\n", ret);
+ return;
+ }
+
+ /*
+ * rx_buf pointers in scan_xfers point directly into scan.vals, so no
+ * copy is needed. The scan_msg already includes a STATE_RESET at the
+ * end (appended in preenable), so no explicit reset is needed here.
+ */
+ iio_push_to_buffers_with_ts(indio_dev, st->vals, sizeof(st->vals), ts);
+}
+
+static irqreturn_t ad4691_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+
+ ad4691_read_scan(indio_dev, pf->timestamp);
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+/*
+ * CNV burst mode: only allow our own trigger (driven by DATA_READY IRQ).
+ * Manual mode: external triggers (e.g. iio-trig-hrtimer) must be allowed
+ * because manual mode has no DATA_READY IRQ to fire the internal trigger.
+ * iio_trigger_ops.validate_device = iio_trigger_validate_own_device is
+ * correct in both modes — it prevents other devices from hijacking our
+ * internal trigger; the distinction here is only for iio_info.validate_trigger.
+ */
+static const struct iio_info ad4691_cnv_burst_info = {
+ .read_raw = ad4691_read_raw,
+ .write_raw = ad4691_write_raw,
+ .read_avail = ad4691_read_avail,
+ .debugfs_reg_access = ad4691_reg_access,
+ .validate_trigger = iio_validate_own_trigger,
+};
+
+static const struct iio_info ad4691_manual_info = {
+ .read_raw = ad4691_read_raw,
+ .write_raw = ad4691_write_raw,
+ .read_avail = ad4691_read_avail,
+ .debugfs_reg_access = ad4691_reg_access,
+};
+
+static int ad4691_pwm_setup(struct ad4691_state *st)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+
+ st->conv_trigger = devm_pwm_get(dev, "cnv");
+ if (IS_ERR(st->conv_trigger))
+ return dev_err_probe(dev, PTR_ERR(st->conv_trigger),
+ "Failed to get CNV PWM\n");
+
+ return ad4691_set_pwm_freq(st, st->info->max_rate);
+}
+
+static int ad4691_regulator_setup(struct ad4691_state *st)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+ int ret;
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4691_supplies),
+ ad4691_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get and enable supplies\n");
+
+ /*
+ * vdd-supply and ldo-in-supply are mutually exclusive:
+ * vdd-supply present → external 1.8V VDD; disable internal LDO.
+ * vdd-supply absent → enable internal LDO fed from ldo-in-supply.
+ * Having both simultaneously is strongly inadvisable per the datasheet.
+ */
+ if (device_property_present(dev, "vdd-supply")) {
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get and enable VDD\n");
+ } else if (device_property_present(dev, "ldo-in-supply")) {
+ ret = devm_regulator_get_enable(dev, "ldo-in");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get and enable LDO-IN\n");
+ st->ldo_en = true;
+ } else {
+ return dev_err_probe(dev, -EINVAL,
+ "missing one of vdd-supply, ldo-in-supply\n");
+ }
+
+ if (device_property_present(dev, "ref-supply")) {
+ st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "ref");
+ if (st->vref_uV < 0)
+ return dev_err_probe(dev, st->vref_uV,
+ "Failed to get REF supply voltage\n");
+ } else if (device_property_present(dev, "refin-supply")) {
+ st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "refin");
+ if (st->vref_uV < 0)
+ return dev_err_probe(dev, st->vref_uV,
+ "Failed to get REFIN supply voltage\n");
+ st->refbuf_en = true;
+ } else {
+ return dev_err_probe(dev, -EINVAL,
+ "missing one of ref-supply, refin-supply\n");
+ }
+
+ if (st->vref_uV < AD4691_VREF_uV_MIN || st->vref_uV > AD4691_VREF_uV_MAX)
+ return dev_err_probe(dev, -EINVAL,
+ "vref(%d) must be in the range [%u...%u]\n",
+ st->vref_uV, AD4691_VREF_uV_MIN,
+ AD4691_VREF_uV_MAX);
+
+ return 0;
+}
+
+static int ad4691_reset(struct ad4691_state *st)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+ struct reset_control *rst;
+ int ret;
+
+ rst = devm_reset_control_get_optional_exclusive(dev, NULL);
+ if (IS_ERR(rst))
+ return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset\n");
+
+ if (rst) {
+ /*
+ * Assert the reset line to guarantee a clean reset pulse on
+ * every probe, including driver reloads where the line may
+ * already be deasserted (reset_control_put() does not
+ * re-assert on release). tRESETL (minimum pulse width) = 10 ns
+ * (Table 5); kernel function-call overhead alone exceeds this,
+ * so no explicit delay is needed between assert and deassert.
+ */
+ reset_control_assert(rst);
+ ret = reset_control_deassert(rst);
+ if (ret)
+ return ret;
+ } else {
+ /* No hardware reset available, fall back to software reset. */
+ ret = regmap_write(st->regmap, AD4691_SPI_CONFIG_A_REG,
+ AD4691_SW_RESET);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Wait 300 µs (Table 5) for the device to complete its internal reset
+ * sequence before accepting SPI commands.
+ */
+ fsleep(300);
+ return 0;
+}
+
+static int ad4691_config(struct ad4691_state *st)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+ enum ad4691_ref_ctrl ref_val;
+ unsigned int val;
+ int ret;
+
+ /*
+ * Determine buffer conversion mode from DT: if a PWM is provided it
+ * drives the CNV pin (CNV_BURST_MODE); otherwise CNV is tied to CS
+ * and each SPI transfer triggers a conversion (MANUAL_MODE).
+ * Both modes idle in AUTONOMOUS mode so that read_raw can use the
+ * internal oscillator without disturbing the hardware configuration.
+ */
+ if (device_property_present(dev, "pwms")) {
+ st->manual_mode = false;
+ ret = ad4691_pwm_setup(st);
+ if (ret)
+ return ret;
+ } else {
+ st->manual_mode = true;
+ }
+
+ switch (st->vref_uV) {
+ case AD4691_VREF_uV_MIN ... AD4691_VREF_2P5_uV_MAX:
+ ref_val = AD4691_VREF_2P5;
+ break;
+ case AD4691_VREF_2P5_uV_MAX + 1 ... AD4691_VREF_3P0_uV_MAX:
+ ref_val = AD4691_VREF_3P0;
+ break;
+ case AD4691_VREF_3P0_uV_MAX + 1 ... AD4691_VREF_3P3_uV_MAX:
+ ref_val = AD4691_VREF_3P3;
+ break;
+ case AD4691_VREF_3P3_uV_MAX + 1 ... AD4691_VREF_4P096_uV_MAX:
+ ref_val = AD4691_VREF_4P096;
+ break;
+ case AD4691_VREF_4P096_uV_MAX + 1 ... AD4691_VREF_uV_MAX:
+ ref_val = AD4691_VREF_5P0;
+ break;
+ default:
+ return dev_err_probe(dev, -EINVAL,
+ "Unsupported vref voltage: %d uV\n",
+ st->vref_uV);
+ }
+
+ val = FIELD_PREP(AD4691_REF_CTRL_MASK, ref_val);
+ if (st->refbuf_en)
+ val |= AD4691_REFBUF_EN;
+
+ ret = regmap_write(st->regmap, AD4691_REF_CTRL, val);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to write REF_CTRL\n");
+
+ ret = regmap_assign_bits(st->regmap, AD4691_DEVICE_SETUP,
+ AD4691_LDO_EN, st->ldo_en);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to write DEVICE_SETUP\n");
+
+ /*
+ * Set the internal oscillator to the highest rate this chip supports.
+ * Index 0 (1 MHz) exceeds the 500 kHz max of AD4691/AD4693, so those
+ * chips start at index 1 (500 kHz).
+ */
+ ret = regmap_write(st->regmap, AD4691_OSC_FREQ_REG,
+ ad4691_samp_freq_start(st->info));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to write OSC_FREQ\n");
+
+ st->target_osc_freq_Hz = ad4691_osc_freqs_Hz[ad4691_samp_freq_start(st->info)];
+
+ ret = regmap_update_bits(st->regmap, AD4691_ADC_SETUP,
+ AD4691_ADC_MODE_MASK, AD4691_AUTONOMOUS_MODE);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to write ADC_SETUP\n");
+
+ ad4691_precompute_samp_freq_avail(st);
+
+ return 0;
+}
+
+static int ad4691_setup_triggered_buffer(struct iio_dev *indio_dev,
+ struct ad4691_state *st)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+ struct iio_trigger *trig;
+ unsigned int i;
+ int irq, ret;
+
+ /*
+ * Manual mode exposes channels without the oversampling_ratio attribute
+ * because ACC_DEPTH_IN is not configured in manual mode.
+ */
+ if (st->manual_mode)
+ indio_dev->channels = st->info->sw_info->manual_channels;
+ else
+ indio_dev->channels = st->info->sw_info->channels;
+ indio_dev->num_channels = st->info->sw_info->num_channels;
+ indio_dev->info = st->manual_mode ? &ad4691_manual_info : &ad4691_cnv_burst_info;
+
+ /*
+ * Manual mode relies on an external trigger (e.g. iio-trig-hrtimer);
+ * no internal trigger is needed or registered.
+ */
+ if (st->manual_mode)
+ return devm_iio_triggered_buffer_setup(dev, indio_dev,
+ iio_pollfunc_store_time,
+ ad4691_trigger_handler,
+ &ad4691_manual_buffer_setup_ops);
+
+ /*
+ * CNV burst mode: allocate an internal trigger driven by the
+ * DATA_READY IRQ on the GP pin.
+ */
+ trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!trig)
+ return -ENOMEM;
+
+ trig->ops = &ad4691_trigger_ops;
+ iio_trigger_set_drvdata(trig, st);
+
+ ret = devm_iio_trigger_register(dev, trig);
+ if (ret)
+ return dev_err_probe(dev, ret, "IIO trigger register failed\n");
+
+ indio_dev->trig = iio_trigger_get(trig);
+
+ /*
+ * The GP pin named in interrupt-names asserts at end-of-conversion.
+ * The IRQ handler fires the IIO trigger so the trigger handler can
+ * read and push the sample to the buffer. The IRQ is kept disabled
+ * until the buffer is enabled.
+ */
+ irq = -ENXIO;
+ for (i = 0; i < ARRAY_SIZE(ad4691_gp_names); i++) {
+ irq = fwnode_irq_get_byname(dev_fwnode(dev),
+ ad4691_gp_names[i]);
+ if (irq > 0 || irq == -EPROBE_DEFER)
+ break;
+ }
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "failed to get GP interrupt\n");
+
+ st->irq = irq;
+
+ ret = ad4691_gpio_setup(st, i);
+ if (ret)
+ return ret;
+
+ /*
+ * The handler only calls disable_irq_nosync() and iio_trigger_poll(),
+ * both safe in hardirq context, so register as a hard IRQ handler.
+ * IRQF_NO_AUTOEN keeps it disabled until the buffer is enabled.
+ */
+ ret = devm_request_irq(dev, irq, ad4691_irq, IRQF_NO_AUTOEN,
+ indio_dev->name, indio_dev);
+ if (ret)
+ return ret;
+
+ return devm_iio_triggered_buffer_setup_ext(dev, indio_dev,
+ iio_pollfunc_store_time,
+ ad4691_trigger_handler,
+ IIO_BUFFER_DIRECTION_IN,
+ &ad4691_cnv_burst_buffer_setup_ops,
+ ad4691_buffer_attrs);
+}
+
+static int ad4691_setup_offload(struct iio_dev *indio_dev,
+ struct ad4691_state *st,
+ struct spi_offload *spi_offload)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+ struct dma_chan *rx_dma;
+ int ret;
+
+ st->offload = spi_offload;
+
+ /*
+ * CNV burst offload exposes oversampling_ratio (ACC_DEPTH_IN is
+ * configured per channel at buffer enable). Manual offload does not
+ * configure ACC_DEPTH_IN, so it uses a separate channel array
+ * without the oversampling_ratio attribute. Both paths use IIO_CPU
+ * (no .endianness annotation) because bits_per_word=16 causes the
+ * SPI Engine to produce native 16-bit DMA words.
+ */
+ if (st->manual_mode)
+ indio_dev->channels = st->info->offload_info->manual_channels;
+ else
+ indio_dev->channels = st->info->offload_info->channels;
+ indio_dev->num_channels = st->info->offload_info->num_channels;
+ /*
+ * Offload path uses DMA directly; no IIO trigger is involved, so
+ * external triggers are not restricted (no validate_trigger).
+ */
+ indio_dev->info = &ad4691_manual_info;
+
+ if (st->manual_mode) {
+ st->offload_trigger =
+ devm_spi_offload_trigger_get(dev, st->offload,
+ SPI_OFFLOAD_TRIGGER_PERIODIC);
+ if (IS_ERR(st->offload_trigger))
+ return dev_err_probe(dev, PTR_ERR(st->offload_trigger),
+ "Failed to get periodic offload trigger\n");
+
+ st->trigger_hz = AD4691_OFFLOAD_INITIAL_TRIGGER_HZ;
+ } else {
+ struct spi_offload_trigger_info trigger_info = {
+ .fwnode = dev_fwnode(dev),
+ .ops = &ad4691_offload_trigger_ops,
+ .priv = st,
+ };
+
+ ret = devm_spi_offload_trigger_register(dev, &trigger_info);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to register offload trigger\n");
+
+ st->offload_trigger =
+ devm_spi_offload_trigger_get(dev, st->offload,
+ SPI_OFFLOAD_TRIGGER_DATA_READY);
+ if (IS_ERR(st->offload_trigger))
+ return dev_err_probe(dev, PTR_ERR(st->offload_trigger),
+ "Failed to get DATA_READY offload trigger\n");
+ }
+
+ rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload);
+ if (IS_ERR(rx_dma))
+ return dev_err_probe(dev, PTR_ERR(rx_dma),
+ "Failed to get offload RX DMA channel\n");
+
+ if (st->manual_mode)
+ indio_dev->setup_ops = &ad4691_manual_offload_buffer_setup_ops;
+ else
+ indio_dev->setup_ops = &ad4691_cnv_burst_offload_buffer_setup_ops;
+
+ ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma,
+ IIO_BUFFER_DIRECTION_IN);
+ if (ret)
+ return ret;
+
+ indio_dev->buffer->attrs = ad4691_buffer_attrs;
+
+ return 0;
+}
+
+static int ad4691_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct spi_offload *spi_offload;
+ struct iio_dev *indio_dev;
+ struct ad4691_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+ st->info = spi_get_device_match_data(spi);
+ if (!st->info)
+ return -ENODEV;
+ st->osr = 1;
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ st->regmap = devm_regmap_init(dev, NULL, spi, &ad4691_regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
+ "Failed to initialize regmap\n");
+
+ ret = ad4691_regulator_setup(st);
+ if (ret)
+ return ret;
+
+ ret = ad4691_reset(st);
+ if (ret)
+ return ret;
+
+ ret = ad4691_config(st);
+ if (ret)
+ return ret;
+
+ spi_offload = devm_spi_offload_get(dev, spi, &ad4691_offload_config);
+ ret = PTR_ERR_OR_ZERO(spi_offload);
+ if (ret == -ENODEV)
+ spi_offload = NULL;
+ else if (ret)
+ return dev_err_probe(dev, ret, "Failed to get SPI offload\n");
+
+ indio_dev->name = st->info->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ if (spi_offload)
+ ret = ad4691_setup_offload(indio_dev, st, spi_offload);
+ else
+ ret = ad4691_setup_triggered_buffer(indio_dev, st);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id ad4691_of_match[] = {
+ { .compatible = "adi,ad4691", .data = &ad4691_chip_info },
+ { .compatible = "adi,ad4692", .data = &ad4692_chip_info },
+ { .compatible = "adi,ad4693", .data = &ad4693_chip_info },
+ { .compatible = "adi,ad4694", .data = &ad4694_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad4691_of_match);
+
+static const struct spi_device_id ad4691_id[] = {
+ { .name = "ad4691", .driver_data = (kernel_ulong_t)&ad4691_chip_info },
+ { .name = "ad4692", .driver_data = (kernel_ulong_t)&ad4692_chip_info },
+ { .name = "ad4693", .driver_data = (kernel_ulong_t)&ad4693_chip_info },
+ { .name = "ad4694", .driver_data = (kernel_ulong_t)&ad4694_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad4691_id);
+
+static struct spi_driver ad4691_driver = {
+ .driver = {
+ .name = "ad4691",
+ .of_match_table = ad4691_of_match,
+ },
+ .probe = ad4691_probe,
+ .id_table = ad4691_id,
+};
+module_spi_driver(ad4691_driver);
+
+MODULE_AUTHOR("Radu Sabau <radu.sabau@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD4691 Family ADC Driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_DMA_BUFFER");
+MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
diff --git a/drivers/iio/adc/ad4695.c b/drivers/iio/adc/ad4695.c
index cda419638d9a..53642de7330d 100644
--- a/drivers/iio/adc/ad4695.c
+++ b/drivers/iio/adc/ad4695.c
@@ -876,14 +876,14 @@ static int ad4695_offload_buffer_postenable(struct iio_dev *indio_dev)
if (ret)
goto err_unoptimize_message;
- ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
- &config);
+ ret = ad4695_enter_advanced_sequencer_mode(st, num_slots);
if (ret)
goto err_disable_busy_output;
- ret = ad4695_enter_advanced_sequencer_mode(st, num_slots);
+ ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
+ &config);
if (ret)
- goto err_offload_trigger_disable;
+ goto err_exit_conversion_mode;
mutex_lock(&st->cnv_pwm_lock);
pwm_get_state(st->cnv_pwm, &state);
@@ -895,23 +895,16 @@ static int ad4695_offload_buffer_postenable(struct iio_dev *indio_dev)
ret = pwm_apply_might_sleep(st->cnv_pwm, &state);
mutex_unlock(&st->cnv_pwm_lock);
if (ret)
- goto err_offload_exit_conversion_mode;
+ goto err_offload_trigger_disable;
return 0;
-err_offload_exit_conversion_mode:
- /*
- * We have to unwind in a different order to avoid triggering offload.
- * ad4695_exit_conversion_mode() triggers a conversion, so it has to be
- * done after spi_offload_trigger_disable().
- */
- spi_offload_trigger_disable(st->offload, st->offload_trigger);
- ad4695_exit_conversion_mode(st);
- goto err_disable_busy_output;
-
err_offload_trigger_disable:
spi_offload_trigger_disable(st->offload, st->offload_trigger);
+err_exit_conversion_mode:
+ ad4695_exit_conversion_mode(st);
+
err_disable_busy_output:
regmap_clear_bits(st->regmap, AD4695_REG_GP_MODE,
AD4695_REG_GP_MODE_BUSY_GP_EN);
diff --git a/drivers/iio/adc/ad4851.c b/drivers/iio/adc/ad4851.c
index 1ad77f2a4580..480d1798f17b 100644
--- a/drivers/iio/adc/ad4851.c
+++ b/drivers/iio/adc/ad4851.c
@@ -12,7 +12,6 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/minmax.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pwm.h>
@@ -1286,15 +1285,15 @@ static const struct of_device_id ad4851_of_match[] = {
};
static const struct spi_device_id ad4851_spi_id[] = {
- { "ad4851", (kernel_ulong_t)&ad4851_info },
- { "ad4852", (kernel_ulong_t)&ad4852_info },
- { "ad4853", (kernel_ulong_t)&ad4853_info },
- { "ad4854", (kernel_ulong_t)&ad4854_info },
- { "ad4855", (kernel_ulong_t)&ad4855_info },
- { "ad4856", (kernel_ulong_t)&ad4856_info },
- { "ad4857", (kernel_ulong_t)&ad4857_info },
- { "ad4858", (kernel_ulong_t)&ad4858_info },
- { "ad4858i", (kernel_ulong_t)&ad4858i_info },
+ { .name = "ad4851", .driver_data = (kernel_ulong_t)&ad4851_info },
+ { .name = "ad4852", .driver_data = (kernel_ulong_t)&ad4852_info },
+ { .name = "ad4853", .driver_data = (kernel_ulong_t)&ad4853_info },
+ { .name = "ad4854", .driver_data = (kernel_ulong_t)&ad4854_info },
+ { .name = "ad4855", .driver_data = (kernel_ulong_t)&ad4855_info },
+ { .name = "ad4856", .driver_data = (kernel_ulong_t)&ad4856_info },
+ { .name = "ad4857", .driver_data = (kernel_ulong_t)&ad4857_info },
+ { .name = "ad4858", .driver_data = (kernel_ulong_t)&ad4858_info },
+ { .name = "ad4858i", .driver_data = (kernel_ulong_t)&ad4858i_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad4851_spi_id);
diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c
index bd4877268689..7bf7d538abd9 100644
--- a/drivers/iio/adc/ad7091r5.c
+++ b/drivers/iio/adc/ad7091r5.c
@@ -101,23 +101,17 @@ static const struct ad7091r_init_info ad7091r5_init_info = {
static int ad7091r5_i2c_probe(struct i2c_client *i2c)
{
- const struct ad7091r_init_info *init_info;
-
- init_info = i2c_get_match_data(i2c);
- if (!init_info)
- return -EINVAL;
-
- return ad7091r_probe(&i2c->dev, init_info, i2c->irq);
+ return ad7091r_probe(&i2c->dev, &ad7091r5_init_info, i2c->irq);
}
static const struct of_device_id ad7091r5_dt_ids[] = {
- { .compatible = "adi,ad7091r5", .data = &ad7091r5_init_info },
+ { .compatible = "adi,ad7091r5" },
{ }
};
MODULE_DEVICE_TABLE(of, ad7091r5_dt_ids);
static const struct i2c_device_id ad7091r5_i2c_ids[] = {
- { "ad7091r5", (kernel_ulong_t)&ad7091r5_init_info },
+ { .name = "ad7091r5" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad7091r5_i2c_ids);
diff --git a/drivers/iio/adc/ad7091r8.c b/drivers/iio/adc/ad7091r8.c
index e93b8bb60e8e..465a8ba01a22 100644
--- a/drivers/iio/adc/ad7091r8.c
+++ b/drivers/iio/adc/ad7091r8.c
@@ -249,9 +249,9 @@ static const struct of_device_id ad7091r8_of_match[] = {
MODULE_DEVICE_TABLE(of, ad7091r8_of_match);
static const struct spi_device_id ad7091r8_spi_id[] = {
- { "ad7091r2", (kernel_ulong_t)&ad7091r2_init_info },
- { "ad7091r4", (kernel_ulong_t)&ad7091r4_init_info },
- { "ad7091r8", (kernel_ulong_t)&ad7091r8_init_info },
+ { .name = "ad7091r2", .driver_data = (kernel_ulong_t)&ad7091r2_init_info },
+ { .name = "ad7091r4", .driver_data = (kernel_ulong_t)&ad7091r4_init_info },
+ { .name = "ad7091r8", .driver_data = (kernel_ulong_t)&ad7091r8_init_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7091r8_spi_id);
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index 5c1a8f886bcc..fc5dbc624856 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -19,7 +19,6 @@
#include <linux/kfifo.h>
#include <linux/minmax.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
@@ -1684,8 +1683,8 @@ 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_4_chip_info },
- { "ad7124-8", (kernel_ulong_t)&ad7124_8_chip_info },
+ { .name = "ad7124-4", .driver_data = (kernel_ulong_t)&ad7124_4_chip_info },
+ { .name = "ad7124-8", .driver_data = (kernel_ulong_t)&ad7124_8_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad71124_ids);
diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c
index d36612352b44..eb47175a0528 100644
--- a/drivers/iio/adc/ad7173.c
+++ b/drivers/iio/adc/ad7173.c
@@ -26,7 +26,6 @@
#include <linux/interrupt.h>
#include <linux/math64.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -561,8 +560,8 @@ out:
return ret;
}
-static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
- unsigned int offset, unsigned int *reg,
+static int ad7173_mask_xlate(struct gpio_regmap *gpio, enum gpio_regmap_operation op,
+ unsigned int base, unsigned int offset, unsigned int *reg,
unsigned int *mask)
{
*mask = AD7173_GPO_DATA(offset);
@@ -570,8 +569,8 @@ static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
return 0;
}
-static int ad4111_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
- unsigned int offset, unsigned int *reg,
+static int ad4111_mask_xlate(struct gpio_regmap *gpio, enum gpio_regmap_operation op,
+ unsigned int base, unsigned int offset, unsigned int *reg,
unsigned int *mask)
{
*mask = AD4111_GPO01_DATA(offset);
@@ -1763,7 +1762,8 @@ static int ad7173_validate_openwire_ain_inputs(struct ad7173_state *st,
static unsigned int ad7173_calc_openwire_thrsh_raw(struct ad7173_state *st,
struct iio_chan_spec *chan,
struct ad7173_channel *chan_st_priv,
- unsigned int thrsh_mv) {
+ unsigned int thrsh_mv)
+{
unsigned int thrsh_raw;
thrsh_raw =
@@ -2065,19 +2065,19 @@ static const struct of_device_id ad7173_of_match[] = {
MODULE_DEVICE_TABLE(of, ad7173_of_match);
static const struct spi_device_id ad7173_id_table[] = {
- { "ad4111", (kernel_ulong_t)&ad4111_device_info },
- { "ad4112", (kernel_ulong_t)&ad4112_device_info },
- { "ad4113", (kernel_ulong_t)&ad4113_device_info },
- { "ad4114", (kernel_ulong_t)&ad4114_device_info },
- { "ad4115", (kernel_ulong_t)&ad4115_device_info },
- { "ad4116", (kernel_ulong_t)&ad4116_device_info },
- { "ad7172-2", (kernel_ulong_t)&ad7172_2_device_info },
- { "ad7172-4", (kernel_ulong_t)&ad7172_4_device_info },
- { "ad7173-8", (kernel_ulong_t)&ad7173_8_device_info },
- { "ad7175-2", (kernel_ulong_t)&ad7175_2_device_info },
- { "ad7175-8", (kernel_ulong_t)&ad7175_8_device_info },
- { "ad7176-2", (kernel_ulong_t)&ad7176_2_device_info },
- { "ad7177-2", (kernel_ulong_t)&ad7177_2_device_info },
+ { .name = "ad4111", .driver_data = (kernel_ulong_t)&ad4111_device_info },
+ { .name = "ad4112", .driver_data = (kernel_ulong_t)&ad4112_device_info },
+ { .name = "ad4113", .driver_data = (kernel_ulong_t)&ad4113_device_info },
+ { .name = "ad4114", .driver_data = (kernel_ulong_t)&ad4114_device_info },
+ { .name = "ad4115", .driver_data = (kernel_ulong_t)&ad4115_device_info },
+ { .name = "ad4116", .driver_data = (kernel_ulong_t)&ad4116_device_info },
+ { .name = "ad7172-2", .driver_data = (kernel_ulong_t)&ad7172_2_device_info },
+ { .name = "ad7172-4", .driver_data = (kernel_ulong_t)&ad7172_4_device_info },
+ { .name = "ad7173-8", .driver_data = (kernel_ulong_t)&ad7173_8_device_info },
+ { .name = "ad7175-2", .driver_data = (kernel_ulong_t)&ad7175_2_device_info },
+ { .name = "ad7175-8", .driver_data = (kernel_ulong_t)&ad7175_8_device_info },
+ { .name = "ad7176-2", .driver_data = (kernel_ulong_t)&ad7176_2_device_info },
+ { .name = "ad7177-2", .driver_data = (kernel_ulong_t)&ad7177_2_device_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7173_id_table);
diff --git a/drivers/iio/adc/ad7191.c b/drivers/iio/adc/ad7191.c
index d9cd903ffdd2..071d26191b3c 100644
--- a/drivers/iio/adc/ad7191.c
+++ b/drivers/iio/adc/ad7191.c
@@ -11,7 +11,6 @@
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
@@ -154,27 +153,18 @@ static int ad7191_config_setup(struct iio_dev *indio_dev)
const u32 gain[4] = { 1, 8, 64, 128 };
static u32 scale_buffer[4][2];
int odr_value, odr_index = 0, pga_value, pga_index = 0, i, ret;
+ const char *propname;
u64 scale_uv;
st->samp_freq_index = 0;
st->scale_index = 0;
- ret = device_property_read_u32(dev, "adi,odr-value", &odr_value);
- if (ret && ret != -EINVAL)
- return dev_err_probe(dev, ret, "Failed to get odr value.\n");
+ propname = "adi,odr-value";
+ if (device_property_present(dev, propname)) {
+ ret = device_property_read_u32(dev, propname, &odr_value);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get %s.\n", propname);
- if (ret == -EINVAL) {
- st->odr_gpios = devm_gpiod_get_array(dev, "odr", GPIOD_OUT_LOW);
- if (IS_ERR(st->odr_gpios))
- return dev_err_probe(dev, PTR_ERR(st->odr_gpios),
- "Failed to get odr gpios.\n");
-
- if (st->odr_gpios->ndescs != 2)
- return dev_err_probe(dev, -EINVAL, "Expected 2 odr gpio pins.\n");
-
- st->samp_freq_avail = samp_freq;
- st->samp_freq_avail_size = ARRAY_SIZE(samp_freq);
- } else {
for (i = 0; i < ARRAY_SIZE(samp_freq); i++) {
if (odr_value != samp_freq[i])
continue;
@@ -186,6 +176,17 @@ static int ad7191_config_setup(struct iio_dev *indio_dev)
st->samp_freq_avail_size = 1;
st->odr_gpios = NULL;
+ } else {
+ st->odr_gpios = devm_gpiod_get_array(dev, "odr", GPIOD_OUT_LOW);
+ if (IS_ERR(st->odr_gpios))
+ return dev_err_probe(dev, PTR_ERR(st->odr_gpios),
+ "Failed to get odr gpios.\n");
+
+ if (st->odr_gpios->ndescs != 2)
+ return dev_err_probe(dev, -EINVAL, "Expected 2 odr gpio pins.\n");
+
+ st->samp_freq_avail = samp_freq;
+ st->samp_freq_avail_size = ARRAY_SIZE(samp_freq);
}
mutex_lock(&st->lock);
@@ -200,22 +201,12 @@ static int ad7191_config_setup(struct iio_dev *indio_dev)
mutex_unlock(&st->lock);
- ret = device_property_read_u32(dev, "adi,pga-value", &pga_value);
- if (ret && ret != -EINVAL)
- return dev_err_probe(dev, ret, "Failed to get pga value.\n");
+ propname = "adi,pga-value";
+ if (device_property_present(dev, propname)) {
+ ret = device_property_read_u32(dev, propname, &pga_value);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get %s.\n", propname);
- if (ret == -EINVAL) {
- st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW);
- if (IS_ERR(st->pga_gpios))
- return dev_err_probe(dev, PTR_ERR(st->pga_gpios),
- "Failed to get pga gpios.\n");
-
- if (st->pga_gpios->ndescs != 2)
- return dev_err_probe(dev, -EINVAL, "Expected 2 pga gpio pins.\n");
-
- st->scale_avail = scale_buffer;
- st->scale_avail_size = ARRAY_SIZE(scale_buffer);
- } else {
for (i = 0; i < ARRAY_SIZE(gain); i++) {
if (pga_value != gain[i])
continue;
@@ -227,6 +218,17 @@ static int ad7191_config_setup(struct iio_dev *indio_dev)
st->scale_avail_size = 1;
st->pga_gpios = NULL;
+ } else {
+ st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW);
+ if (IS_ERR(st->pga_gpios))
+ return dev_err_probe(dev, PTR_ERR(st->pga_gpios),
+ "Failed to get pga gpios.\n");
+
+ if (st->pga_gpios->ndescs != 2)
+ return dev_err_probe(dev, -EINVAL, "Expected 2 pga gpio pins.\n");
+
+ st->scale_avail = scale_buffer;
+ st->scale_avail_size = ARRAY_SIZE(scale_buffer);
}
st->temp_gpio = devm_gpiod_get(dev, "temp", GPIOD_OUT_LOW);
@@ -533,7 +535,7 @@ static const struct of_device_id ad7191_of_match[] = {
MODULE_DEVICE_TABLE(of, ad7191_of_match);
static const struct spi_device_id ad7191_id_table[] = {
- { "ad7191" },
+ { .name = "ad7191" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7191_id_table);
diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c
index 530e1d307860..d8f5886fcf69 100644
--- a/drivers/iio/adc/ad7192.c
+++ b/drivers/iio/adc/ad7192.c
@@ -20,7 +20,6 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/units.h>
@@ -39,7 +38,7 @@
#define AD7192_REG_CONF 2 /* Configuration Register (RW, 24-bit) */
#define AD7192_REG_DATA 3 /* Data Register (RO, 24/32-bit) */
#define AD7192_REG_ID 4 /* ID Register (RO, 8-bit) */
-#define AD7192_REG_GPOCON 5 /* GPOCON Register (RO, 8-bit) */
+#define AD7192_REG_GPOCON 5 /* GPOCON Register (RW, 8-bit) */
#define AD7192_REG_OFFSET 6 /* Offset Register (RW, 16-bit */
/* (AD7792)/24-bit (AD7192)) */
#define AD7192_REG_FULLSALE 7 /* Full-Scale Register */
@@ -576,7 +575,12 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev)
ret = ad_sd_reset(&st->sd);
if (ret < 0)
return ret;
- usleep_range(500, 1000); /* Wait for at least 500us */
+
+ /*
+ * Per AD7192 datasheet (Rev. A, page 34, RESET section), allow
+ * 500 us after a reset before accessing on-chip registers.
+ */
+ fsleep(500);
/* write/read test for device presence */
ret = ad_sd_read_reg(&st->sd, AD7192_REG_ID, 1, &id);
@@ -1402,9 +1406,6 @@ static int ad7192_probe(struct spi_device *spi)
st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI;
st->chip_info = spi_get_device_match_data(spi);
- if (!st->chip_info)
- return -ENODEV;
-
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = st->chip_info->info;
@@ -1447,11 +1448,11 @@ 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] },
- { "ad7194", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] },
- { "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] },
+ { .name = "ad7190", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] },
+ { .name = "ad7192", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] },
+ { .name = "ad7193", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] },
+ { .name = "ad7194", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] },
+ { .name = "ad7195", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7192_ids);
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index 3364ac6c4631..594a070c3745 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -409,10 +409,8 @@ static int ad7266_probe(struct spi_device *spi)
st->gpios[i] = devm_gpiod_get(&spi->dev,
ad7266_gpio_labels[i],
GPIOD_OUT_LOW);
- if (IS_ERR(st->gpios[i])) {
- ret = PTR_ERR(st->gpios[i]);
- return ret;
- }
+ if (IS_ERR(st->gpios[i]))
+ return PTR_ERR(st->gpios[i]);
}
}
} else {
@@ -455,8 +453,8 @@ static int ad7266_probe(struct spi_device *spi)
}
static const struct spi_device_id ad7266_id[] = {
- { "ad7265", 0 },
- { "ad7266", 0 },
+ { .name = "ad7265" },
+ { .name = "ad7266" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7266_id);
diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c
index ba12a3796e2b..5ae0d694d20c 100644
--- a/drivers/iio/adc/ad7280a.c
+++ b/drivers/iio/adc/ad7280a.c
@@ -15,7 +15,6 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
@@ -496,7 +495,8 @@ static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev,
devaddr = chan->address >> 8;
ch = chan->address & 0xFF;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
+
if (readin)
st->cb_mask[devaddr] |= BIT(ch);
else
@@ -505,7 +505,6 @@ static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev,
ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE_REG, 0,
FIELD_PREP(AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK,
st->cb_mask[devaddr]));
- mutex_unlock(&st->lock);
return ret ? ret : len;
}
@@ -516,14 +515,13 @@ static ssize_t ad7280_show_balance_timer(struct iio_dev *indio_dev,
char *buf)
{
struct ad7280_state *st = iio_priv(indio_dev);
+ u8 devaddr = chan->address >> 8;
+ u8 ch = chan->address & 0xFF;
unsigned int msecs;
int ret;
- mutex_lock(&st->lock);
- ret = ad7280_read_reg(st, chan->address >> 8,
- (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG);
- mutex_unlock(&st->lock);
-
+ scoped_guard(mutex, &st->lock)
+ ret = ad7280_read_reg(st, devaddr, ch + AD7280A_CB1_TIMER_REG);
if (ret < 0)
return ret;
@@ -538,6 +536,8 @@ static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev,
const char *buf, size_t len)
{
struct ad7280_state *st = iio_priv(indio_dev);
+ u8 devaddr = chan->address >> 8;
+ u8 ch = chan->address & 0xFF;
int val, val2;
int ret;
@@ -551,11 +551,10 @@ static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev,
if (val > 31)
return -EINVAL;
- mutex_lock(&st->lock);
- ret = ad7280_write(st, chan->address >> 8,
- (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG, 0,
+ guard(mutex)(&st->lock);
+
+ ret = ad7280_write(st, devaddr, ch + AD7280A_CB1_TIMER_REG, 0,
FIELD_PREP(AD7280A_CB_TIMER_VAL_MSK, val));
- mutex_unlock(&st->lock);
return ret ? ret : len;
}
@@ -737,7 +736,8 @@ static int ad7280a_write_thresh(struct iio_dev *indio_dev,
if (val2 != 0)
return -EINVAL;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
+
switch (chan->type) {
case IIO_VOLTAGE:
value = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */
@@ -748,22 +748,20 @@ static int ad7280a_write_thresh(struct iio_dev *indio_dev,
ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr,
1, value);
if (ret)
- break;
+ return ret;
st->cell_threshhigh = value;
- break;
+ return 0;
case IIO_EV_DIR_FALLING:
addr = AD7280A_CELL_UNDERVOLTAGE_REG;
ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr,
1, value);
if (ret)
- break;
+ return ret;
st->cell_threshlow = value;
- break;
+ return 0;
default:
- ret = -EINVAL;
- goto err_unlock;
+ return -EINVAL;
}
- break;
case IIO_TEMP:
value = (val * 10) / 196; /* LSB 19.6mV */
value = clamp(value, 0L, 0xFFL);
@@ -773,31 +771,23 @@ static int ad7280a_write_thresh(struct iio_dev *indio_dev,
ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr,
1, value);
if (ret)
- break;
+ return ret;
st->aux_threshhigh = value;
- break;
+ return 0;
case IIO_EV_DIR_FALLING:
addr = AD7280A_AUX_ADC_UNDERVOLTAGE_REG;
ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr,
1, value);
if (ret)
- break;
+ return ret;
st->aux_threshlow = value;
- break;
+ return 0;
default:
- ret = -EINVAL;
- goto err_unlock;
+ return -EINVAL;
}
- break;
default:
- ret = -EINVAL;
- goto err_unlock;
+ return -EINVAL;
}
-
-err_unlock:
- mutex_unlock(&st->lock);
-
- return ret;
}
static irqreturn_t ad7280_event_handler(int irq, void *private)
@@ -806,8 +796,8 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
struct ad7280_state *st = iio_priv(indio_dev);
int i, ret;
- unsigned int *channels __free(kfree) = kcalloc(st->scan_cnt, sizeof(*channels),
- GFP_KERNEL);
+ unsigned int *channels __free(kfree) = kzalloc_objs(*channels,
+ st->scan_cnt);
if (!channels)
return IRQ_HANDLED;
@@ -881,17 +871,18 @@ static int ad7280_read_raw(struct iio_dev *indio_dev,
long m)
{
struct ad7280_state *st = iio_priv(indio_dev);
+ u8 devaddr = chan->address >> 8;
+ u8 ch = chan->address & 0xFF;
int ret;
switch (m) {
- case IIO_CHAN_INFO_RAW:
- mutex_lock(&st->lock);
+ case IIO_CHAN_INFO_RAW: {
+ guard(mutex)(&st->lock);
+
if (chan->address == AD7280A_ALL_CELLS)
ret = ad7280_read_all_channels(st, st->scan_cnt, NULL);
else
- ret = ad7280_read_channel(st, chan->address >> 8,
- chan->address & 0xFF);
- mutex_unlock(&st->lock);
+ ret = ad7280_read_channel(st, devaddr, ch);
if (ret < 0)
return ret;
@@ -899,8 +890,9 @@ static int ad7280_read_raw(struct iio_dev *indio_dev,
*val = ret;
return IIO_VAL_INT;
+ }
case IIO_CHAN_INFO_SCALE:
- if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6_REG)
+ if (ch <= AD7280A_CELL_VOLTAGE_6_REG)
*val = 4000;
else
*val = 5000;
@@ -990,8 +982,8 @@ static int ad7280_probe(struct spi_device *spi)
st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1600ns;
break;
default:
- dev_err(dev, "Firmware provided acquisition time is invalid\n");
- return -EINVAL;
+ return dev_err_probe(dev, -EINVAL,
+ "Firmware provided acquisition time is invalid\n");
}
} else {
st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns;
@@ -1090,7 +1082,7 @@ static int ad7280_probe(struct spi_device *spi)
}
static const struct spi_device_id ad7280_id[] = {
- { "ad7280a", 0 },
+ { .name = "ad7280a" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7280_id);
diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c
index 60e12faa3207..6a1493e27a30 100644
--- a/drivers/iio/adc/ad7291.c
+++ b/drivers/iio/adc/ad7291.c
@@ -536,7 +536,7 @@ static int ad7291_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad7291_id[] = {
- { "ad7291" },
+ { .name = "ad7291" },
{ }
};
diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c
index a398973f313d..1d7bf46b80e2 100644
--- a/drivers/iio/adc/ad7292.c
+++ b/drivers/iio/adc/ad7292.c
@@ -8,7 +8,6 @@
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
@@ -253,12 +252,13 @@ static const struct iio_info ad7292_info = {
static int ad7292_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
struct ad7292_state *st;
struct iio_dev *indio_dev;
bool diff_channels = false;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -266,12 +266,11 @@ static int ad7292_probe(struct spi_device *spi)
st->spi = spi;
ret = ad7292_spi_reg_read(st, AD7292_REG_VENDOR_ID);
- if (ret != ADI_VENDOR_ID) {
- dev_err(&spi->dev, "Wrong vendor id 0x%x\n", ret);
- return -EINVAL;
- }
+ if (ret != ADI_VENDOR_ID)
+ return dev_err_probe(dev, -EINVAL,
+ "Wrong vendor id 0x%x\n", ret);
- ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
+ ret = devm_regulator_get_enable_read_voltage(dev, "vref");
if (ret < 0 && ret != -ENODEV)
return ret;
@@ -281,7 +280,7 @@ static int ad7292_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ad7292_info;
- device_for_each_child_node_scoped(&spi->dev, child) {
+ device_for_each_child_node_scoped(dev, child) {
diff_channels = fwnode_property_read_bool(child,
"diff-channels");
if (diff_channels)
@@ -296,11 +295,11 @@ static int ad7292_probe(struct spi_device *spi)
indio_dev->channels = ad7292_channels;
}
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id ad7292_id_table[] = {
- { "ad7292", 0 },
+ { .name = "ad7292" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7292_id_table);
diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
index 7c0538ea15c8..c669022b5dec 100644
--- a/drivers/iio/adc/ad7298.c
+++ b/drivers/iio/adc/ad7298.c
@@ -13,7 +13,6 @@
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/delay.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
@@ -354,7 +353,7 @@ static const struct acpi_device_id ad7298_acpi_ids[] = {
MODULE_DEVICE_TABLE(acpi, ad7298_acpi_ids);
static const struct spi_device_id ad7298_id[] = {
- { "ad7298", 0 },
+ { .name = "ad7298" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7298_id);
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
index bfd908deefc0..2e90f125a797 100644
--- a/drivers/iio/adc/ad7380.c
+++ b/drivers/iio/adc/ad7380.c
@@ -77,8 +77,7 @@
#define AD7380_CONFIG1_REFSEL BIT(1)
#define AD7380_CONFIG1_PMODE BIT(0)
-#define AD7380_CONFIG2_SDO2 GENMASK(9, 8)
-#define AD7380_CONFIG2_SDO BIT(8)
+#define AD7380_CONFIG2_SDO GENMASK(9, 8)
#define AD7380_CONFIG2_RESET GENMASK(7, 0)
#define AD7380_CONFIG2_RESET_SOFT 0x3C
@@ -92,11 +91,6 @@
#define T_CONVERT_X_NS 500 /* xth conversion start time (oversampling) */
#define T_POWERUP_US 5000 /* Power up */
-/*
- * AD738x support several SDO lines to increase throughput, but driver currently
- * supports only 1 SDO line (standard SPI transaction)
- */
-#define AD7380_NUM_SDO_LINES 1
#define AD7380_DEFAULT_GAIN_MILLI 1000
/*
@@ -888,6 +882,8 @@ struct ad7380_state {
bool resolution_boost_enabled;
unsigned int ch;
bool seq;
+ /* How many SDO lines are wired up. */
+ u8 num_sdo_lines;
unsigned int vref_mv;
unsigned int vcm_mv[MAX_NUM_CHANNELS];
unsigned int gain_milli[MAX_NUM_CHANNELS];
@@ -1084,7 +1080,7 @@ static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch)
if (oversampling_ratio > 1)
xfer.delay.value = T_CONVERT_0_NS +
T_CONVERT_X_NS * (oversampling_ratio - 1) *
- st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES;
+ st->chip_info->num_simult_channels / st->num_sdo_lines;
return spi_sync_transfer(st->spi, &xfer, 1);
}
@@ -1113,7 +1109,7 @@ static int ad7380_update_xfers(struct ad7380_state *st,
if (oversampling_ratio > 1)
t_convert = T_CONVERT_0_NS + T_CONVERT_X_NS *
(oversampling_ratio - 1) *
- st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES;
+ st->chip_info->num_simult_channels / st->num_sdo_lines;
if (st->seq) {
xfer[0].delay.value = xfer[1].delay.value = t_convert;
@@ -1198,6 +1194,8 @@ static int ad7380_init_offload_msg(struct ad7380_state *st,
xfer->bits_per_word = scan_type->realbits;
xfer->offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
xfer->len = AD7380_SPI_BYTES(scan_type) * st->chip_info->num_simult_channels;
+ if (st->num_sdo_lines > 1)
+ xfer->multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
spi_message_init_with_transfers(&st->offload_msg, xfer, 1);
st->offload_msg.offload = st->offload;
@@ -1793,6 +1791,7 @@ static const struct iio_info ad7380_info = {
static int ad7380_init(struct ad7380_state *st, bool external_ref_en)
{
+ u32 sdo;
int ret;
/* perform hard reset */
@@ -1815,11 +1814,24 @@ static int ad7380_init(struct ad7380_state *st, bool external_ref_en)
st->ch = 0;
st->seq = false;
- /* SPI 1-wire mode */
+ /* SDO field has an irregular mapping. */
+ switch (st->num_sdo_lines) {
+ case 1:
+ sdo = 1;
+ break;
+ case 2:
+ sdo = 0;
+ break;
+ case 4:
+ sdo = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
AD7380_CONFIG2_SDO,
- FIELD_PREP(AD7380_CONFIG2_SDO,
- AD7380_NUM_SDO_LINES));
+ FIELD_PREP(AD7380_CONFIG2_SDO, sdo));
}
static int ad7380_probe_spi_offload(struct iio_dev *indio_dev,
@@ -1842,7 +1854,7 @@ static int ad7380_probe_spi_offload(struct iio_dev *indio_dev,
"failed to get offload trigger\n");
sample_rate = st->chip_info->max_conversion_rate_hz *
- AD7380_NUM_SDO_LINES / st->chip_info->num_simult_channels;
+ st->num_sdo_lines / st->chip_info->num_simult_channels;
st->sample_freq_range[0] = 1; /* min */
st->sample_freq_range[1] = 1; /* step */
@@ -1850,7 +1862,7 @@ static int ad7380_probe_spi_offload(struct iio_dev *indio_dev,
/*
* Starting with a quite low frequency, to allow oversampling x32,
- * user is then reponsible to adjust the frequency for the specific case.
+ * user is then responsible to adjust the frequency for the specific case.
*/
ret = ad7380_set_sample_freq(st, sample_rate / 32);
if (ret)
@@ -1887,6 +1899,13 @@ static int ad7380_probe(struct spi_device *spi)
if (!st->chip_info)
return dev_err_probe(dev, -EINVAL, "missing match data\n");
+ st->num_sdo_lines = spi->num_rx_lanes;
+
+ if (st->num_sdo_lines < 1 || st->num_sdo_lines > st->chip_info->num_simult_channels)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid number of SDO lines (%d)\n",
+ st->num_sdo_lines);
+
ret = devm_regulator_bulk_get_enable(dev, st->chip_info->num_supplies,
st->chip_info->supplies);
@@ -2010,6 +2029,8 @@ static int ad7380_probe(struct spi_device *spi)
st->normal_xfer[0].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
st->normal_xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
st->normal_xfer[1].rx_buf = st->scan_data;
+ if (st->num_sdo_lines > 1)
+ st->normal_xfer[1].multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
spi_message_init_with_transfers(&st->normal_msg, st->normal_xfer,
ARRAY_SIZE(st->normal_xfer));
@@ -2031,6 +2052,10 @@ static int ad7380_probe(struct spi_device *spi)
st->seq_xfer[2].cs_change = 1;
st->seq_xfer[2].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
st->seq_xfer[2].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
+ if (st->num_sdo_lines > 1) {
+ st->seq_xfer[2].multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
+ st->seq_xfer[3].multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
+ }
spi_message_init_with_transfers(&st->seq_msg, st->seq_xfer,
ARRAY_SIZE(st->seq_xfer));
@@ -2091,24 +2116,24 @@ static const struct of_device_id ad7380_of_match_table[] = {
};
static const struct spi_device_id ad7380_id_table[] = {
- { "ad7380", (kernel_ulong_t)&ad7380_chip_info },
- { "ad7381", (kernel_ulong_t)&ad7381_chip_info },
- { "ad7383", (kernel_ulong_t)&ad7383_chip_info },
- { "ad7384", (kernel_ulong_t)&ad7384_chip_info },
- { "ad7386", (kernel_ulong_t)&ad7386_chip_info },
- { "ad7387", (kernel_ulong_t)&ad7387_chip_info },
- { "ad7388", (kernel_ulong_t)&ad7388_chip_info },
- { "ad7380-4", (kernel_ulong_t)&ad7380_4_chip_info },
- { "ad7381-4", (kernel_ulong_t)&ad7381_4_chip_info },
- { "ad7383-4", (kernel_ulong_t)&ad7383_4_chip_info },
- { "ad7384-4", (kernel_ulong_t)&ad7384_4_chip_info },
- { "ad7386-4", (kernel_ulong_t)&ad7386_4_chip_info },
- { "ad7387-4", (kernel_ulong_t)&ad7387_4_chip_info },
- { "ad7388-4", (kernel_ulong_t)&ad7388_4_chip_info },
- { "ad7389-4", (kernel_ulong_t)&ad7389_4_chip_info },
- { "adaq4370-4", (kernel_ulong_t)&adaq4370_4_chip_info },
- { "adaq4380-4", (kernel_ulong_t)&adaq4380_4_chip_info },
- { "adaq4381-4", (kernel_ulong_t)&adaq4381_4_chip_info },
+ { .name = "ad7380", .driver_data = (kernel_ulong_t)&ad7380_chip_info },
+ { .name = "ad7381", .driver_data = (kernel_ulong_t)&ad7381_chip_info },
+ { .name = "ad7383", .driver_data = (kernel_ulong_t)&ad7383_chip_info },
+ { .name = "ad7384", .driver_data = (kernel_ulong_t)&ad7384_chip_info },
+ { .name = "ad7386", .driver_data = (kernel_ulong_t)&ad7386_chip_info },
+ { .name = "ad7387", .driver_data = (kernel_ulong_t)&ad7387_chip_info },
+ { .name = "ad7388", .driver_data = (kernel_ulong_t)&ad7388_chip_info },
+ { .name = "ad7380-4", .driver_data = (kernel_ulong_t)&ad7380_4_chip_info },
+ { .name = "ad7381-4", .driver_data = (kernel_ulong_t)&ad7381_4_chip_info },
+ { .name = "ad7383-4", .driver_data = (kernel_ulong_t)&ad7383_4_chip_info },
+ { .name = "ad7384-4", .driver_data = (kernel_ulong_t)&ad7384_4_chip_info },
+ { .name = "ad7386-4", .driver_data = (kernel_ulong_t)&ad7386_4_chip_info },
+ { .name = "ad7387-4", .driver_data = (kernel_ulong_t)&ad7387_4_chip_info },
+ { .name = "ad7388-4", .driver_data = (kernel_ulong_t)&ad7388_4_chip_info },
+ { .name = "ad7389-4", .driver_data = (kernel_ulong_t)&ad7389_4_chip_info },
+ { .name = "adaq4370-4", .driver_data = (kernel_ulong_t)&adaq4370_4_chip_info },
+ { .name = "adaq4380-4", .driver_data = (kernel_ulong_t)&adaq4380_4_chip_info },
+ { .name = "adaq4381-4", .driver_data = (kernel_ulong_t)&adaq4381_4_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7380_id_table);
diff --git a/drivers/iio/adc/ad7405.c b/drivers/iio/adc/ad7405.c
index 9adf85a732ce..0996f48d76f1 100644
--- a/drivers/iio/adc/ad7405.c
+++ b/drivers/iio/adc/ad7405.c
@@ -10,7 +10,6 @@
#include <linux/err.h>
#include <linux/math64.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 21d3f6aae972..c007f453ae18 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -411,42 +411,42 @@ static int ad7476_probe(struct spi_device *spi)
}
static const struct spi_device_id ad7476_id[] = {
- { "ad7091", (kernel_ulong_t)&ad7091_chip_info },
- { "ad7091r", (kernel_ulong_t)&ad7091r_chip_info },
- { "ad7273", (kernel_ulong_t)&ad7273_chip_info },
- { "ad7274", (kernel_ulong_t)&ad7274_chip_info },
- { "ad7276", (kernel_ulong_t)&ad7276_chip_info },
- { "ad7277", (kernel_ulong_t)&ad7277_chip_info },
- { "ad7278", (kernel_ulong_t)&ad7278_chip_info },
- { "ad7466", (kernel_ulong_t)&ad7466_chip_info },
- { "ad7467", (kernel_ulong_t)&ad7467_chip_info },
- { "ad7468", (kernel_ulong_t)&ad7468_chip_info },
- { "ad7475", (kernel_ulong_t)&ad7475_chip_info },
- { "ad7476", (kernel_ulong_t)&ad7466_chip_info },
- { "ad7476a", (kernel_ulong_t)&ad7466_chip_info },
- { "ad7477", (kernel_ulong_t)&ad7467_chip_info },
- { "ad7477a", (kernel_ulong_t)&ad7467_chip_info },
- { "ad7478", (kernel_ulong_t)&ad7468_chip_info },
- { "ad7478a", (kernel_ulong_t)&ad7468_chip_info },
- { "ad7495", (kernel_ulong_t)&ad7495_chip_info },
- { "ad7910", (kernel_ulong_t)&ad7467_chip_info },
- { "ad7920", (kernel_ulong_t)&ad7466_chip_info },
- { "ad7940", (kernel_ulong_t)&ad7940_chip_info },
- { "adc081s", (kernel_ulong_t)&adc081s_chip_info },
- { "adc101s", (kernel_ulong_t)&adc101s_chip_info },
- { "adc121s", (kernel_ulong_t)&adc121s_chip_info },
- { "ads7866", (kernel_ulong_t)&ads7866_chip_info },
- { "ads7867", (kernel_ulong_t)&ads7867_chip_info },
- { "ads7868", (kernel_ulong_t)&ads7868_chip_info },
- { "bd79105", (kernel_ulong_t)&bd79105_chip_info },
+ { .name = "ad7091", .driver_data = (kernel_ulong_t)&ad7091_chip_info },
+ { .name = "ad7091r", .driver_data = (kernel_ulong_t)&ad7091r_chip_info },
+ { .name = "ad7273", .driver_data = (kernel_ulong_t)&ad7273_chip_info },
+ { .name = "ad7274", .driver_data = (kernel_ulong_t)&ad7274_chip_info },
+ { .name = "ad7276", .driver_data = (kernel_ulong_t)&ad7276_chip_info },
+ { .name = "ad7277", .driver_data = (kernel_ulong_t)&ad7277_chip_info },
+ { .name = "ad7278", .driver_data = (kernel_ulong_t)&ad7278_chip_info },
+ { .name = "ad7466", .driver_data = (kernel_ulong_t)&ad7466_chip_info },
+ { .name = "ad7467", .driver_data = (kernel_ulong_t)&ad7467_chip_info },
+ { .name = "ad7468", .driver_data = (kernel_ulong_t)&ad7468_chip_info },
+ { .name = "ad7475", .driver_data = (kernel_ulong_t)&ad7475_chip_info },
+ { .name = "ad7476", .driver_data = (kernel_ulong_t)&ad7466_chip_info },
+ { .name = "ad7476a", .driver_data = (kernel_ulong_t)&ad7466_chip_info },
+ { .name = "ad7477", .driver_data = (kernel_ulong_t)&ad7467_chip_info },
+ { .name = "ad7477a", .driver_data = (kernel_ulong_t)&ad7467_chip_info },
+ { .name = "ad7478", .driver_data = (kernel_ulong_t)&ad7468_chip_info },
+ { .name = "ad7478a", .driver_data = (kernel_ulong_t)&ad7468_chip_info },
+ { .name = "ad7495", .driver_data = (kernel_ulong_t)&ad7495_chip_info },
+ { .name = "ad7910", .driver_data = (kernel_ulong_t)&ad7467_chip_info },
+ { .name = "ad7920", .driver_data = (kernel_ulong_t)&ad7466_chip_info },
+ { .name = "ad7940", .driver_data = (kernel_ulong_t)&ad7940_chip_info },
+ { .name = "adc081s", .driver_data = (kernel_ulong_t)&adc081s_chip_info },
+ { .name = "adc101s", .driver_data = (kernel_ulong_t)&adc101s_chip_info },
+ { .name = "adc121s", .driver_data = (kernel_ulong_t)&adc121s_chip_info },
+ { .name = "ads7866", .driver_data = (kernel_ulong_t)&ads7866_chip_info },
+ { .name = "ads7867", .driver_data = (kernel_ulong_t)&ads7867_chip_info },
+ { .name = "ads7868", .driver_data = (kernel_ulong_t)&ads7868_chip_info },
+ { .name = "bd79105", .driver_data = (kernel_ulong_t)&bd79105_chip_info },
/*
* The ROHM BU79100G is identical to the TI's ADS7866 from the software
* point of view. The binding document mandates the ADS7866 to be
* marked as a fallback for the BU79100G, but we still need the SPI ID
* here to make the module loading work.
*/
- { "bu79100g", (kernel_ulong_t)&ads7866_chip_info },
- { "ltc2314-14", (kernel_ulong_t)&ltc2314_14_chip_info },
+ { .name = "bu79100g", .driver_data = (kernel_ulong_t)&ads7866_chip_info },
+ { .name = "ltc2314-14", .driver_data = (kernel_ulong_t)&ltc2314_14_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7476_id);
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index d9271894f091..cebb8ed8dcb1 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -1475,7 +1475,7 @@ static int ad7606_probe_channels(struct iio_dev *indio_dev)
}
if (slow_bus)
- channels[i] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(i);
+ channels[i] = IIO_CHAN_SOFT_TIMESTAMP(i);
indio_dev->channels = channels;
diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c
index b81e707ab40c..5b137e947f0b 100644
--- a/drivers/iio/adc/ad7606_par.c
+++ b/drivers/iio/adc/ad7606_par.c
@@ -9,7 +9,6 @@
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/io.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c
index 7e17ccbcedd0..1ebdfb8580ab 100644
--- a/drivers/iio/adc/ad7606_spi.c
+++ b/drivers/iio/adc/ad7606_spi.c
@@ -463,17 +463,17 @@ static int ad7606_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id ad7606_id_table[] = {
- { "ad7605-4", (kernel_ulong_t)&ad7605_4_bus_info },
- { "ad7606-4", (kernel_ulong_t)&ad7606_4_bus_info },
- { "ad7606-6", (kernel_ulong_t)&ad7606_6_bus_info },
- { "ad7606-8", (kernel_ulong_t)&ad7606_8_bus_info },
- { "ad7606b", (kernel_ulong_t)&ad7606b_bus_info },
- { "ad7606c-16", (kernel_ulong_t)&ad7606c_16_bus_info },
- { "ad7606c-18", (kernel_ulong_t)&ad7606c_18_bus_info },
- { "ad7607", (kernel_ulong_t)&ad7607_bus_info },
- { "ad7608", (kernel_ulong_t)&ad7608_bus_info },
- { "ad7609", (kernel_ulong_t)&ad7609_bus_info },
- { "ad7616", (kernel_ulong_t)&ad7616_bus_info },
+ { .name = "ad7605-4", .driver_data = (kernel_ulong_t)&ad7605_4_bus_info },
+ { .name = "ad7606-4", .driver_data = (kernel_ulong_t)&ad7606_4_bus_info },
+ { .name = "ad7606-6", .driver_data = (kernel_ulong_t)&ad7606_6_bus_info },
+ { .name = "ad7606-8", .driver_data = (kernel_ulong_t)&ad7606_8_bus_info },
+ { .name = "ad7606b", .driver_data = (kernel_ulong_t)&ad7606b_bus_info },
+ { .name = "ad7606c-16", .driver_data = (kernel_ulong_t)&ad7606c_16_bus_info },
+ { .name = "ad7606c-18", .driver_data = (kernel_ulong_t)&ad7606c_18_bus_info },
+ { .name = "ad7607", .driver_data = (kernel_ulong_t)&ad7607_bus_info },
+ { .name = "ad7608", .driver_data = (kernel_ulong_t)&ad7608_bus_info },
+ { .name = "ad7609", .driver_data = (kernel_ulong_t)&ad7609_bus_info },
+ { .name = "ad7616", .driver_data = (kernel_ulong_t)&ad7616_bus_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7606_id_table);
diff --git a/drivers/iio/adc/ad7625.c b/drivers/iio/adc/ad7625.c
index 0466c0c7eae4..e73a5c9e7f0b 100644
--- a/drivers/iio/adc/ad7625.c
+++ b/drivers/iio/adc/ad7625.c
@@ -17,7 +17,6 @@
#include <linux/iio/backend.h>
#include <linux/iio/iio.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
@@ -175,12 +174,12 @@ enum ad7960_mode {
static int ad7625_set_sampling_freq(struct ad7625_state *st, u32 freq)
{
- u32 target;
struct pwm_waveform clk_gate_wf = { }, cnv_wf = { };
+ unsigned long target;
int ret;
target = DIV_ROUND_UP(NSEC_PER_SEC, freq);
- cnv_wf.period_length_ns = clamp(target, 100, 10 * KILO);
+ cnv_wf.period_length_ns = clamp(target, 100UL, 10UL * NSEC_PER_USEC);
/*
* Use the maximum conversion time t_CNVH from the datasheet as
diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c
index 9e4a66477d2d..92957196de59 100644
--- a/drivers/iio/adc/ad7766.c
+++ b/drivers/iio/adc/ad7766.c
@@ -285,12 +285,12 @@ static int ad7766_probe(struct spi_device *spi)
}
static const struct spi_device_id ad7766_id[] = {
- { "ad7766", ID_AD7766 },
- { "ad7766-1", ID_AD7766_1 },
- { "ad7766-2", ID_AD7766_2 },
- { "ad7767", ID_AD7766 },
- { "ad7767-1", ID_AD7766_1 },
- { "ad7767-2", ID_AD7766_2 },
+ { .name = "ad7766", .driver_data = ID_AD7766 },
+ { .name = "ad7766-1", .driver_data = ID_AD7766_1 },
+ { .name = "ad7766-2", .driver_data = ID_AD7766_2 },
+ { .name = "ad7767", .driver_data = ID_AD7766 },
+ { .name = "ad7767-1", .driver_data = ID_AD7766_1 },
+ { .name = "ad7767-2", .driver_data = ID_AD7766_2 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7766_id);
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index e16dede687d3..e9060c1bbe6f 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -25,12 +25,15 @@
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/sysfs.h>
+#include <linux/spi/offload/consumer.h>
+#include <linux/spi/offload/provider.h>
#include <linux/spi/spi.h>
#include <linux/unaligned.h>
#include <linux/units.h>
#include <linux/util_macros.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/buffer-dmaengine.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
@@ -161,6 +164,8 @@ enum ad7768_filter_regval {
enum ad7768_scan_type {
AD7768_SCAN_TYPE_NORMAL,
AD7768_SCAN_TYPE_HIGH_SPEED,
+ AD7768_SCAN_TYPE_OFFLOAD_NORMAL,
+ AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED,
};
enum {
@@ -266,6 +271,18 @@ static const struct iio_scan_type ad7768_scan_type[] = {
.storagebits = 16,
.endianness = IIO_BE,
},
+ [AD7768_SCAN_TYPE_OFFLOAD_NORMAL] = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ [AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED] = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
};
struct ad7768_chip_info {
@@ -283,6 +300,8 @@ struct ad7768_chip_info {
struct ad7768_state {
struct spi_device *spi;
+ struct spi_offload *offload;
+ struct spi_offload_trigger *offload_trigger;
struct regmap *regmap;
struct regmap *regmap24;
int vref_uv;
@@ -290,7 +309,6 @@ struct ad7768_state {
unsigned int vcm_output_sel;
struct clk *mclk;
unsigned int mclk_freq;
- unsigned int mclk_div;
unsigned int oversampling_ratio;
enum ad7768_filter_type filter_type;
unsigned int samp_freq;
@@ -306,6 +324,8 @@ struct ad7768_state {
struct gpio_desc *gpio_reset;
const char *labels[AD7768_MAX_CHANNELS];
struct gpio_chip gpiochip;
+ struct spi_transfer offload_xfer;
+ struct spi_message offload_msg;
const struct ad7768_chip_info *chip;
bool en_spi_sync;
struct mutex pga_lock; /* protect device internal state (PGA) */
@@ -464,13 +484,11 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
int readval, ret;
reinit_completion(&st->completion);
-
- ret = ad7768_set_mode(st, AD7768_ONE_SHOT);
- if (ret < 0)
- return ret;
+ enable_irq(st->spi->irq);
ret = wait_for_completion_timeout(&st->completion,
msecs_to_jiffies(1000));
+ disable_irq(st->spi->irq);
if (!ret)
return -ETIMEDOUT;
@@ -487,14 +505,6 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
if (st->oversampling_ratio == 8)
readval >>= 8;
- /*
- * Any SPI configuration of the AD7768-1 can only be
- * performed in continuous conversion mode.
- */
- ret = ad7768_set_mode(st, AD7768_CONTINUOUS);
- if (ret < 0)
- return ret;
-
return readval;
}
@@ -1138,6 +1148,10 @@ static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev,
{
struct ad7768_state *st = iio_priv(indio_dev);
+ if (st->offload)
+ return st->oversampling_ratio == 8 ?
+ AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED : AD7768_SCAN_TYPE_OFFLOAD_NORMAL;
+
return st->oversampling_ratio == 8 ?
AD7768_SCAN_TYPE_HIGH_SPEED : AD7768_SCAN_TYPE_NORMAL;
}
@@ -1252,6 +1266,10 @@ static int ad7768_setup(struct iio_dev *indio_dev)
return ret;
}
+ ret = ad7768_set_mode(st, AD7768_CONTINUOUS);
+ if (ret)
+ return ret;
+
/* For backwards compatibility, try the adi,sync-in-gpios property */
st->gpio_sync_in = devm_gpiod_get_optional(&st->spi->dev, "adi,sync-in",
GPIOD_OUT_LOW);
@@ -1356,8 +1374,94 @@ static const struct iio_buffer_setup_ops ad7768_buffer_ops = {
.predisable = &ad7768_buffer_predisable,
};
+static int ad7768_offload_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ struct spi_offload_trigger_config config = {
+ .type = SPI_OFFLOAD_TRIGGER_DATA_READY,
+ };
+ const struct iio_scan_type *scan_type;
+ unsigned int unused;
+ int ret;
+
+ scan_type = iio_get_current_scan_type(indio_dev, &indio_dev->channels[0]);
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
+
+ st->offload_xfer.len = spi_bpw_to_bytes(scan_type->realbits);
+ st->offload_xfer.bits_per_word = scan_type->realbits;
+ st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
+
+ spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1);
+ st->offload_msg.offload = st->offload;
+
+ ret = spi_optimize_message(st->spi, &st->offload_msg);
+ if (ret) {
+ dev_err(&st->spi->dev, "failed to prepare offload, err: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Write a 1 to the LSB of the INTERFACE_FORMAT register to enter
+ * continuous read mode. Subsequent data reads do not require an
+ * initial 8-bit write to query the ADC_DATA register.
+ */
+ ret = regmap_write(st->regmap, AD7768_REG_INTERFACE_FORMAT, 0x01);
+ if (ret)
+ goto err_unoptimize_message;
+
+ ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
+ &config);
+ if (ret)
+ goto err_exit_continuous_read_mode;
+
+ return 0;
+
+err_exit_continuous_read_mode:
+ regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused);
+
+err_unoptimize_message:
+ spi_unoptimize_message(&st->offload_msg);
+
+ return ret;
+}
+
+static int ad7768_offload_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ unsigned int unused;
+
+ spi_offload_trigger_disable(st->offload, st->offload_trigger);
+ spi_unoptimize_message(&st->offload_msg);
+
+ /*
+ * To exit continuous read mode, perform a single read of the ADC_DATA
+ * reg (0x2C), which allows further configuration of the device.
+ */
+ return regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused);
+}
+
+static const struct iio_buffer_setup_ops ad7768_offload_buffer_ops = {
+ .postenable = ad7768_offload_buffer_postenable,
+ .predisable = ad7768_offload_buffer_predisable,
+};
+
+static int ad7768_set_trigger_state(struct iio_trigger *trig, bool enable)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct ad7768_state *st = iio_priv(indio_dev);
+
+ if (enable)
+ enable_irq(st->spi->irq);
+ else
+ disable_irq(st->spi->irq);
+
+ return 0;
+}
+
static const struct iio_trigger_ops ad7768_trigger_ops = {
.validate_device = iio_trigger_validate_own_device,
+ .set_trigger_state = ad7768_set_trigger_state,
};
static int ad7768_set_channel_label(struct iio_dev *indio_dev,
@@ -1590,6 +1694,36 @@ static int ad7768_parse_aaf_gain(struct device *dev, struct ad7768_state *st)
return 0;
}
+static bool ad7768_offload_trigger_match(struct spi_offload_trigger *trigger,
+ enum spi_offload_trigger_type type,
+ u64 *args, u32 nargs)
+{
+ if (type != SPI_OFFLOAD_TRIGGER_DATA_READY)
+ return false;
+
+ /* Up to 2 args are allowed, but only 1 is used */
+ if (nargs == 0 || nargs > 2 || args[0] != AD7768_TRIGGER_SOURCE_DRDY)
+ return false;
+
+ return true;
+}
+
+static int ad7768_offload_trigger_request(struct spi_offload_trigger *trigger,
+ enum spi_offload_trigger_type type,
+ u64 *args, u32 nargs)
+{
+ /* Should already be validated by match, but just in case */
+ if (nargs == 0 || nargs > 2)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct spi_offload_trigger_ops ad7768_offload_trigger_ops = {
+ .match = ad7768_offload_trigger_match,
+ .request = ad7768_offload_trigger_request,
+};
+
static const struct ad7768_chip_info ad7768_chip_info = {
.name = "ad7768-1",
.channel_spec = ad7768_channels,
@@ -1627,10 +1761,51 @@ static const struct ad7768_chip_info adaq7769_chip_info = {
.has_variable_aaf = true,
};
+static const struct spi_offload_config ad7768_spi_offload_config = {
+ .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | SPI_OFFLOAD_CAP_RX_STREAM_DMA,
+};
+
+static int ad7768_spi_offload_probe(struct iio_dev *indio_dev,
+ struct ad7768_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ struct spi_offload_trigger_info trigger_info = {
+ .fwnode = dev_fwnode(dev),
+ .ops = &ad7768_offload_trigger_ops,
+ .priv = st,
+ };
+ struct dma_chan *rx_dma;
+ int ret;
+
+ ret = devm_spi_offload_trigger_register(dev, &trigger_info);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register offload trigger\n");
+
+ st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload,
+ SPI_OFFLOAD_TRIGGER_DATA_READY);
+ if (IS_ERR(st->offload_trigger))
+ return dev_err_probe(dev, PTR_ERR(st->offload_trigger),
+ "failed to get offload trigger\n");
+
+ rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload);
+ if (IS_ERR(rx_dma))
+ return dev_err_probe(dev, PTR_ERR(rx_dma), "failed to get offload RX DMA\n");
+
+ ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma,
+ IIO_BUFFER_DIRECTION_IN);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to setup offload RX DMA\n");
+
+ indio_dev->setup_ops = &ad7768_offload_buffer_ops;
+
+ return 0;
+}
+
static int ad7768_probe(struct spi_device *spi)
{
struct ad7768_state *st;
struct iio_dev *indio_dev;
+ struct device *dev = &spi->dev;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -1696,10 +1871,8 @@ static int ad7768_probe(struct spi_device *spi)
return ret;
ret = ad7768_setup(indio_dev);
- if (ret < 0) {
- dev_err(&spi->dev, "AD7768 setup failed\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "AD7768 setup failed\n");
init_completion(&st->completion);
ret = devm_mutex_init(&spi->dev, &st->pga_lock);
@@ -1721,23 +1894,34 @@ static int ad7768_probe(struct spi_device *spi)
return ret;
ret = devm_request_irq(&spi->dev, spi->irq, &ad7768_interrupt,
- IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
+ IRQF_TRIGGER_RISING | IRQF_NO_THREAD | IRQF_NO_AUTOEN,
indio_dev->name, indio_dev);
if (ret)
return ret;
- ret = ad7768_triggered_buffer_alloc(indio_dev);
- if (ret)
- return ret;
+ st->offload = devm_spi_offload_get(dev, spi, &ad7768_spi_offload_config);
+ ret = PTR_ERR_OR_ZERO(st->offload);
+ if (ret == -ENODEV) {
+ /* If not using SPI offload, fall back to low speed usage */
+ ret = ad7768_triggered_buffer_alloc(indio_dev);
+ if (ret)
+ return ret;
+ } else if (ret) {
+ return dev_err_probe(dev, ret, "failed to get SPI offload\n");
+ } else {
+ ret = ad7768_spi_offload_probe(indio_dev, st);
+ if (ret)
+ return ret;
+ }
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad7768_id_table[] = {
- { "ad7768-1", (kernel_ulong_t)&ad7768_chip_info },
- { "adaq7767-1", (kernel_ulong_t)&adaq7767_chip_info },
- { "adaq7768-1", (kernel_ulong_t)&adaq7768_chip_info },
- { "adaq7769-1", (kernel_ulong_t)&adaq7769_chip_info },
+ { .name = "ad7768-1", .driver_data = (kernel_ulong_t)&ad7768_chip_info },
+ { .name = "adaq7767-1", .driver_data = (kernel_ulong_t)&adaq7767_chip_info },
+ { .name = "adaq7768-1", .driver_data = (kernel_ulong_t)&adaq7768_chip_info },
+ { .name = "adaq7769-1", .driver_data = (kernel_ulong_t)&adaq7769_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7768_id_table);
@@ -1764,3 +1948,4 @@ module_spi_driver(ad7768_driver);
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7768-1 ADC driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c
index 695cc79e78da..79fb38d0f400 100644
--- a/drivers/iio/adc/ad7779.c
+++ b/drivers/iio/adc/ad7779.c
@@ -16,7 +16,6 @@
#include <linux/irq.h>
#include <linux/math.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/string.h>
@@ -143,7 +142,6 @@ struct ad7779_state {
const struct ad7779_chip_info *chip_info;
struct clk *mclk;
struct iio_trigger *trig;
- struct completion completion;
unsigned int sampling_freq;
enum ad7779_filter filter_enabled;
struct iio_backend *back;
@@ -843,8 +841,7 @@ static int ad7779_setup_without_backend(struct ad7779_state *st, struct iio_dev
IRQF_NO_THREAD | IRQF_NO_AUTOEN, indio_dev->name,
st->trig);
if (ret)
- return dev_err_probe(dev, ret, "request IRQ %d failed\n",
- st->spi->irq);
+ return ret;
ret = devm_iio_trigger_register(dev, st->trig);
if (ret)
@@ -852,8 +849,6 @@ static int ad7779_setup_without_backend(struct ad7779_state *st, struct iio_dev
indio_dev->trig = iio_trigger_get(st->trig);
- init_completion(&st->completion);
-
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
&iio_pollfunc_store_time,
&ad7779_trigger_handler,
diff --git a/drivers/iio/adc/ad7780.c b/drivers/iio/adc/ad7780.c
index 24d2dcad8f4d..1cfad70320fe 100644
--- a/drivers/iio/adc/ad7780.c
+++ b/drivers/iio/adc/ad7780.c
@@ -264,16 +264,12 @@ static const struct iio_info ad7780_info = {
static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st)
{
- int ret;
-
st->powerdown_gpio = devm_gpiod_get_optional(dev,
"powerdown",
GPIOD_OUT_LOW);
- if (IS_ERR(st->powerdown_gpio)) {
- ret = PTR_ERR(st->powerdown_gpio);
- dev_err(dev, "Failed to request powerdown GPIO: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(st->powerdown_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->powerdown_gpio),
+ "Failed to request powerdown GPIO\n");
if (!st->chip_info->is_ad778x)
return 0;
@@ -282,20 +278,16 @@ static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st)
st->gain_gpio = devm_gpiod_get_optional(dev,
"adi,gain",
GPIOD_OUT_HIGH);
- if (IS_ERR(st->gain_gpio)) {
- ret = PTR_ERR(st->gain_gpio);
- dev_err(dev, "Failed to request gain GPIO: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(st->gain_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->gain_gpio),
+ "Failed to request gain GPIO\n");
st->filter_gpio = devm_gpiod_get_optional(dev,
"adi,filter",
GPIOD_OUT_HIGH);
- if (IS_ERR(st->filter_gpio)) {
- ret = PTR_ERR(st->filter_gpio);
- dev_err(dev, "Failed to request filter GPIO: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(st->filter_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->filter_gpio),
+ "Failed to request filter GPIO\n");
return 0;
}
@@ -307,11 +299,12 @@ static void ad7780_reg_disable(void *reg)
static int ad7780_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
struct ad7780_state *st;
struct iio_dev *indio_dev;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -329,36 +322,35 @@ static int ad7780_probe(struct spi_device *spi)
indio_dev->num_channels = 1;
indio_dev->info = &ad7780_info;
- ret = ad7780_init_gpios(&spi->dev, st);
+ ret = ad7780_init_gpios(dev, st);
if (ret)
return ret;
- st->reg = devm_regulator_get(&spi->dev, "avdd");
+ st->reg = devm_regulator_get(dev, "avdd");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
- if (ret) {
- dev_err(&spi->dev, "Failed to enable specified AVdd supply\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable specified AVdd supply\n");
- ret = devm_add_action_or_reset(&spi->dev, ad7780_reg_disable, st->reg);
+ ret = devm_add_action_or_reset(dev, ad7780_reg_disable, st->reg);
if (ret)
return ret;
- ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
+ ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev);
if (ret)
return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id ad7780_id[] = {
- { "ad7170", ID_AD7170 },
- { "ad7171", ID_AD7171 },
- { "ad7780", ID_AD7780 },
- { "ad7781", ID_AD7781 },
+ { .name = "ad7170", .driver_data = ID_AD7170 },
+ { .name = "ad7171", .driver_data = ID_AD7171 },
+ { .name = "ad7780", .driver_data = ID_AD7780 },
+ { .name = "ad7781", .driver_data = ID_AD7781 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7780_id);
diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c
index 041fc25e3209..c2688307bbba 100644
--- a/drivers/iio/adc/ad7791.c
+++ b/drivers/iio/adc/ad7791.c
@@ -407,23 +407,22 @@ static void ad7791_reg_disable(void *reg)
static int ad7791_probe(struct spi_device *spi)
{
- const struct ad7791_platform_data *pdata = dev_get_platdata(&spi->dev);
+ struct device *dev = &spi->dev;
+ const struct ad7791_platform_data *pdata = dev_get_platdata(dev);
struct iio_dev *indio_dev;
struct ad7791_state *st;
int ret;
- if (!spi->irq) {
- dev_err(&spi->dev, "Missing IRQ.\n");
- return -ENXIO;
- }
+ if (!spi->irq)
+ return dev_err_probe(dev, -ENXIO, "Missing IRQ.\n");
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = devm_regulator_get(&spi->dev, "refin");
+ st->reg = devm_regulator_get(dev, "refin");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
@@ -431,7 +430,7 @@ static int ad7791_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_add_action_or_reset(&spi->dev, ad7791_reg_disable, st->reg);
+ ret = devm_add_action_or_reset(dev, ad7791_reg_disable, st->reg);
if (ret)
return ret;
@@ -447,7 +446,7 @@ static int ad7791_probe(struct spi_device *spi)
else
indio_dev->info = &ad7791_no_filter_info;
- ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
+ ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev);
if (ret)
return ret;
@@ -455,15 +454,15 @@ static int ad7791_probe(struct spi_device *spi)
if (ret)
return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id ad7791_spi_ids[] = {
- { "ad7787", AD7787 },
- { "ad7788", AD7788 },
- { "ad7789", AD7789 },
- { "ad7790", AD7790 },
- { "ad7791", AD7791 },
+ { .name = "ad7787", .driver_data = AD7787 },
+ { .name = "ad7788", .driver_data = AD7788 },
+ { .name = "ad7789", .driver_data = AD7789 },
+ { .name = "ad7790", .driver_data = AD7790 },
+ { .name = "ad7791", .driver_data = AD7791 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7791_spi_ids);
diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c
index ccf18ce48e34..b0f44c144f20 100644
--- a/drivers/iio/adc/ad7793.c
+++ b/drivers/iio/adc/ad7793.c
@@ -152,7 +152,6 @@ struct ad7793_chip_info {
struct ad7793_state {
const struct ad7793_chip_info *chip_info;
- u16 int_vref_mv;
u16 mode;
u16 conf;
u32 scale_avail[8][2];
@@ -269,7 +268,12 @@ static int ad7793_setup(struct iio_dev *indio_dev,
ret = ad_sd_reset(&st->sd);
if (ret < 0)
goto out;
- usleep_range(500, 2000); /* Wait for at least 500us */
+
+ /*
+ * Per AD7792/AD7793 datasheet (Rev. B, page 25, RESET section),
+ * allow 500 us after a reset before accessing on-chip registers.
+ */
+ fsleep(500);
/* write/read test for device presence */
ret = ad_sd_read_reg(&st->sd, AD7793_REG_ID, 1, &id);
@@ -279,8 +283,8 @@ static int ad7793_setup(struct iio_dev *indio_dev,
id &= AD7793_ID_MASK;
if (id != st->chip_info->id) {
- ret = -ENODEV;
- dev_err(&st->sd.spi->dev, "device ID query failed\n");
+ ret = dev_err_probe(&st->sd.spi->dev, -ENODEV,
+ "device ID query failed\n");
goto out;
}
@@ -339,8 +343,7 @@ static int ad7793_setup(struct iio_dev *indio_dev,
return 0;
out:
- dev_err(&st->sd.spi->dev, "setup failed\n");
- return ret;
+ return dev_err_probe(&st->sd.spi->dev, ret, "setup failed\n");
}
static const u16 ad7793_sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39,
@@ -775,22 +778,19 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
static int ad7793_probe(struct spi_device *spi)
{
- const struct ad7793_platform_data *pdata = dev_get_platdata(&spi->dev);
+ struct device *dev = &spi->dev;
+ const struct ad7793_platform_data *pdata = dev_get_platdata(dev);
struct ad7793_state *st;
struct iio_dev *indio_dev;
int ret, vref_mv = 0;
- if (!pdata) {
- dev_err(&spi->dev, "no platform data?\n");
- return -ENODEV;
- }
+ if (!pdata)
+ return dev_err_probe(dev, -ENODEV, "no platform data?\n");
- if (!spi->irq) {
- dev_err(&spi->dev, "no IRQ?\n");
- return -ENODEV;
- }
+ if (!spi->irq)
+ return dev_err_probe(dev, -ENODEV, "no IRQ?\n");
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -799,13 +799,13 @@ static int ad7793_probe(struct spi_device *spi)
ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info);
if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
- ret = devm_regulator_get_enable_read_voltage(&spi->dev, "refin");
+ ret = devm_regulator_get_enable_read_voltage(dev, "refin");
if (ret < 0)
return ret;
vref_mv = ret / 1000;
} else {
- vref_mv = 1170; /* Build-in ref */
+ vref_mv = 1170; /* Built-in ref */
}
st->chip_info =
@@ -817,7 +817,7 @@ static int ad7793_probe(struct spi_device *spi)
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = st->chip_info->iio_info;
- ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
+ ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev);
if (ret)
return ret;
@@ -825,19 +825,19 @@ static int ad7793_probe(struct spi_device *spi)
if (ret)
return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id ad7793_id[] = {
- { "ad7785", ID_AD7785 },
- { "ad7792", ID_AD7792 },
- { "ad7793", ID_AD7793 },
- { "ad7794", ID_AD7794 },
- { "ad7795", ID_AD7795 },
- { "ad7796", ID_AD7796 },
- { "ad7797", ID_AD7797 },
- { "ad7798", ID_AD7798 },
- { "ad7799", ID_AD7799 },
+ { .name = "ad7785", .driver_data = ID_AD7785 },
+ { .name = "ad7792", .driver_data = ID_AD7792 },
+ { .name = "ad7793", .driver_data = ID_AD7793 },
+ { .name = "ad7794", .driver_data = ID_AD7794 },
+ { .name = "ad7795", .driver_data = ID_AD7795 },
+ { .name = "ad7796", .driver_data = ID_AD7796 },
+ { .name = "ad7797", .driver_data = ID_AD7797 },
+ { .name = "ad7798", .driver_data = ID_AD7798 },
+ { .name = "ad7799", .driver_data = ID_AD7799 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7793_id);
diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c
index 87ff95643794..62aaedbce748 100644
--- a/drivers/iio/adc/ad7887.c
+++ b/drivers/iio/adc/ad7887.c
@@ -104,7 +104,7 @@ static int ad7887_ring_postdisable(struct iio_dev *indio_dev)
{
struct ad7887_state *st = iio_priv(indio_dev);
- /* dummy read: restore default CH0 settin */
+ /* dummy read: restore default CH0 settings */
return spi_sync(st->spi, &st->msg[AD7887_CH0]);
}
@@ -328,7 +328,7 @@ static int ad7887_probe(struct spi_device *spi)
}
static const struct spi_device_id ad7887_id[] = {
- { "ad7887", ID_AD7887 },
+ { .name = "ad7887", .driver_data = ID_AD7887 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7887_id);
diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c
index 0369151c7db1..44e014da9722 100644
--- a/drivers/iio/adc/ad7923.c
+++ b/drivers/iio/adc/ad7923.c
@@ -30,7 +30,7 @@
#define AD7923_PM_MODE_AS (1) /* auto shutdown */
#define AD7923_PM_MODE_FS (2) /* full shutdown */
#define AD7923_PM_MODE_OPS (3) /* normal operation */
-#define AD7923_SEQUENCE_OFF (0) /* no sequence fonction */
+#define AD7923_SEQUENCE_OFF (0) /* no sequence function */
#define AD7923_SEQUENCE_PROTECT (2) /* no interrupt write cycle */
#define AD7923_SEQUENCE_ON (3) /* continuous sequence */
@@ -39,7 +39,7 @@
#define AD7923_CHANNEL_WRITE(channel) ((channel) << 6) /* write channel */
#define AD7923_SEQUENCE_WRITE(sequence) ((((sequence) & 1) << 3) \
+ (((sequence) & 2) << 9))
- /* write sequence fonction */
+ /* write sequence function */
/* left shift for CR : bit 11 transmit in first */
#define AD7923_SHIFT_REGISTER 4
@@ -360,13 +360,13 @@ static int ad7923_probe(struct spi_device *spi)
}
static const struct spi_device_id ad7923_id[] = {
- { "ad7904", AD7904 },
- { "ad7914", AD7914 },
- { "ad7923", AD7924 },
- { "ad7924", AD7924 },
- { "ad7908", AD7908 },
- { "ad7918", AD7918 },
- { "ad7928", AD7928 },
+ { .name = "ad7904", .driver_data = AD7904 },
+ { .name = "ad7914", .driver_data = AD7914 },
+ { .name = "ad7923", .driver_data = AD7924 },
+ { .name = "ad7924", .driver_data = AD7924 },
+ { .name = "ad7908", .driver_data = AD7908 },
+ { .name = "ad7918", .driver_data = AD7918 },
+ { .name = "ad7928", .driver_data = AD7928 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7923_id);
diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c
index 7722cf9e8214..12656d3cdcec 100644
--- a/drivers/iio/adc/ad7944.c
+++ b/drivers/iio/adc/ad7944.c
@@ -865,9 +865,9 @@ static const struct of_device_id ad7944_of_match[] = {
MODULE_DEVICE_TABLE(of, ad7944_of_match);
static const struct spi_device_id ad7944_spi_id[] = {
- { "ad7944", (kernel_ulong_t)&ad7944_chip_info },
- { "ad7985", (kernel_ulong_t)&ad7985_chip_info },
- { "ad7986", (kernel_ulong_t)&ad7986_chip_info },
+ { .name = "ad7944", .driver_data = (kernel_ulong_t)&ad7944_chip_info },
+ { .name = "ad7985", .driver_data = (kernel_ulong_t)&ad7985_chip_info },
+ { .name = "ad7986", .driver_data = (kernel_ulong_t)&ad7986_chip_info },
{ }
};
diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c
index b35d299a3977..93a57a3d59b8 100644
--- a/drivers/iio/adc/ad7949.c
+++ b/drivers/iio/adc/ad7949.c
@@ -341,8 +341,8 @@ static int ad7949_spi_probe(struct spi_device *spi)
} else if (spi_is_bpw_supported(spi, 8)) {
spi->bits_per_word = 8;
} else {
- dev_err(dev, "unable to find common BPW with spi controller\n");
- return -EINVAL;
+ return dev_err_probe(dev, -EINVAL,
+ "unable to find common BPW with spi controller\n");
}
/* Setup internal voltage reference */
@@ -357,8 +357,8 @@ static int ad7949_spi_probe(struct spi_device *spi)
ad7949_adc->refsel = AD7949_CFG_VAL_REF_INT_4096;
break;
default:
- dev_err(dev, "unsupported internal voltage reference\n");
- return -EINVAL;
+ return dev_err_probe(dev, -EINVAL,
+ "unsupported internal voltage reference\n");
}
/* Setup external voltage reference, buffered? */
@@ -382,10 +382,9 @@ static int ad7949_spi_probe(struct spi_device *spi)
if (ad7949_adc->refsel & AD7949_CFG_VAL_REF_EXTERNAL) {
ret = regulator_enable(ad7949_adc->vref);
- if (ret < 0) {
- dev_err(dev, "fail to enable regulator\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "fail to enable regulator\n");
ret = devm_add_action_or_reset(dev, ad7949_disable_reg,
ad7949_adc->vref);
@@ -396,16 +395,10 @@ static int ad7949_spi_probe(struct spi_device *spi)
mutex_init(&ad7949_adc->lock);
ret = ad7949_spi_init(ad7949_adc);
- if (ret) {
- dev_err(dev, "fail to init this device: %d\n", ret);
- return ret;
- }
-
- ret = devm_iio_device_register(dev, indio_dev);
if (ret)
- dev_err(dev, "fail to register iio device: %d\n", ret);
+ return dev_err_probe(dev, ret, "fail to init this device\n");
- return ret;
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id ad7949_spi_of_id[] = {
@@ -417,9 +410,9 @@ static const struct of_device_id ad7949_spi_of_id[] = {
MODULE_DEVICE_TABLE(of, ad7949_spi_of_id);
static const struct spi_device_id ad7949_spi_id[] = {
- { "ad7949", ID_AD7949 },
- { "ad7682", ID_AD7682 },
- { "ad7689", ID_AD7689 },
+ { .name = "ad7949", .driver_data = ID_AD7949 },
+ { .name = "ad7682", .driver_data = ID_AD7682 },
+ { .name = "ad7689", .driver_data = ID_AD7689 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7949_spi_id);
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 108bb22162ef..bb076d8f5dd5 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -18,27 +18,29 @@
* ad7998 and similar chips.
*/
-#include <linux/interrupt.h>
+#include <linux/bitops.h>
#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/sysfs.h>
+#include <linux/err.h>
#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/sysfs.h>
#include <linux/types.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/bitops.h>
+#include <linux/units.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#define AD799X_CHANNEL_SHIFT 4
+#define AD799X_MAX_CHANNELS 8
/*
* AD7991, AD7995 and AD7999 defines
@@ -133,8 +135,11 @@ struct ad799x_state {
unsigned int id;
u16 config;
- u8 *rx_buf;
unsigned int transfer_size;
+
+ int vref_uV;
+
+ IIO_DECLARE_BUFFER_WITH_TS(__be16, rx_buf, AD799X_MAX_CHANNELS);
};
static int ad799x_write_config(struct ad799x_state *st, u16 val)
@@ -217,7 +222,8 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
}
b_sent = i2c_smbus_read_i2c_block_data(st->client,
- cmd, st->transfer_size, st->rx_buf);
+ cmd, st->transfer_size,
+ (u8 *)st->rx_buf);
if (b_sent < 0)
goto out;
@@ -234,11 +240,6 @@ static int ad799x_update_scan_mode(struct iio_dev *indio_dev,
{
struct ad799x_state *st = iio_priv(indio_dev);
- kfree(st->rx_buf);
- st->rx_buf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
- if (!st->rx_buf)
- return -ENOMEM;
-
st->transfer_size = bitmap_weight(scan_mask,
iio_get_masklength(indio_dev)) * 2;
@@ -306,14 +307,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- if (st->vref)
- ret = regulator_get_voltage(st->vref);
- else
- ret = regulator_get_voltage(st->reg);
-
- if (ret < 0)
- return ret;
- *val = ret / 1000;
+ *val = st->vref_uV / (MICRO / MILLI);
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
@@ -781,8 +775,14 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
},
};
+static void ad799x_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int ad799x_probe(struct i2c_client *client)
{
+ struct device *dev = &client->dev;
const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
int extra_config = 0;
@@ -791,7 +791,7 @@ static int ad799x_probe(struct i2c_client *client)
const struct ad799x_chip_info *chip_info =
&ad799x_chip_info_tbl[id->driver_data];
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -799,6 +799,10 @@ static int ad799x_probe(struct i2c_client *client)
/* this is only used for device removal purposes */
i2c_set_clientdata(client, indio_dev);
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
st->id = id->driver_data;
if (client->irq > 0 && chip_info->irq_config.info)
st->chip_config = &chip_info->irq_config;
@@ -807,33 +811,53 @@ static int ad799x_probe(struct i2c_client *client)
/* TODO: Add pdata options for filtering and bit delay */
- st->reg = devm_regulator_get(&client->dev, "vcc");
+ st->reg = devm_regulator_get(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(dev, ad799x_reg_disable, st->reg);
+ if (ret)
+ return ret;
+
/* check if an external reference is supplied */
if (chip_info->has_vref) {
- st->vref = devm_regulator_get_optional(&client->dev, "vref");
+ st->vref = devm_regulator_get_optional(dev, "vref");
ret = PTR_ERR_OR_ZERO(st->vref);
- if (ret) {
- if (ret != -ENODEV)
- goto error_disable_reg;
+ if (ret == -ENODEV) {
st->vref = NULL;
- dev_info(&client->dev, "Using VCC reference voltage\n");
+ dev_info(dev, "Using VCC reference voltage\n");
+ } else if (ret) {
+ return ret;
}
if (st->vref) {
- dev_info(&client->dev, "Using external reference voltage\n");
+ dev_info(dev, "Using external reference voltage\n");
extra_config |= AD7991_REF_SEL;
ret = regulator_enable(st->vref);
if (ret)
- goto error_disable_reg;
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, ad799x_reg_disable, st->vref);
+ if (ret)
+ return ret;
+
+ ret = regulator_get_voltage(st->vref);
+ if (ret < 0)
+ return ret;
+ st->vref_uV = ret;
}
}
+ if (!st->vref) {
+ ret = regulator_get_voltage(st->reg);
+ if (ret < 0)
+ return ret;
+ st->vref_uV = ret;
+ }
+
st->client = client;
indio_dev->name = id->name;
@@ -845,15 +869,15 @@ static int ad799x_probe(struct i2c_client *client)
ret = ad799x_update_config(st, st->chip_config->default_config | extra_config);
if (ret)
- goto error_disable_vref;
+ return ret;
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
&ad799x_trigger_handler, NULL);
if (ret)
- goto error_disable_vref;
+ return ret;
if (client->irq > 0) {
- ret = devm_request_threaded_irq(&client->dev,
+ ret = devm_request_threaded_irq(dev,
client->irq,
NULL,
ad799x_event_handler,
@@ -862,40 +886,10 @@ static int ad799x_probe(struct i2c_client *client)
client->name,
indio_dev);
if (ret)
- goto error_cleanup_ring;
+ return ret;
}
- mutex_init(&st->lock);
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_cleanup_ring;
-
- return 0;
-
-error_cleanup_ring:
- iio_triggered_buffer_cleanup(indio_dev);
-error_disable_vref:
- if (st->vref)
- regulator_disable(st->vref);
-error_disable_reg:
- regulator_disable(st->reg);
-
- return ret;
-}
-
-static void ad799x_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct ad799x_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
-
- iio_triggered_buffer_cleanup(indio_dev);
- if (st->vref)
- regulator_disable(st->vref);
- regulator_disable(st->reg);
- kfree(st->rx_buf);
+ return devm_iio_device_register(dev, indio_dev);
}
static int ad799x_suspend(struct device *dev)
@@ -946,14 +940,14 @@ static int ad799x_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(ad799x_pm_ops, ad799x_suspend, ad799x_resume);
static const struct i2c_device_id ad799x_id[] = {
- { "ad7991", ad7991 },
- { "ad7995", ad7995 },
- { "ad7999", ad7999 },
- { "ad7992", ad7992 },
- { "ad7993", ad7993 },
- { "ad7994", ad7994 },
- { "ad7997", ad7997 },
- { "ad7998", ad7998 },
+ { .name = "ad7991", .driver_data = ad7991 },
+ { .name = "ad7995", .driver_data = ad7995 },
+ { .name = "ad7999", .driver_data = ad7999 },
+ { .name = "ad7992", .driver_data = ad7992 },
+ { .name = "ad7993", .driver_data = ad7993 },
+ { .name = "ad7994", .driver_data = ad7994 },
+ { .name = "ad7997", .driver_data = ad7997 },
+ { .name = "ad7998", .driver_data = ad7998 },
{ }
};
@@ -965,7 +959,6 @@ static struct i2c_driver ad799x_driver = {
.pm = pm_sleep_ptr(&ad799x_pm_ops),
},
.probe = ad799x_probe,
- .remove = ad799x_remove,
.id_table = ad799x_id,
};
module_i2c_driver(ad799x_driver);
diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c
index 022888545580..34b7b1256f0d 100644
--- a/drivers/iio/adc/ad9467.c
+++ b/drivers/iio/adc/ad9467.c
@@ -176,7 +176,6 @@ struct ad9467_state {
struct clk *clk;
/* used for debugfs */
struct ad9467_chan_test_mode *chan_test;
- unsigned int output_mode;
unsigned int (*scales)[2];
/*
* Times 2 because we may also invert the signal polarity and run the
@@ -925,7 +924,11 @@ static int __ad9467_update_clock(struct ad9467_state *st, long r_clk)
return ret;
guard(mutex)(&st->lock);
- return ad9467_calibrate(st);
+
+ if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION))
+ return ad9467_calibrate(st);
+
+ return 0;
}
static int ad9467_write_raw(struct iio_dev *indio_dev,
@@ -1131,12 +1134,15 @@ static ssize_t ad9467_chan_test_mode_read(struct file *file,
len = scnprintf(buf, sizeof(buf), "Running \"%s\" Test:\n\t",
ad9467_test_modes[chan->mode]);
- ret = iio_backend_debugfs_print_chan_status(st->back, chan->idx,
- buf + len,
- sizeof(buf) - len);
- if (ret < 0)
- return ret;
- len += ret;
+ if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) {
+ ret = iio_backend_debugfs_print_chan_status(st->back,
+ chan->idx,
+ buf + len,
+ sizeof(buf) - len);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ }
} else if (chan->mode == AN877_ADC_TESTMODE_OFF) {
len = scnprintf(buf, sizeof(buf), "No test Running...\n");
} else {
@@ -1175,11 +1181,13 @@ static ssize_t ad9467_chan_test_mode_write(struct file *file,
if (mode == AN877_ADC_TESTMODE_OFF) {
unsigned int out_mode;
- if (chan->mode == AN877_ADC_TESTMODE_PN9_SEQ ||
- chan->mode == AN877_ADC_TESTMODE_PN23_SEQ) {
- ret = ad9467_backend_testmode_off(st, chan->idx);
- if (ret)
- return ret;
+ if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) {
+ if (chan->mode == AN877_ADC_TESTMODE_PN9_SEQ ||
+ chan->mode == AN877_ADC_TESTMODE_PN23_SEQ) {
+ ret = ad9467_backend_testmode_off(st, chan->idx);
+ if (ret)
+ return ret;
+ }
}
ret = ad9467_testmode_set(st, chan->idx, mode);
@@ -1205,16 +1213,18 @@ static ssize_t ad9467_chan_test_mode_write(struct file *file,
return ret;
/* some patterns have a backend matching monitoring block */
- if (mode == AN877_ADC_TESTMODE_PN9_SEQ) {
- ret = ad9467_backend_testmode_on(st, chan->idx,
+ if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) {
+ if (mode == AN877_ADC_TESTMODE_PN9_SEQ) {
+ ret = ad9467_backend_testmode_on(st, chan->idx,
IIO_BACKEND_ADI_PRBS_9A);
- if (ret)
- return ret;
- } else if (mode == AN877_ADC_TESTMODE_PN23_SEQ) {
- ret = ad9467_backend_testmode_on(st, chan->idx,
+ if (ret)
+ return ret;
+ } else if (mode == AN877_ADC_TESTMODE_PN23_SEQ) {
+ ret = ad9467_backend_testmode_on(st, chan->idx,
IIO_BACKEND_ADI_PRBS_23A);
- if (ret)
- return ret;
+ if (ret)
+ return ret;
+ }
}
}
@@ -1280,8 +1290,9 @@ static void ad9467_debugfs_init(struct iio_dev *indio_dev)
if (!st->chan_test)
return;
- debugfs_create_file("calibration_table_dump", 0400, d, st,
- &ad9467_calib_table_fops);
+ if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION))
+ debugfs_create_file("calibration_table_dump", 0400, d, st,
+ &ad9467_calib_table_fops);
for (chan = 0; chan < st->info->num_channels; chan++) {
snprintf(attr_name, sizeof(attr_name), "in_voltage%u_test_mode",
@@ -1300,12 +1311,13 @@ static void ad9467_debugfs_init(struct iio_dev *indio_dev)
static int ad9467_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
struct iio_dev *indio_dev;
struct ad9467_state *st;
unsigned int id;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -1320,16 +1332,15 @@ static int ad9467_probe(struct spi_device *spi)
if (AD9467_CAN_INVERT(st))
st->calib_map_size *= 2;
- st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk");
+ st->clk = devm_clk_get_enabled(dev, "adc-clk");
if (IS_ERR(st->clk))
return PTR_ERR(st->clk);
- st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
- GPIOD_OUT_LOW);
+ st->pwrdown_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_LOW);
if (IS_ERR(st->pwrdown_gpio))
return PTR_ERR(st->pwrdown_gpio);
- ret = ad9467_reset(&spi->dev);
+ ret = ad9467_reset(dev);
if (ret)
return ret;
@@ -1338,11 +1349,10 @@ static int ad9467_probe(struct spi_device *spi)
return ret;
id = ad9467_spi_read(st, AN877_ADC_REG_CHIP_ID);
- if (id != st->info->id) {
- dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n",
- id, st->info->id);
- return -ENODEV;
- }
+ if (id != st->info->id)
+ return dev_err_probe(dev, -ENODEV,
+ "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n",
+ id, st->info->id);
if (st->info->num_scales > 1)
indio_dev->info = &ad9467_info;
@@ -1356,19 +1366,25 @@ static int ad9467_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_iio_backend_request_buffer(&spi->dev, st->back, indio_dev);
- if (ret)
- return ret;
+ if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_BUFFER)) {
+ ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
+ if (ret)
+ return ret;
+ }
- ret = devm_iio_backend_enable(&spi->dev, st->back);
- if (ret)
- return ret;
+ if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_ENABLE)) {
+ ret = devm_iio_backend_enable(dev, st->back);
+ if (ret)
+ return ret;
+ }
- ret = ad9467_calibrate(st);
- if (ret)
- return ret;
+ if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) {
+ ret = ad9467_calibrate(st);
+ if (ret)
+ return ret;
+ }
- ret = devm_iio_device_register(&spi->dev, indio_dev);
+ ret = devm_iio_device_register(dev, indio_dev);
if (ret)
return ret;
@@ -1390,13 +1406,13 @@ static const struct of_device_id ad9467_of_match[] = {
MODULE_DEVICE_TABLE(of, ad9467_of_match);
static const struct spi_device_id ad9467_ids[] = {
- { "ad9211", (kernel_ulong_t)&ad9211_chip_tbl },
- { "ad9265", (kernel_ulong_t)&ad9265_chip_tbl },
- { "ad9434", (kernel_ulong_t)&ad9434_chip_tbl },
- { "ad9467", (kernel_ulong_t)&ad9467_chip_tbl },
- { "ad9643", (kernel_ulong_t)&ad9643_chip_tbl },
- { "ad9649", (kernel_ulong_t)&ad9649_chip_tbl, },
- { "ad9652", (kernel_ulong_t)&ad9652_chip_tbl, },
+ { .name = "ad9211", .driver_data = (kernel_ulong_t)&ad9211_chip_tbl },
+ { .name = "ad9265", .driver_data = (kernel_ulong_t)&ad9265_chip_tbl },
+ { .name = "ad9434", .driver_data = (kernel_ulong_t)&ad9434_chip_tbl },
+ { .name = "ad9467", .driver_data = (kernel_ulong_t)&ad9467_chip_tbl },
+ { .name = "ad9643", .driver_data = (kernel_ulong_t)&ad9643_chip_tbl },
+ { .name = "ad9649", .driver_data = (kernel_ulong_t)&ad9649_chip_tbl },
+ { .name = "ad9652", .driver_data = (kernel_ulong_t)&ad9652_chip_tbl },
{ }
};
MODULE_DEVICE_TABLE(spi, ad9467_ids);
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 7852884703b0..1b410291da53 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -51,8 +51,10 @@
*/
void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, u8 comm)
{
- /* Some variants use the lower two bits of the communications register
- * to select the channel */
+ /*
+ * Some variants use the lower two bits of the communications register
+ * to select the channel.
+ */
sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK;
}
EXPORT_SYMBOL_NS_GPL(ad_sd_set_comm, "IIO_AD_SIGMA_DELTA");
@@ -260,11 +262,25 @@ static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta
/*
* Read R̅D̅Y̅ pin (if possible) or status register to check if there is an
- * old event.
+ * old event. For devices with neither an RDY GPIO nor registers,
+ * ad_sd_read_reg() transmits no address byte and clocks raw MISO bytes,
+ * which is indistinguishable from reading conversion data and would
+ * partially consume a pending result. Skip the check for such devices.
+ *
+ * This is safe for all current registerless devices: ad7191 and ad7780
+ * (with powerdown GPIO) are reset between conversions by CS deassertion,
+ * so there is no stale result to drain; ad7780 (without powerdown GPIO)
+ * and max11205 are continuously-converting and cycle ~DRDY at the output
+ * data rate regardless of whether the previous result was read, so the
+ * next falling edge fires naturally.
+ *
+ * A future registerless device that holds ~DRDY asserted until data is
+ * read would be broken by this early return and would need either
+ * num_resetclks set or a rdy-gpio.
*/
if (sigma_delta->rdy_gpiod) {
pending_event = gpiod_get_value(sigma_delta->rdy_gpiod);
- } else {
+ } else if (sigma_delta->info->has_registers) {
unsigned int status_reg;
ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_STATUS, 1, &status_reg);
@@ -272,12 +288,25 @@ static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta
return ret;
pending_event = !(status_reg & AD_SD_REG_STATUS_RDY);
+ } else {
+ return 0;
}
if (!pending_event)
return 0;
/*
+ * With num_resetclks = 0, data_read_len is 0 and the drain sequence
+ * below would compute memset(data + 2, 0xff, 0 - 1), underflowing to
+ * SIZE_MAX and corrupting the heap. There is no safe way to drain the
+ * stale result without knowing the data register size; it will be
+ * consumed by the first ad_sd_read_reg() call in
+ * ad_sigma_delta_single_conversion().
+ */
+ if (!data_read_len)
+ return 0;
+
+ /*
* In general the size of the data register is unknown. It varies from
* device to device, might be one byte longer if CONTROL.DATA_STATUS is
* set and even varies on some devices depending on which input is
@@ -439,11 +468,10 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
out:
ad_sd_disable_irq(sigma_delta);
- ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
- ad_sigma_delta_disable_one(sigma_delta, chan->address);
-
out_unlock:
sigma_delta->keep_cs_asserted = false;
+ ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
+ ad_sigma_delta_disable_one(sigma_delta, chan->address);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->controller);
out_release:
@@ -576,6 +604,9 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
return 0;
err_unlock:
+ sigma_delta->keep_cs_asserted = false;
+ ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
+ sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->controller);
spi_unoptimize_message(&sigma_delta->sample_msg);
diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c
index db085dc5e526..c6c3ea953fea 100644
--- a/drivers/iio/adc/ade9000.c
+++ b/drivers/iio/adc/ade9000.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* ADE9000 driver
*
* Copyright 2025 Analog Devices Inc.
@@ -218,9 +218,6 @@
#define ADE9000_ST1_ERROR1_BIT BIT(29)
#define ADE9000_ST1_ERROR2_BIT BIT(30)
#define ADE9000_ST1_ERROR3_BIT BIT(31)
-#define ADE9000_ST_ERROR \
- (ADE9000_ST1_ERROR0 | ADE9000_ST1_ERROR1 | \
- ADE9000_ST1_ERROR2 | ADE9000_ST1_ERROR3)
#define ADE9000_ST1_CROSSING_FIRST 6
#define ADE9000_ST1_CROSSING_DEPTH 25
@@ -283,7 +280,6 @@ enum ade9000_wfb_cfg {
#define ADE9000_PHASE_C_POS_BIT BIT(6)
#define ADE9000_MAX_PHASE_NR 3
-#define AD9000_CHANNELS_PER_PHASE 10
/*
* Calculate register address for multi-phase device.
@@ -787,7 +783,7 @@ static int ade9000_iio_push_streaming(struct iio_dev *indio_dev)
ADE9000_MIDDLE_PAGE_BIT);
if (ret) {
dev_err_ratelimited(dev, "IRQ0 WFB write fail");
- return IRQ_HANDLED;
+ return ret;
}
ade9000_configure_scan(indio_dev, ADE9000_REG_WF_BUFF);
@@ -1123,7 +1119,7 @@ static int ade9000_write_raw(struct iio_dev *indio_dev,
tmp &= ~ADE9000_PHASE_C_POS_BIT;
switch (tmp) {
- case ADE9000_REG_AWATTOS:
+ case ADE9000_REG_AWATT:
return regmap_write(st->regmap,
ADE9000_ADDR_ADJUST(ADE9000_REG_AWATTOS,
chan->channel), val);
@@ -1549,7 +1545,7 @@ static int ade9000_buffer_postdisable(struct iio_dev *indio_dev)
ret = regmap_clear_bits(st->regmap, ADE9000_REG_MASK0, interrupts);
if (ret) {
- dev_err(dev, "Post-disable update maks0 fail\n");
+ dev_err(dev, "Post-disable update mask0 fail\n");
return ret;
}
@@ -1589,10 +1585,9 @@ static int ade9000_reset(struct ade9000_state *st)
/* Only wait for completion if IRQ1 is available to signal reset done */
if (fwnode_irq_get_byname(dev_fwnode(dev), "irq1") >= 0) {
if (!wait_for_completion_timeout(&st->reset_completion,
- msecs_to_jiffies(1000))) {
- dev_err(dev, "Reset timeout after 1s\n");
- return -ETIMEDOUT;
- }
+ msecs_to_jiffies(1000)))
+ return dev_err_probe(dev, -ETIMEDOUT,
+ "Reset timeout after 1s\n");
}
/* If no IRQ available, reset is already complete after the 50ms delay above */
@@ -1706,19 +1701,19 @@ static int ade9000_probe(struct spi_device *spi)
init_completion(&st->reset_completion);
- ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev);
+ ret = devm_mutex_init(dev, &st->lock);
if (ret)
return ret;
- ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev);
+ ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev);
if (ret)
return ret;
- ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev);
+ ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev);
if (ret)
return ret;
- ret = devm_mutex_init(dev, &st->lock);
+ ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev);
if (ret)
return ret;
@@ -1773,7 +1768,7 @@ static int ade9000_probe(struct spi_device *spi)
};
static const struct spi_device_id ade9000_id[] = {
- { "ade9000", 0 },
+ { .name = "ade9000" },
{ }
};
MODULE_DEVICE_TABLE(spi, ade9000_id);
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index 5f445e0de9ea..589f03618ecf 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -13,7 +13,6 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/delay.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
@@ -54,6 +53,10 @@
#define AXI_AD485X_PACKET_FORMAT_24BIT 0x1
#define AXI_AD485X_PACKET_FORMAT_32BIT 0x2
#define AXI_AD408X_CNTRL_3_FILTER_EN_MSK BIT(0)
+#define AXI_AD408X_CNTRL_3_PACKET_FORMAT_MSK GENMASK(3, 2)
+#define AXI_AD408X_PACKET_FORMAT_20BIT 0x0
+#define AXI_AD408X_PACKET_FORMAT_16BIT 0x1
+#define AXI_AD408X_PACKET_FORMAT_14BIT 0x2
#define ADI_AXI_ADC_REG_SYNC_STATUS 0x0068
#define ADI_AXI_ADC_SYNC_STATUS_ADC_SYNC_MSK BIT(0)
@@ -437,6 +440,31 @@ static int axi_adc_ad408x_filter_type_set(struct iio_backend *back,
AXI_AD408X_CNTRL_3_FILTER_EN_MSK);
}
+static int axi_adc_ad408x_data_size_set(struct iio_backend *back,
+ unsigned int size)
+{
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+ unsigned int val;
+
+ switch (size) {
+ case 20:
+ val = AXI_AD408X_PACKET_FORMAT_20BIT;
+ break;
+ case 16:
+ val = AXI_AD408X_PACKET_FORMAT_16BIT;
+ break;
+ case 14:
+ val = AXI_AD408X_PACKET_FORMAT_14BIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(st->regmap, ADI_AXI_ADC_REG_CNTRL_3,
+ AXI_AD408X_CNTRL_3_PACKET_FORMAT_MSK,
+ FIELD_PREP(AXI_AD408X_CNTRL_3_PACKET_FORMAT_MSK, val));
+}
+
static int axi_adc_ad408x_interface_data_align(struct iio_backend *back,
u32 timeout_us)
{
@@ -621,6 +649,8 @@ static const struct iio_backend_ops adi_axi_adc_ops = {
static const struct iio_backend_info adi_axi_adc_generic = {
.name = "axi-adc",
.ops = &adi_axi_adc_ops,
+ .caps = IIO_BACKEND_CAP_CALIBRATION | IIO_BACKEND_CAP_BUFFER |
+ IIO_BACKEND_CAP_ENABLE,
};
static const struct iio_backend_ops adi_ad485x_ops = {
@@ -645,6 +675,8 @@ static const struct iio_backend_ops adi_ad485x_ops = {
static const struct iio_backend_info axi_ad485x = {
.name = "axi-ad485x",
.ops = &adi_ad485x_ops,
+ .caps = IIO_BACKEND_CAP_CALIBRATION | IIO_BACKEND_CAP_BUFFER |
+ IIO_BACKEND_CAP_ENABLE,
};
static const struct iio_backend_ops adi_ad408x_ops = {
@@ -656,6 +688,7 @@ static const struct iio_backend_ops adi_ad408x_ops = {
.free_buffer = axi_adc_free_buffer,
.data_sample_trigger = axi_adc_data_sample_trigger,
.filter_type_set = axi_adc_ad408x_filter_type_set,
+ .data_size_set = axi_adc_ad408x_data_size_set,
.interface_data_align = axi_adc_ad408x_interface_data_align,
.num_lanes_set = axi_adc_num_lanes_set,
.debugfs_reg_access = iio_backend_debugfs_ptr(axi_adc_reg_access),
@@ -665,6 +698,7 @@ static const struct iio_backend_ops adi_ad408x_ops = {
static const struct iio_backend_info axi_ad408x = {
.name = "axi-ad408x",
.ops = &adi_ad408x_ops,
+ .caps = IIO_BACKEND_CAP_BUFFER | IIO_BACKEND_CAP_ENABLE,
};
static int adi_axi_adc_probe(struct platform_device *pdev)
diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 4be44c524b4d..6169ce28261e 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -75,6 +75,8 @@
#define ASPEED_ADC_INIT_POLLING_TIME 500
#define ASPEED_ADC_INIT_TIMEOUT 500000
+/* Battery sensing is typically on the last channel */
+#define ASPEED_ADC_BATTERY_CHANNEL 7
/*
* When the sampling rate is too high, the ADC may not have enough charging
* time, resulting in a low voltage value. Thus, the default uses a slow
@@ -121,6 +123,31 @@ struct aspeed_adc_data {
struct adc_gain battery_mode_gain;
};
+/*
+ * Enable multiple consecutive channels starting from channel 0.
+ * This creates a bitmask for channels 0 to (num_channels - 1).
+ * For example: num_channels=3 creates mask 0x0007 (channels 0,1,2)
+ */
+static inline u32 aspeed_adc_channels_mask(unsigned int num_channels)
+{
+ if (num_channels > 16)
+ return GENMASK(15, 0);
+
+ return BIT(num_channels) - 1;
+}
+
+static inline unsigned int aspeed_adc_get_active_channels(const struct aspeed_adc_data *data)
+{
+ /*
+ * For controllers with battery sensing capability, the last channel
+ * is reserved for battery sensing and should not be included in
+ * normal channel operations.
+ */
+ if (data->model_data->bat_sense_sup)
+ return data->model_data->num_channels - 1;
+ return data->model_data->num_channels;
+}
+
#define ASPEED_CHAN(_idx, _data_reg_addr) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
@@ -236,10 +263,10 @@ static int aspeed_adc_compensation(struct iio_dev *indio_dev)
ASPEED_ADC_CTRL_CHANNEL_ENABLE(0),
data->base + ASPEED_REG_ENGINE_CONTROL);
/*
- * After enable compensating sensing mode need to wait some time for ADC stable
- * Experiment result is 1ms.
+ * After enable compensating sensing mode need to wait some time for the
+ * ADC stablize. Experiment result is 1ms.
*/
- mdelay(1);
+ fsleep(1000);
for (index = 0; index < 16; index++) {
/*
@@ -285,31 +312,48 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- if (data->battery_sensing && chan->channel == 7) {
- adc_engine_control_reg_val =
- readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+ adc_engine_control_reg_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+ /*
+ * For battery sensing capable controllers, we need to enable
+ * the specific channel before reading. This is required because
+ * the battery channel may not be enabled by default.
+ */
+ if (data->model_data->bat_sense_sup &&
+ chan->channel == ASPEED_ADC_BATTERY_CHANNEL) {
+ u32 ctrl_reg = adc_engine_control_reg_val & ~ASPEED_ADC_CTRL_CHANNEL;
+
+ ctrl_reg |= ASPEED_ADC_CTRL_CHANNEL_ENABLE(chan->channel);
+ writel(ctrl_reg, data->base + ASPEED_REG_ENGINE_CONTROL);
+ /*
+ * After enable a new channel need to wait some time for ADC stable
+ * Experiment result is 1ms.
+ */
+ fsleep(1000);
+ }
+
+ if (data->battery_sensing && chan->channel == ASPEED_ADC_BATTERY_CHANNEL) {
writel(adc_engine_control_reg_val |
FIELD_PREP(ASPEED_ADC_CH7_MODE,
ASPEED_ADC_CH7_BAT) |
ASPEED_ADC_BAT_SENSING_ENABLE,
data->base + ASPEED_REG_ENGINE_CONTROL);
/*
- * After enable battery sensing mode need to wait some time for adc stable
+ * After enable battery sensing mode need to wait some time for ADC stable
* Experiment result is 1ms.
*/
- mdelay(1);
+ fsleep(1000);
*val = readw(data->base + chan->address);
*val = (*val * data->battery_mode_gain.mult) /
data->battery_mode_gain.div;
- /* Restore control register value */
- writel(adc_engine_control_reg_val,
- data->base + ASPEED_REG_ENGINE_CONTROL);
} else
*val = readw(data->base + chan->address);
+ /* Restore control register value */
+ writel(adc_engine_control_reg_val,
+ data->base + ASPEED_REG_ENGINE_CONTROL);
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
- if (data->battery_sensing && chan->channel == 7)
+ if (data->battery_sensing && chan->channel == ASPEED_ADC_BATTERY_CHANNEL)
*val = (data->cv * data->battery_mode_gain.mult) /
data->battery_mode_gain.div;
else
@@ -415,6 +459,7 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
}
adc_engine_control_reg_val =
readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+ adc_engine_control_reg_val &= ~ASPEED_ADC_REF_VOLTAGE;
ret = devm_regulator_get_enable_read_voltage(data->dev, "vref");
if (ret < 0 && ret != -ENODEV)
@@ -610,7 +655,9 @@ static int aspeed_adc_probe(struct platform_device *pdev)
/* Start all channels in normal mode. */
adc_engine_control_reg_val =
readl(data->base + ASPEED_REG_ENGINE_CONTROL);
- adc_engine_control_reg_val |= ASPEED_ADC_CTRL_CHANNEL;
+ FIELD_MODIFY(ASPEED_ADC_CTRL_CHANNEL, &adc_engine_control_reg_val,
+ aspeed_adc_channels_mask(aspeed_adc_get_active_channels(data)));
+
writel(adc_engine_control_reg_val,
data->base + ASPEED_REG_ENGINE_CONTROL);
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index aa4ba3f5a506..e8a5285bb6d4 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -17,7 +17,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/sched.h>
@@ -2259,7 +2258,7 @@ static int at91_adc_temp_sensor_init(struct at91_adc_state *st,
return 0;
/* Get the calibration data from NVMEM. */
- temp_calib = devm_nvmem_cell_get(dev, "temperature_calib");
+ temp_calib = nvmem_cell_get(dev, "temperature_calib");
if (IS_ERR(temp_calib)) {
ret = PTR_ERR(temp_calib);
if (ret != -ENOENT)
@@ -2268,6 +2267,7 @@ static int at91_adc_temp_sensor_init(struct at91_adc_state *st,
}
buf = nvmem_cell_read(temp_calib, &len);
+ nvmem_cell_put(temp_calib);
if (IS_ERR(buf)) {
dev_err(dev, "Failed to read calibration data!\n");
return PTR_ERR(buf);
@@ -2507,7 +2507,7 @@ static int at91_adc_suspend(struct device *dev)
at91_adc_buffer_postdisable(indio_dev);
/*
- * Do a sofware reset of the ADC before we go to suspend.
+ * Do a software reset of the ADC before we go to suspend.
* this will ensure that all pins are free from being muxed by the ADC
* and can be used by for other devices.
* Otherwise, ADC will hog them and we can't go to suspend mode.
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 920dd9ffd27a..0ac74ad92fca 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -171,7 +171,7 @@ struct at91_adc_trigger {
};
/**
- * struct at91_adc_reg_desc - Various informations relative to registers
+ * struct at91_adc_reg_desc - Various information relative to registers
* @channel_base: Base offset for the channel data registers
* @drdy_mask: Mask of the DRDY field in the relevant registers
* (Interruptions registers mostly)
@@ -231,7 +231,7 @@ struct at91_adc_state {
struct iio_trigger **trig;
bool use_external;
u32 vref_mv;
- u32 res; /* resolution used for convertions */
+ u32 res; /* resolution used for conversions */
wait_queue_head_t wq_data_avail;
const struct at91_adc_caps *caps;
@@ -304,7 +304,7 @@ static void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
}
}
-static int at91_ts_sample(struct iio_dev *idev)
+static void at91_ts_sample(struct iio_dev *idev)
{
struct at91_adc_state *st = iio_priv(idev);
unsigned int xscale, yscale, reg, z1, z2;
@@ -323,7 +323,7 @@ static int at91_ts_sample(struct iio_dev *idev)
xscale = (reg >> 16) & xyz_mask;
if (xscale == 0) {
dev_err(&idev->dev, "Error: xscale == 0!\n");
- return -1;
+ return;
}
x /= xscale;
@@ -334,7 +334,7 @@ static int at91_ts_sample(struct iio_dev *idev)
yscale = (reg >> 16) & xyz_mask;
if (yscale == 0) {
dev_err(&idev->dev, "Error: yscale == 0!\n");
- return -1;
+ return;
}
y /= yscale;
@@ -363,8 +363,6 @@ static int at91_ts_sample(struct iio_dev *idev)
} else {
dev_dbg(&idev->dev, "pressure too low: not reporting\n");
}
-
- return 0;
}
static irqreturn_t at91_adc_rl_interrupt(int irq, void *private)
@@ -483,7 +481,7 @@ static irqreturn_t at91_adc_9x5_interrupt(int irq, void *private)
static int at91_adc_channel_init(struct iio_dev *idev)
{
struct at91_adc_state *st = iio_priv(idev);
- struct iio_chan_spec *chan_array, *timestamp;
+ struct iio_chan_spec *chan_array;
int bit, idx = 0;
unsigned long rsvd_mask = 0;
@@ -521,14 +519,8 @@ static int at91_adc_channel_init(struct iio_dev *idev)
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
idx++;
}
- timestamp = chan_array + idx;
- timestamp->type = IIO_TIMESTAMP;
- timestamp->channel = -1;
- timestamp->scan_index = idx;
- timestamp->scan_type.sign = 's';
- timestamp->scan_type.realbits = 64;
- timestamp->scan_type.storagebits = 64;
+ chan_array[idx] = IIO_CHAN_SOFT_TIMESTAMP(idx);
idev->channels = chan_array;
return idev->num_channels;
@@ -996,7 +988,7 @@ static int at91_adc_probe(struct platform_device *pdev)
struct iio_dev *idev;
struct at91_adc_state *st;
u32 reg, prop;
- char *s;
+ const char *s;
idev = devm_iio_device_alloc(&pdev->dev, sizeof(struct at91_adc_state));
if (!idev)
@@ -1031,7 +1023,7 @@ static int at91_adc_probe(struct platform_device *pdev)
st->res = st->caps->high_res_bits;
if (st->caps->low_res_bits &&
- !of_property_read_string(node, "atmel,adc-use-res", (const char **)&s)
+ !of_property_read_string(node, "atmel,adc-use-res", &s)
&& !strcmp(s, "lowres"))
st->res = st->caps->low_res_bits;
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index f9a60e8b05cb..d9016fe1aca9 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -11,7 +11,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c
index 6426c9e6ccc9..cf4738b16e62 100644
--- a/drivers/iio/adc/bcm_iproc_adc.c
+++ b/drivers/iio/adc/bcm_iproc_adc.c
@@ -4,7 +4,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c
index fa04e0a5f645..a67edf0bddaa 100644
--- a/drivers/iio/adc/berlin2-adc.c
+++ b/drivers/iio/adc/berlin2-adc.c
@@ -15,7 +15,6 @@
#include <linux/iio/machine.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c
index 2c51b90b7101..d42b747325aa 100644
--- a/drivers/iio/adc/cc10001_adc.c
+++ b/drivers/iio/adc/cc10001_adc.c
@@ -262,7 +262,7 @@ static const struct iio_info cc10001_adc_info = {
static int cc10001_adc_channel_init(struct iio_dev *indio_dev,
unsigned long channel_map)
{
- struct iio_chan_spec *chan_array, *timestamp;
+ struct iio_chan_spec *chan_array;
unsigned int bit, idx = 0;
indio_dev->num_channels = bitmap_weight(&channel_map,
@@ -289,13 +289,7 @@ static int cc10001_adc_channel_init(struct iio_dev *indio_dev,
idx++;
}
- timestamp = &chan_array[idx];
- timestamp->type = IIO_TIMESTAMP;
- timestamp->channel = -1;
- timestamp->scan_index = idx;
- timestamp->scan_type.sign = 's';
- timestamp->scan_type.realbits = 64;
- timestamp->scan_type.storagebits = 64;
+ chan_array[idx] = IIO_CHAN_SOFT_TIMESTAMP(idx);
indio_dev->channels = chan_array;
diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c
index d9ee2ea116a7..223e2737c564 100644
--- a/drivers/iio/adc/cpcap-adc.c
+++ b/drivers/iio/adc/cpcap-adc.c
@@ -15,7 +15,6 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -934,6 +933,17 @@ static const struct cpcap_adc_ato mapphone_adc = {
.atox_ps_factor_out = 0,
};
+static const struct cpcap_adc_ato mot_adc = {
+ .ato_in = 0x0300,
+ .atox_in = 0,
+ .adc_ps_factor_in = 0x0200,
+ .atox_ps_factor_in = 0,
+ .ato_out = 0x0780,
+ .atox_out = 0,
+ .adc_ps_factor_out = 0x0600,
+ .atox_ps_factor_out = 0,
+};
+
static const struct of_device_id cpcap_adc_id_table[] = {
{
.compatible = "motorola,cpcap-adc",
@@ -942,6 +952,10 @@ static const struct of_device_id cpcap_adc_id_table[] = {
.compatible = "motorola,mapphone-cpcap-adc",
.data = &mapphone_adc,
},
+ {
+ .compatible = "motorola,mot-cpcap-adc",
+ .data = &mot_adc,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, cpcap_adc_id_table);
diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
index eb902a946efe..b01c6f5a73b1 100644
--- a/drivers/iio/adc/dln2-adc.c
+++ b/drivers/iio/adc/dln2-adc.c
@@ -444,16 +444,6 @@ static int dln2_update_scan_mode(struct iio_dev *indio_dev,
lval.scan_type.endianness = IIO_LE; \
}
-/* Assignment version of IIO_CHAN_SOFT_TIMESTAMP */
-#define IIO_CHAN_SOFT_TIMESTAMP_ASSIGN(lval, _si) { \
- lval.type = IIO_TIMESTAMP; \
- lval.channel = -1; \
- lval.scan_index = _si; \
- lval.scan_type.sign = 's'; \
- lval.scan_type.realbits = 64; \
- lval.scan_type.storagebits = 64; \
-}
-
static const struct iio_info dln2_adc_info = {
.read_raw = dln2_adc_read_raw,
.write_raw = dln2_adc_write_raw,
@@ -614,7 +604,7 @@ static int dln2_adc_probe(struct platform_device *pdev)
for (i = 0; i < chans; ++i)
DLN2_ADC_CHAN(dln2->iio_channels[i], i)
- IIO_CHAN_SOFT_TIMESTAMP_ASSIGN(dln2->iio_channels[i], i);
+ dln2->iio_channels[i] = IIO_CHAN_SOFT_TIMESTAMP(i);
indio_dev->name = DLN2_ADC_MOD_NAME;
indio_dev->info = &dln2_adc_info;
diff --git a/drivers/iio/adc/envelope-detector.c b/drivers/iio/adc/envelope-detector.c
index 5b16fe737659..aace7e103770 100644
--- a/drivers/iio/adc/envelope-detector.c
+++ b/drivers/iio/adc/envelope-detector.c
@@ -31,7 +31,6 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/iio/consumer.h>
#include <linux/iio/iio.h>
@@ -406,3 +405,4 @@ module_platform_driver(envelope_detector_driver);
MODULE_DESCRIPTION("Envelope detector using a DAC and a comparator");
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c
index f8c220f6a7b4..dc310ed616a1 100644
--- a/drivers/iio/adc/fsl-imx25-gcq.c
+++ b/drivers/iio/adc/fsl-imx25-gcq.c
@@ -12,7 +12,6 @@
#include <linux/interrupt.h>
#include <linux/mfd/imx25-tsadc.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -47,7 +46,7 @@ struct mx25_gcq_priv {
* of register writes, then a wait for a completion callback,
* and finally a register read, during which userspace could issue
* another read request. This lock protects a read access from
- * ocurring before another one has finished.
+ * occurring before another one has finished.
*/
struct mutex lock;
};
diff --git a/drivers/iio/adc/gehc-pmc-adc.c b/drivers/iio/adc/gehc-pmc-adc.c
index d1167818b17d..24193e941494 100644
--- a/drivers/iio/adc/gehc-pmc-adc.c
+++ b/drivers/iio/adc/gehc-pmc-adc.c
@@ -207,7 +207,7 @@ static const struct of_device_id pmc_adc_of_match[] = {
MODULE_DEVICE_TABLE(of, pmc_adc_of_match);
static const struct i2c_device_id pmc_adc_id_table[] = {
- { "pmc-adc" },
+ { .name = "pmc-adc" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pmc_adc_id_table);
diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c
index 86c10ea7ded4..9fa63de4b9ca 100644
--- a/drivers/iio/adc/hi8435.c
+++ b/drivers/iio/adc/hi8435.c
@@ -15,7 +15,6 @@
#include <linux/iio/triggered_event.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/gpio/consumer.h>
@@ -527,7 +526,7 @@ static const struct of_device_id hi8435_dt_ids[] = {
MODULE_DEVICE_TABLE(of, hi8435_dt_ids);
static const struct spi_device_id hi8435_id[] = {
- { "hi8435", 0 },
+ { .name = "hi8435" },
{ }
};
MODULE_DEVICE_TABLE(spi, hi8435_id);
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index 1db8b68a8f64..00adafa7cbd7 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -4,10 +4,11 @@
*
* Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de>
*/
+#include <linux/array_size.h>
+#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
@@ -21,6 +22,8 @@
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
+#define HX711_DATA_BITS 24
+
/* gain to pulse and scale conversion */
#define HX711_GAIN_MAX 3
#define HX711_RESET_GAIN 128
@@ -28,22 +31,20 @@
struct hx711_gain_to_scale {
int gain;
int gain_pulse;
- int scale;
int channel;
};
/*
* .scale depends on AVDD which in turn is known as soon as the regulator
- * is available
- * therefore we set .scale in hx711_probe()
+ * is available; it is stored per device in hx711_data.gain_scale[]
*
* channel A in documentation is channel 0 in source code
* channel B in documentation is channel 1 in source code
*/
-static struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = {
- { 128, 1, 0, 0 },
- { 32, 2, 0, 1 },
- { 64, 3, 0, 0 }
+static const struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = {
+ { 128, 1, 0 },
+ { 32, 2, 1 },
+ { 64, 3, 0 },
};
static int hx711_get_gain_to_pulse(int gain)
@@ -56,32 +57,48 @@ static int hx711_get_gain_to_pulse(int gain)
return 1;
}
-static int hx711_get_gain_to_scale(int gain)
+static int hx711_get_gain_to_scale(const int *gain_scale, int gain)
{
int i;
for (i = 0; i < HX711_GAIN_MAX; i++)
if (hx711_gain_to_scale[i].gain == gain)
- return hx711_gain_to_scale[i].scale;
+ return gain_scale[i];
return 0;
}
-static int hx711_get_scale_to_gain(int scale)
+static int hx711_get_scale_to_gain(const int *gain_scale, int scale)
{
int i;
for (i = 0; i < HX711_GAIN_MAX; i++)
- if (hx711_gain_to_scale[i].scale == scale)
+ if (gain_scale[i] == scale)
return hx711_gain_to_scale[i].gain;
return -EINVAL;
}
+/**
+ * struct hx711_chip_info - per-variant static configuration
+ * @name: IIO device name
+ * @channels: channel specification array
+ * @num_channels: number of entries in @channels
+ * @iio_info: IIO info ops for this variant
+ */
+struct hx711_chip_info {
+ const char *name;
+ const struct iio_chan_spec *channels __counted_by_ptr(num_channels);
+ unsigned int num_channels;
+ const struct iio_info *iio_info;
+};
+
struct hx711_data {
struct device *dev;
struct gpio_desc *gpiod_pd_sck;
struct gpio_desc *gpiod_dout;
int gain_set; /* gain set on device */
int gain_chan_a; /* gain for channel A */
+ int gain_scale[HX711_GAIN_MAX];
+ const struct hx711_chip_info *chip_info;
struct mutex lock;
/*
* triggered buffer
@@ -139,17 +156,18 @@ static int hx711_cycle(struct hx711_data *hx711_data)
return gpiod_get_value(hx711_data->gpiod_dout);
}
-static int hx711_read(struct hx711_data *hx711_data)
+static int hx711_read(struct hx711_data *hx711_data, int trailing_pulses)
{
- int i, ret;
int value = 0;
- int val = gpiod_get_value(hx711_data->gpiod_dout);
+ int val;
+ int ret;
/* we double check if it's really down */
+ val = gpiod_get_value(hx711_data->gpiod_dout);
if (val)
return -EIO;
- for (i = 0; i < 24; i++) {
+ for (int i = 0; i < HX711_DATA_BITS; i++) {
value <<= 1;
ret = hx711_cycle(hx711_data);
if (ret)
@@ -158,7 +176,7 @@ static int hx711_read(struct hx711_data *hx711_data)
value ^= 0x800000;
- for (i = 0; i < hx711_get_gain_to_pulse(hx711_data->gain_set); i++)
+ for (int i = 0; i < trailing_pulses; i++)
hx711_cycle(hx711_data);
return value;
@@ -188,8 +206,9 @@ static int hx711_wait_for_ready(struct hx711_data *hx711_data)
static int hx711_reset(struct hx711_data *hx711_data)
{
- int val = hx711_wait_for_ready(hx711_data);
+ int val;
+ val = hx711_wait_for_ready(hx711_data);
if (val) {
/*
* an examination with the oszilloscope indicated
@@ -221,7 +240,8 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
if (hx711_data->gain_set == 32) {
hx711_data->gain_set = hx711_data->gain_chan_a;
- ret = hx711_read(hx711_data);
+ ret = hx711_read(hx711_data,
+ hx711_get_gain_to_pulse(hx711_data->gain_set));
if (ret < 0)
return ret;
@@ -233,7 +253,8 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
if (hx711_data->gain_set != 32) {
hx711_data->gain_set = 32;
- ret = hx711_read(hx711_data);
+ ret = hx711_read(hx711_data,
+ hx711_get_gain_to_pulse(hx711_data->gain_set));
if (ret < 0)
return ret;
@@ -246,10 +267,26 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
return 0;
}
-static int hx711_reset_read(struct hx711_data *hx711_data, int chan)
+static int hx711_set_hx711_channel(struct hx711_data *hx711_data,
+ const struct iio_chan_spec *chan,
+ int *trailing_pulses)
{
int ret;
- int val;
+
+ ret = hx711_set_gain_for_channel(hx711_data, chan->channel);
+ if (ret < 0)
+ return ret;
+
+ *trailing_pulses = hx711_get_gain_to_pulse(hx711_data->gain_set);
+
+ return 0;
+}
+
+static int hx711_reset_read(struct hx711_data *hx711_data,
+ const struct iio_chan_spec *chan)
+{
+ int trailing_pulses;
+ int ret;
/*
* hx711_reset() must be called from here
@@ -260,13 +297,11 @@ static int hx711_reset_read(struct hx711_data *hx711_data, int chan)
return -EIO;
}
- ret = hx711_set_gain_for_channel(hx711_data, chan);
+ ret = hx711_set_hx711_channel(hx711_data, chan, &trailing_pulses);
if (ret < 0)
return ret;
- val = hx711_read(hx711_data);
-
- return val;
+ return hx711_read(hx711_data, trailing_pulses);
}
static int hx711_read_raw(struct iio_dev *indio_dev,
@@ -279,7 +314,7 @@ static int hx711_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW:
mutex_lock(&hx711_data->lock);
- *val = hx711_reset_read(hx711_data, chan->channel);
+ *val = hx711_reset_read(hx711_data, chan);
mutex_unlock(&hx711_data->lock);
@@ -290,7 +325,8 @@ static int hx711_read_raw(struct iio_dev *indio_dev,
*val = 0;
mutex_lock(&hx711_data->lock);
- *val2 = hx711_get_gain_to_scale(hx711_data->gain_set);
+ *val2 = hx711_get_gain_to_scale(hx711_data->gain_scale,
+ hx711_data->gain_set);
mutex_unlock(&hx711_data->lock);
@@ -321,7 +357,7 @@ static int hx711_write_raw(struct iio_dev *indio_dev,
mutex_lock(&hx711_data->lock);
- gain = hx711_get_scale_to_gain(val2);
+ gain = hx711_get_scale_to_gain(hx711_data->gain_scale, val2);
if (gain < 0) {
mutex_unlock(&hx711_data->lock);
return gain;
@@ -332,7 +368,8 @@ static int hx711_write_raw(struct iio_dev *indio_dev,
if (gain != 32)
hx711_data->gain_chan_a = gain;
- ret = hx711_read(hx711_data);
+ ret = hx711_read(hx711_data,
+ hx711_get_gain_to_pulse(hx711_data->gain_set));
if (ret < 0) {
mutex_unlock(&hx711_data->lock);
return ret;
@@ -367,8 +404,8 @@ static irqreturn_t hx711_trigger(int irq, void *p)
memset(&hx711_data->buffer, 0, sizeof(hx711_data->buffer));
iio_for_each_active_channel(indio_dev, i) {
- hx711_data->buffer.channel[j] = hx711_reset_read(hx711_data,
- indio_dev->channels[i].channel);
+ hx711_data->buffer.channel[j] =
+ hx711_reset_read(hx711_data, &indio_dev->channels[i]);
j++;
}
@@ -386,6 +423,7 @@ static ssize_t hx711_scale_available_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
+ struct hx711_data *hx711_data = iio_priv(dev_to_iio_dev(dev));
struct iio_dev_attr *iio_attr = to_iio_dev_attr(attr);
int channel = iio_attr->address;
int i, len = 0;
@@ -393,7 +431,7 @@ static ssize_t hx711_scale_available_show(struct device *dev,
for (i = 0; i < HX711_GAIN_MAX; i++)
if (hx711_gain_to_scale[i].channel == channel)
len += sprintf(buf + len, "0.%09d ",
- hx711_gain_to_scale[i].scale);
+ hx711_data->gain_scale[i]);
len += sprintf(buf + len, "\n");
@@ -455,8 +493,16 @@ static const struct iio_chan_spec hx711_chan_spec[] = {
IIO_CHAN_SOFT_TIMESTAMP(2),
};
+static const struct hx711_chip_info hx711_chip = {
+ .name = "hx711",
+ .channels = hx711_chan_spec,
+ .iio_info = &hx711_iio_info,
+ .num_channels = ARRAY_SIZE(hx711_chan_spec),
+};
+
static int hx711_probe(struct platform_device *pdev)
{
+ const struct hx711_chip_info *chip_info;
struct device *dev = &pdev->dev;
struct hx711_data *hx711_data;
struct iio_dev *indio_dev;
@@ -472,6 +518,12 @@ static int hx711_probe(struct platform_device *pdev)
mutex_init(&hx711_data->lock);
+ chip_info = device_get_match_data(dev);
+ if (!chip_info)
+ return dev_err_probe(dev, -ENODEV, "missing driver data\n");
+
+ hx711_data->chip_info = chip_info;
+
/*
* PD_SCK stands for power down and serial clock input of HX711
* in the driver it is an output
@@ -511,7 +563,7 @@ static int hx711_probe(struct platform_device *pdev)
ret *= 100;
for (i = 0; i < HX711_GAIN_MAX; i++)
- hx711_gain_to_scale[i].scale =
+ hx711_data->gain_scale[i] =
ret / hx711_gain_to_scale[i].gain / 1678;
hx711_data->gain_set = 128;
@@ -533,11 +585,11 @@ static int hx711_probe(struct platform_device *pdev)
hx711_data->data_ready_delay_ns =
1000000000 / hx711_data->clock_frequency;
- indio_dev->name = "hx711";
- indio_dev->info = &hx711_iio_info;
+ indio_dev->name = chip_info->name;
+ indio_dev->info = chip_info->iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = hx711_chan_spec;
- indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec);
+ indio_dev->channels = chip_info->channels;
+ indio_dev->num_channels = chip_info->num_channels;
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
@@ -554,7 +606,7 @@ static int hx711_probe(struct platform_device *pdev)
}
static const struct of_device_id of_hx711_match[] = {
- { .compatible = "avia,hx711", },
+ { .compatible = "avia,hx711", .data = &hx711_chip },
{ }
};
diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c
index 039c0387da23..e9a509dc11b8 100644
--- a/drivers/iio/adc/imx7d_adc.c
+++ b/drivers/iio/adc/imx7d_adc.c
@@ -11,7 +11,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c
index 6fc50394ad90..d7cc9774359e 100644
--- a/drivers/iio/adc/imx8qxp-adc.c
+++ b/drivers/iio/adc/imx8qxp-adc.c
@@ -19,7 +19,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c
index 787e80db5de3..797adaf371ba 100644
--- a/drivers/iio/adc/imx93_adc.c
+++ b/drivers/iio/adc/imx93_adc.c
@@ -13,7 +13,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c
index 857e1b69d6cd..c412f5ed46a1 100644
--- a/drivers/iio/adc/ina2xx-adc.c
+++ b/drivers/iio/adc/ina2xx-adc.c
@@ -33,8 +33,6 @@
#include <linux/sched/task.h>
#include <linux/util_macros.h>
-#include <linux/platform_data/ina2xx.h>
-
/* INA2XX registers definition */
#define INA2XX_CONFIG 0x00
#define INA2XX_SHUNT_VOLTAGE 0x01 /* readonly */
@@ -121,7 +119,7 @@ static const struct regmap_config ina2xx_regmap_config = {
.volatile_reg = ina2xx_is_volatile_reg,
};
-enum ina2xx_ids { ina219, ina226 };
+enum ina2xx_ids { ina219, ina226, ina236 };
struct ina2xx_config {
const char *name;
@@ -175,6 +173,16 @@ static const struct ina2xx_config ina2xx_config[] = {
.power_lsb_factor = 25,
.chip_id = ina226,
},
+ [ina236] = {
+ .name = "ina236",
+ .config_default = INA226_CONFIG_DEFAULT,
+ .calibration_value = 2048,
+ .shunt_voltage_lsb = 2500,
+ .bus_voltage_shift = 0,
+ .bus_voltage_lsb = 1600,
+ .power_lsb_factor = 32,
+ .chip_id = ina236,
+ },
};
static int ina2xx_read_raw(struct iio_dev *indio_dev,
@@ -499,20 +507,26 @@ static int ina2xx_write_raw(struct iio_dev *indio_dev,
break;
case IIO_CHAN_INFO_INT_TIME:
- if (chip->config->chip_id == ina226) {
+ switch (chip->config->chip_id) {
+ case ina226:
+ case ina236:
if (chan->address == INA2XX_SHUNT_VOLTAGE)
ret = ina226_set_int_time_vshunt(chip, val2,
&tmp);
else
ret = ina226_set_int_time_vbus(chip, val2,
&tmp);
- } else {
+ break;
+ case ina219:
if (chan->address == INA2XX_SHUNT_VOLTAGE)
ret = ina219_set_int_time_vshunt(chip, val2,
&tmp);
else
ret = ina219_set_int_time_vbus(chip, val2,
&tmp);
+ break;
+ default:
+ ret = -EINVAL;
}
break;
@@ -727,19 +741,27 @@ static int ina2xx_conversion_ready(struct iio_dev *indio_dev)
* For now, we do an extra read of the MASK_ENABLE register (INA226)
* resp. the BUS_VOLTAGE register (INA219).
*/
- if (chip->config->chip_id == ina226) {
+ switch (chip->config->chip_id) {
+ case ina226:
+ case ina236:
ret = regmap_read(chip->regmap,
INA226_MASK_ENABLE, &alert);
+ if (ret < 0)
+ return ret;
+
alert &= INA226_CVRF;
- } else {
+ break;
+ case ina219:
ret = regmap_read(chip->regmap,
INA2XX_BUS_VOLTAGE, &alert);
+ if (ret < 0)
+ return ret;
alert &= INA219_CNVR;
+ break;
+ default:
+ return -EINVAL;
}
- if (ret < 0)
- return ret;
-
return !!alert;
}
@@ -980,16 +1002,8 @@ static int ina2xx_probe(struct i2c_client *client)
mutex_init(&chip->state_lock);
- if (of_property_read_u32(client->dev.of_node,
- "shunt-resistor", &val) < 0) {
- struct ina2xx_platform_data *pdata =
- dev_get_platdata(&client->dev);
-
- if (pdata)
- val = pdata->shunt_uohms;
- else
- val = INA2XX_RSHUNT_DEFAULT;
- }
+ if (of_property_read_u32(client->dev.of_node, "shunt-resistor", &val) < 0)
+ val = INA2XX_RSHUNT_DEFAULT;
ret = set_shunt_resistor(chip, val);
if (ret)
@@ -998,16 +1012,22 @@ static int ina2xx_probe(struct i2c_client *client)
/* Patch the current config register with default. */
val = chip->config->config_default;
- if (type == ina226) {
+ switch (type) {
+ case ina226:
+ case ina236:
ina226_set_average(chip, INA226_DEFAULT_AVG, &val);
ina226_set_int_time_vbus(chip, INA226_DEFAULT_IT, &val);
ina226_set_int_time_vshunt(chip, INA226_DEFAULT_IT, &val);
- } else {
+ break;
+ case ina219:
chip->avg = 1;
ina219_set_int_time_vbus(chip, INA219_DEFAULT_IT, &val);
ina219_set_int_time_vshunt(chip, INA219_DEFAULT_IT, &val);
ina219_set_vbus_range_denom(chip, INA219_DEFAULT_BRNG, &val);
ina219_set_vshunt_pga_gain(chip, INA219_DEFAULT_PGA, &val);
+ break;
+ default:
+ return -EINVAL;
}
ret = ina2xx_init(chip, val);
@@ -1017,14 +1037,20 @@ static int ina2xx_probe(struct i2c_client *client)
}
indio_dev->modes = INDIO_DIRECT_MODE;
- if (type == ina226) {
+ switch (type) {
+ case ina226:
+ case ina236:
indio_dev->channels = ina226_channels;
indio_dev->num_channels = ARRAY_SIZE(ina226_channels);
indio_dev->info = &ina226_info;
- } else {
+ break;
+ case ina219:
indio_dev->channels = ina219_channels;
indio_dev->num_channels = ARRAY_SIZE(ina219_channels);
indio_dev->info = &ina219_info;
+ break;
+ default:
+ return -EINVAL;
}
indio_dev->name = id ? id->name : chip->config->name;
@@ -1052,11 +1078,12 @@ static void ina2xx_remove(struct i2c_client *client)
}
static const struct i2c_device_id ina2xx_id[] = {
- { "ina219", ina219 },
- { "ina220", ina219 },
- { "ina226", ina226 },
- { "ina230", ina226 },
- { "ina231", ina226 },
+ { .name = "ina219", .driver_data = ina219 },
+ { .name = "ina220", .driver_data = ina219 },
+ { .name = "ina226", .driver_data = ina226 },
+ { .name = "ina230", .driver_data = ina226 },
+ { .name = "ina231", .driver_data = ina226 },
+ { .name = "ina236", .driver_data = ina236 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ina2xx_id);
@@ -1082,6 +1109,10 @@ static const struct of_device_id ina2xx_of_match[] = {
.compatible = "ti,ina231",
.data = (void *)ina226
},
+ {
+ .compatible = "ti,ina236",
+ .data = (void *)ina236
+ },
{ }
};
MODULE_DEVICE_TABLE(of, ina2xx_of_match);
diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c
index 1e802c8779a4..71fcdfedb041 100644
--- a/drivers/iio/adc/ingenic-adc.c
+++ b/drivers/iio/adc/ingenic-adc.c
@@ -7,6 +7,8 @@
*/
#include <dt-bindings/iio/adc/ingenic,adc.h>
+
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
@@ -15,7 +17,6 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -115,7 +116,7 @@ static void ingenic_adc_set_adcmd(struct iio_dev *iio_dev, unsigned long mask)
{
struct ingenic_adc *adc = iio_priv(iio_dev);
- mutex_lock(&adc->lock);
+ guard(mutex)(&adc->lock);
/* Init ADCMD */
readl(adc->base + JZ_ADC_REG_ADCMD);
@@ -162,8 +163,6 @@ static void ingenic_adc_set_adcmd(struct iio_dev *iio_dev, unsigned long mask)
/* We're done */
writel(0, adc->base + JZ_ADC_REG_ADCMD);
-
- mutex_unlock(&adc->lock);
}
static void ingenic_adc_set_config(struct ingenic_adc *adc,
@@ -172,18 +171,15 @@ static void ingenic_adc_set_config(struct ingenic_adc *adc,
{
uint32_t cfg;
- mutex_lock(&adc->lock);
+ guard(mutex)(&adc->lock);
cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask;
cfg |= val;
writel(cfg, adc->base + JZ_ADC_REG_CFG);
-
- mutex_unlock(&adc->lock);
}
-static void ingenic_adc_enable_unlocked(struct ingenic_adc *adc,
- int engine,
- bool enabled)
+static void __ingenic_adc_enable(struct ingenic_adc *adc, int engine,
+ bool enabled)
{
u8 val;
@@ -201,9 +197,8 @@ static void ingenic_adc_enable(struct ingenic_adc *adc,
int engine,
bool enabled)
{
- mutex_lock(&adc->lock);
- ingenic_adc_enable_unlocked(adc, engine, enabled);
- mutex_unlock(&adc->lock);
+ guard(mutex)(&adc->lock);
+ __ingenic_adc_enable(adc, engine, enabled);
}
static int ingenic_adc_capture(struct ingenic_adc *adc,
@@ -218,18 +213,17 @@ static int ingenic_adc_capture(struct ingenic_adc *adc,
* probably due to the switch of VREF. We must keep the lock here to
* avoid races with the buffer enable/disable functions.
*/
- mutex_lock(&adc->lock);
+ guard(mutex)(&adc->lock);
cfg = readl(adc->base + JZ_ADC_REG_CFG);
writel(cfg & ~JZ_ADC_REG_CFG_CMD_SEL, adc->base + JZ_ADC_REG_CFG);
- ingenic_adc_enable_unlocked(adc, engine, true);
+ __ingenic_adc_enable(adc, engine, true);
ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val,
!(val & BIT(engine)), 250, 1000);
if (ret)
- ingenic_adc_enable_unlocked(adc, engine, false);
+ __ingenic_adc_enable(adc, engine, false);
writel(cfg, adc->base + JZ_ADC_REG_CFG);
- mutex_unlock(&adc->lock);
return ret;
}
@@ -628,22 +622,12 @@ static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
}
}
-static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
- struct iio_chan_spec const *chan,
- int *val)
+static int __ingenic_adc_read_chan(struct ingenic_adc *adc,
+ struct iio_chan_spec const *chan,
+ int *val)
{
int cmd, ret, engine = (chan->channel == INGENIC_ADC_BATTERY);
- struct ingenic_adc *adc = iio_priv(iio_dev);
-
- ret = clk_enable(adc->clk);
- if (ret) {
- dev_err(iio_dev->dev.parent, "Failed to enable clock: %d\n",
- ret);
- return ret;
- }
- /* We cannot sample the aux channels in parallel. */
- mutex_lock(&adc->aux_lock);
if (adc->soc_data->has_aux_md && engine == 0) {
switch (chan->channel) {
case INGENIC_ADC_AUX0:
@@ -662,7 +646,7 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
ret = ingenic_adc_capture(adc, engine);
if (ret)
- goto out;
+ return ret;
switch (chan->channel) {
case INGENIC_ADC_AUX0:
@@ -675,9 +659,26 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
break;
}
- ret = IIO_VAL_INT;
-out:
- mutex_unlock(&adc->aux_lock);
+ return IIO_VAL_INT;
+}
+
+static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ struct ingenic_adc *adc = iio_priv(iio_dev);
+ int ret;
+
+ ret = clk_enable(adc->clk);
+ if (ret) {
+ dev_err(iio_dev->dev.parent, "Failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
+ /* We cannot sample the aux channels in parallel. */
+ scoped_guard(mutex, &adc->aux_lock)
+ ret = __ingenic_adc_read_chan(adc, chan, val);
+
clk_disable(adc->clk);
return ret;
diff --git a/drivers/iio/adc/intel_dc_ti_adc.c b/drivers/iio/adc/intel_dc_ti_adc.c
index 0fe34f1c338e..698a2a3049e3 100644
--- a/drivers/iio/adc/intel_dc_ti_adc.c
+++ b/drivers/iio/adc/intel_dc_ti_adc.c
@@ -14,7 +14,6 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/mfd/intel_soc_pmic.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
@@ -290,8 +289,8 @@ static int dc_ti_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- info->vbat_zse = sign_extend32(FIELD_GET(DC_TI_VBAT_ZSE, val), 3);
- info->vbat_ge = sign_extend32(FIELD_GET(DC_TI_VBAT_GE, val), 3);
+ info->vbat_zse = FIELD_GET_SIGNED(DC_TI_VBAT_ZSE, val);
+ info->vbat_ge = FIELD_GET_SIGNED(DC_TI_VBAT_GE, val);
dev_dbg(dev, "vbat-zse %d vbat-ge %d\n", info->vbat_zse, info->vbat_ge);
diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c
index 101c1a0ce591..ff34e597944b 100644
--- a/drivers/iio/adc/intel_mrfld_adc.c
+++ b/drivers/iio/adc/intel_mrfld_adc.c
@@ -15,7 +15,6 @@
#include <linux/interrupt.h>
#include <linux/mfd/intel_soc_pmic.h>
#include <linux/mfd/intel_soc_pmic_mrfld.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
diff --git a/drivers/iio/adc/lpc18xx_adc.c b/drivers/iio/adc/lpc18xx_adc.c
index 7e5d181ff702..2cf2519f55f3 100644
--- a/drivers/iio/adc/lpc18xx_adc.c
+++ b/drivers/iio/adc/lpc18xx_adc.c
@@ -17,7 +17,6 @@
#include <linux/iio/driver.h>
#include <linux/io.h>
#include <linux/iopoll.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c
index 43a7bc8158b5..32a15d193d97 100644
--- a/drivers/iio/adc/lpc32xx_adc.c
+++ b/drivers/iio/adc/lpc32xx_adc.c
@@ -14,7 +14,6 @@
#include <linux/interrupt.h>
#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>
@@ -179,6 +178,8 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
+ init_completion(&st->completion);
+
retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0,
LPC32XXAD_NAME, st);
if (retval < 0) {
@@ -197,8 +198,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, iodev);
- init_completion(&st->completion);
-
iodev->name = LPC32XXAD_NAME;
iodev->info = &lpc32xx_adc_iio_info;
iodev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c
index 5f0d947d0615..1ad533270a39 100644
--- a/drivers/iio/adc/ltc2309.c
+++ b/drivers/iio/adc/ltc2309.c
@@ -1,13 +1,17 @@
// SPDX-License-Identifier: GPL-2.0
/*
+ * The LTC2305 is a 2-Channel, 12-Bit SAR ADC with an I2C Interface.
* The LTC2309 is an 8-Channel, 12-Bit SAR ADC with an I2C Interface.
*
* Datasheet:
+ * https://www.analog.com/media/en/technical-documentation/data-sheets/23015fb.pdf
* https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf
*
* Copyright (c) 2023, Liam Beguin <liambeguin@gmail.com>
*/
+#include <linux/array_size.h>
#include <linux/bitfield.h>
+#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/kernel.h>
@@ -32,32 +36,41 @@
* @client: I2C reference
* @lock: Lock to serialize data access
* @vref_mv: Internal voltage reference
+ * @read_delay_us: Chip-specific read delay in microseconds
*/
struct ltc2309 {
struct device *dev;
struct i2c_client *client;
struct mutex lock; /* serialize data access */
int vref_mv;
+ unsigned int read_delay_us;
};
/* Order matches expected channel address, See datasheet Table 1. */
+enum ltc2305_channels {
+ LTC2305_CH0_CH1 = 0x0,
+ LTC2305_CH1_CH0 = 0x4,
+ LTC2305_CH0 = 0x8,
+ LTC2305_CH1 = 0xc,
+};
+
enum ltc2309_channels {
- LTC2309_CH0_CH1 = 0,
- LTC2309_CH2_CH3,
- LTC2309_CH4_CH5,
- LTC2309_CH6_CH7,
- LTC2309_CH1_CH0,
- LTC2309_CH3_CH2,
- LTC2309_CH5_CH4,
- LTC2309_CH7_CH6,
- LTC2309_CH0,
- LTC2309_CH2,
- LTC2309_CH4,
- LTC2309_CH6,
- LTC2309_CH1,
- LTC2309_CH3,
- LTC2309_CH5,
- LTC2309_CH7,
+ LTC2309_CH0_CH1 = 0x0,
+ LTC2309_CH2_CH3 = 0x1,
+ LTC2309_CH4_CH5 = 0x2,
+ LTC2309_CH6_CH7 = 0x3,
+ LTC2309_CH1_CH0 = 0x4,
+ LTC2309_CH3_CH2 = 0x5,
+ LTC2309_CH5_CH4 = 0x6,
+ LTC2309_CH7_CH6 = 0x7,
+ LTC2309_CH0 = 0x8,
+ LTC2309_CH2 = 0x9,
+ LTC2309_CH4 = 0xa,
+ LTC2309_CH6 = 0xb,
+ LTC2309_CH1 = 0xc,
+ LTC2309_CH3 = 0xd,
+ LTC2309_CH5 = 0xe,
+ LTC2309_CH7 = 0xf,
};
#define LTC2309_CHAN(_chan, _addr) { \
@@ -80,6 +93,13 @@ enum ltc2309_channels {
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
+static const struct iio_chan_spec ltc2305_channels[] = {
+ LTC2309_CHAN(0, LTC2305_CH0),
+ LTC2309_CHAN(1, LTC2305_CH1),
+ LTC2309_DIFF_CHAN(0, 1, LTC2305_CH0_CH1),
+ LTC2309_DIFF_CHAN(1, 0, LTC2305_CH1_CH0),
+};
+
static const struct iio_chan_spec ltc2309_channels[] = {
LTC2309_CHAN(0, LTC2309_CH0),
LTC2309_CHAN(1, LTC2309_CH1),
@@ -99,6 +119,26 @@ static const struct iio_chan_spec ltc2309_channels[] = {
LTC2309_DIFF_CHAN(7, 6, LTC2309_CH7_CH6),
};
+struct ltc2309_chip_info {
+ const char *name;
+ unsigned int read_delay_us;
+ int num_channels;
+ const struct iio_chan_spec *channels __counted_by_ptr(num_channels);
+};
+
+static const struct ltc2309_chip_info ltc2305_chip_info = {
+ .name = "ltc2305",
+ .read_delay_us = 2,
+ .num_channels = ARRAY_SIZE(ltc2305_channels),
+ .channels = ltc2305_channels,
+};
+
+static const struct ltc2309_chip_info ltc2309_chip_info = {
+ .name = "ltc2309",
+ .num_channels = ARRAY_SIZE(ltc2309_channels),
+ .channels = ltc2309_channels,
+};
+
static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309,
unsigned long address, int *val)
{
@@ -117,6 +157,9 @@ static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309,
return ret;
}
+ if (ltc2309->read_delay_us)
+ fsleep(ltc2309->read_delay_us);
+
ret = i2c_master_recv(ltc2309->client, (char *)&buf, 2);
if (ret < 0) {
dev_err(ltc2309->dev, "i2c read failed: %pe\n", ERR_PTR(ret));
@@ -158,6 +201,7 @@ static const struct iio_info ltc2309_info = {
static int ltc2309_probe(struct i2c_client *client)
{
+ const struct ltc2309_chip_info *chip_info;
struct iio_dev *indio_dev;
struct ltc2309 *ltc2309;
int ret;
@@ -167,13 +211,16 @@ static int ltc2309_probe(struct i2c_client *client)
return -ENOMEM;
ltc2309 = iio_priv(indio_dev);
+ chip_info = i2c_get_match_data(client);
+
ltc2309->dev = &indio_dev->dev;
ltc2309->client = client;
+ ltc2309->read_delay_us = chip_info->read_delay_us;
- indio_dev->name = "ltc2309";
+ indio_dev->name = chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = ltc2309_channels;
- indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels);
+ indio_dev->channels = chip_info->channels;
+ indio_dev->num_channels = chip_info->num_channels;
indio_dev->info = &ltc2309_info;
ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref");
@@ -189,13 +236,15 @@ static int ltc2309_probe(struct i2c_client *client)
}
static const struct of_device_id ltc2309_of_match[] = {
- { .compatible = "lltc,ltc2309" },
+ { .compatible = "lltc,ltc2305", .data = &ltc2305_chip_info },
+ { .compatible = "lltc,ltc2309", .data = &ltc2309_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ltc2309_of_match);
static const struct i2c_device_id ltc2309_id[] = {
- { "ltc2309" },
+ { .name = "ltc2305", .driver_data = (kernel_ulong_t)&ltc2305_chip_info },
+ { .name = "ltc2309", .driver_data = (kernel_ulong_t)&ltc2309_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc2309_id);
diff --git a/drivers/iio/adc/ltc2378.c b/drivers/iio/adc/ltc2378.c
new file mode 100644
index 000000000000..b0ff2be1aee0
--- /dev/null
+++ b/drivers/iio/adc/ltc2378.c
@@ -0,0 +1,857 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Analog Devices LTC2378 ADC series driver
+ *
+ * Copyright (C) 2026 Analog Devices Inc.
+ * Author: Marcelo Schmitt <marcelo.schmitt@analog.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/bits.h>
+#include <linux/byteorder/generic.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/device-id/spi.h>
+#include <linux/device-id/of.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pwm.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/offload/consumer.h>
+#include <linux/spi/offload/types.h>
+#include <linux/time64.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/buffer-dmaengine.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/types.h>
+
+#define LTC2378_TDSDOBUSYL_NS 5
+#define LTC2378_TBUSYLH_NS 13
+#define LTC2378_TCNV_HIGH_NS 20
+#define LTC2378_MAX_DATA_WAIT_US 4 /* max(TBUSYLH + TCONV + TDSDOBUSYL) */
+
+#define LTC2378_CHANNEL(_sign, _real_bits, _storage_bits) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .differential = _sign, \
+ .channel = 0, \
+ .channel2 = _sign ? 1 : 0, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = 0, \
+ .scan_type = { \
+ .format = _sign ? IIO_SCAN_FORMAT_SIGNED_INT : \
+ IIO_SCAN_FORMAT_UNSIGNED_INT, \
+ .realbits = _real_bits, \
+ .storagebits = _storage_bits, \
+ .shift = _storage_bits - _real_bits, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define LTC2378_DIFF_CHANNEL(_real_bits) \
+ LTC2378_CHANNEL(1, _real_bits, (((_real_bits) > 16) ? 32 : 16))
+
+#define LTC2378_PSEUDO_DIFF_CHANNEL(_real_bits) \
+ LTC2378_CHANNEL(0, _real_bits, (((_real_bits) > 16) ? 32 : 16))
+
+#define LTC2378_OFFLOAD_CHANNEL(_sign, _real_bits, _storage_bits) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .differential = _sign, \
+ .channel = 0, \
+ .channel2 = _sign ? 1 : 0, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = 0, \
+ .scan_type = { \
+ .format = _sign ? IIO_SCAN_FORMAT_SIGNED_INT : \
+ IIO_SCAN_FORMAT_UNSIGNED_INT, \
+ .realbits = _real_bits, \
+ .storagebits = _storage_bits, \
+ .shift = 0, \
+ .endianness = IIO_CPU, \
+ }, \
+}
+
+/*
+ * Currently, the available offload hardware + DMA configuration only supports
+ * pushing 32-bit data elements to DMA IIO buffers in CPU endianness. For 16-bit
+ * precision parts, those 32-bit elements (in CPU endianness) contain 2 bytes
+ * with data and 2 bytes always zeroed out. Nevertheless, for the offload use
+ * case, the IIO buffer is configured for 32 storage bits in CPU endianness so
+ * data is correctly aligned in user space despite 2 out of the 4 bytes being
+ * zeros.
+ */
+#define LTC2378_OFFLOAD_DIFF_CHANNEL(_real_bits) \
+ LTC2378_OFFLOAD_CHANNEL(1, (_real_bits), 32)
+
+#define LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(_real_bits) \
+ LTC2378_OFFLOAD_CHANNEL(0, (_real_bits), 32)
+
+struct ltc2378_chip_info {
+ const char *name;
+ unsigned int internal_ref_uV;
+ struct u32_fract internal_div;
+ struct iio_chan_spec chan[2]; /* 1 physical chan + 1 timestamp chan */
+ struct iio_chan_spec offload_chan;
+ unsigned int max_sample_rate_Hz;
+ unsigned int tconv_ns;
+};
+
+struct ltc2378_state {
+ const struct ltc2378_chip_info *info;
+ struct gpio_desc *cnv_gpio;
+ struct spi_device *spi;
+ struct mutex lock; /* Protect data acquisition cycle */
+ int ref_uV;
+ struct spi_transfer xfer;
+ struct spi_transfer offload_xfer;
+ struct spi_offload *offload;
+ struct spi_offload_trigger *offload_trigger;
+ struct pwm_waveform cnv_wf;
+ struct spi_message offload_msg;
+ struct spi_offload_trigger_config offload_trigger_config;
+ struct pwm_device *cnv_trigger;
+ unsigned int cnv_Hz;
+ unsigned int sample_freq_range[3];
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the transfer buffers
+ * to live in their own cache lines.
+ */
+ struct {
+ union {
+ __be16 sample_buf16_be;
+ __be32 sample_buf32_be;
+ u16 sample_buf16;
+ u32 sample_buf32;
+ } data;
+ aligned_s64 timestamp;
+ } scan __aligned(IIO_DMA_MINALIGN);
+};
+
+static const struct ltc2378_chip_info ltc2338_18_chip_info = {
+ .name = "ltc2338-18",
+ .internal_ref_uV = 2048000,
+ .internal_div = { .numerator = 5, .denominator = 2 },
+ .chan = { LTC2378_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(18),
+ .max_sample_rate_Hz = 1 * HZ_PER_MHZ,
+ .tconv_ns = 527,
+};
+
+static const struct ltc2378_chip_info ltc2364_16_chip_info = {
+ .name = "ltc2364-16",
+ .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(16),
+ .max_sample_rate_Hz = 250 * HZ_PER_KHZ,
+ .tconv_ns = 3000,
+};
+
+static const struct ltc2378_chip_info ltc2364_18_chip_info = {
+ .name = "ltc2364-18",
+ .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(18),
+ .max_sample_rate_Hz = 250 * HZ_PER_KHZ,
+ .tconv_ns = 3000,
+};
+
+static const struct ltc2378_chip_info ltc2367_16_chip_info = {
+ .name = "ltc2367-16",
+ .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(16),
+ .max_sample_rate_Hz = 500 * HZ_PER_KHZ,
+ .tconv_ns = 1500,
+};
+
+static const struct ltc2378_chip_info ltc2367_18_chip_info = {
+ .name = "ltc2367-18",
+ .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(18),
+ .max_sample_rate_Hz = 500 * HZ_PER_KHZ,
+ .tconv_ns = 1500,
+};
+
+static const struct ltc2378_chip_info ltc2368_16_chip_info = {
+ .name = "ltc2368-16",
+ .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(16),
+ .max_sample_rate_Hz = 1 * HZ_PER_MHZ,
+ .tconv_ns = 527,
+};
+
+static const struct ltc2378_chip_info ltc2368_18_chip_info = {
+ .name = "ltc2368-18",
+ .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(18),
+ .max_sample_rate_Hz = 1 * HZ_PER_MHZ,
+ .tconv_ns = 527,
+};
+
+static const struct ltc2378_chip_info ltc2369_18_chip_info = {
+ .name = "ltc2369-18",
+ .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(18),
+ .max_sample_rate_Hz = 1600 * HZ_PER_KHZ,
+ .tconv_ns = 412,
+};
+
+static const struct ltc2378_chip_info ltc2370_16_chip_info = {
+ .name = "ltc2370-16",
+ .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(16),
+ .max_sample_rate_Hz = 2 * HZ_PER_MHZ,
+ .tconv_ns = 322,
+};
+
+static const struct ltc2378_chip_info ltc2376_16_chip_info = {
+ .name = "ltc2376-16",
+ .chan = { LTC2378_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(16),
+ .max_sample_rate_Hz = 250 * HZ_PER_KHZ,
+ .tconv_ns = 3000,
+};
+
+static const struct ltc2378_chip_info ltc2376_18_chip_info = {
+ .name = "ltc2376-18",
+ .chan = { LTC2378_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(18),
+ .max_sample_rate_Hz = 250 * HZ_PER_KHZ,
+ .tconv_ns = 3000,
+};
+
+static const struct ltc2378_chip_info ltc2376_20_chip_info = {
+ .name = "ltc2376-20",
+ .chan = { LTC2378_DIFF_CHANNEL(20), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(20),
+ .max_sample_rate_Hz = 250 * HZ_PER_KHZ,
+ .tconv_ns = 3000,
+};
+
+static const struct ltc2378_chip_info ltc2377_16_chip_info = {
+ .name = "ltc2377-16",
+ .chan = { LTC2378_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(16),
+ .max_sample_rate_Hz = 500 * HZ_PER_KHZ,
+ .tconv_ns = 1500,
+};
+
+static const struct ltc2378_chip_info ltc2377_18_chip_info = {
+ .name = "ltc2377-18",
+ .chan = { LTC2378_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(18),
+ .max_sample_rate_Hz = 500 * HZ_PER_KHZ,
+ .tconv_ns = 1500,
+};
+
+static const struct ltc2378_chip_info ltc2377_20_chip_info = {
+ .name = "ltc2377-20",
+ .chan = { LTC2378_DIFF_CHANNEL(20), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(20),
+ .max_sample_rate_Hz = 500 * HZ_PER_KHZ,
+ .tconv_ns = 1500,
+};
+
+static const struct ltc2378_chip_info ltc2378_16_chip_info = {
+ .name = "ltc2378-16",
+ .chan = { LTC2378_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(16),
+ .max_sample_rate_Hz = 1 * HZ_PER_MHZ,
+ .tconv_ns = 527,
+};
+
+static const struct ltc2378_chip_info ltc2378_18_chip_info = {
+ .name = "ltc2378-18",
+ .chan = { LTC2378_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(18),
+ .max_sample_rate_Hz = 1 * HZ_PER_MHZ,
+ .tconv_ns = 527,
+};
+
+static const struct ltc2378_chip_info ltc2378_20_chip_info = {
+ .name = "ltc2378-20",
+ .chan = { LTC2378_DIFF_CHANNEL(20), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(20),
+ .max_sample_rate_Hz = 1 * HZ_PER_MHZ,
+ .tconv_ns = 675,
+};
+
+static const struct ltc2378_chip_info ltc2379_18_chip_info = {
+ .name = "ltc2379-18",
+ .chan = { LTC2378_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(18),
+ .max_sample_rate_Hz = 1600 * HZ_PER_KHZ,
+ .tconv_ns = 412,
+};
+
+static const struct ltc2378_chip_info ltc2380_16_chip_info = {
+ .name = "ltc2380-16",
+ .chan = { LTC2378_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) },
+ .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(16),
+ .max_sample_rate_Hz = 2 * HZ_PER_MHZ,
+ .tconv_ns = 322,
+};
+
+static int ltc2378_convert_and_acquire(struct ltc2378_state *st)
+{
+ int ret;
+
+ /* Cause a rising edge of CNV to initiate a new ADC conversion */
+ gpiod_set_value_cansleep(st->cnv_gpio, 1);
+ fsleep(LTC2378_MAX_DATA_WAIT_US);
+ ret = spi_sync_transfer(st->spi, &st->xfer, 1);
+ gpiod_set_value_cansleep(st->cnv_gpio, 0);
+
+ return ret;
+}
+
+static irqreturn_t ltc2378_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ltc2378_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = ltc2378_convert_and_acquire(st);
+ if (ret < 0)
+ goto err_out;
+
+ iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan),
+ pf->timestamp);
+
+err_out:
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+static int ltc2378_channel_single_read(const struct iio_chan_spec *chan,
+ struct ltc2378_state *st, int *val)
+{
+ const struct iio_scan_type *scan_type = &chan->scan_type;
+ u32 sample;
+ int ret;
+
+ guard(mutex)(&st->lock);
+ ret = ltc2378_convert_and_acquire(st);
+ if (ret)
+ return ret;
+
+ if (chan->scan_type.endianness == IIO_BE) {
+ if (chan->scan_type.realbits > 16)
+ sample = be32_to_cpu(st->scan.data.sample_buf32_be);
+ else
+ sample = be16_to_cpu(st->scan.data.sample_buf16_be);
+ } else { /* IIO_CPU */
+ if (chan->scan_type.realbits > 16)
+ sample = st->scan.data.sample_buf32;
+ else
+ sample = st->scan.data.sample_buf16;
+ }
+
+ sample >>= chan->scan_type.shift;
+
+ if (scan_type->format == IIO_SCAN_FORMAT_SIGNED_INT)
+ *val = sign_extend32(sample, scan_type->realbits - 1);
+ else
+ *val = sample;
+
+ return 0;
+}
+
+static int ltc2378_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct ltc2378_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW: {
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
+
+ ret = ltc2378_channel_single_read(chan, st, val);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_SCALE: {
+ struct u32_fract fract = st->info->internal_div;
+ *val = st->ref_uV / MILLI;
+ if (fract.numerator && fract.denominator)
+ *val = mult_frac(*val, fract.numerator, fract.denominator);
+ /*
+ * For all LTC2378-like devices, the amount of bits that express
+ * voltage magnitude depend on the polarity / output code format:
+ * - straight binary: All precision/resolution bits are used.
+ * - 2's complement: One of the precision bits is used for sign.
+ */
+ if (chan->scan_type.format == IIO_SCAN_FORMAT_SIGNED_INT)
+ *val2 = chan->scan_type.realbits - 1;
+ else
+ *val2 = chan->scan_type.realbits;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = st->cnv_Hz;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ltc2378_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length, long mask)
+{
+ struct ltc2378_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = st->sample_freq_range;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_RANGE;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * SPI offload wiring schema
+ *
+ * +-------------+ +-------------+
+ * | CNV |<-----+--| GPIO |
+ * | | +--| PWM0 |
+ * | | | |
+ * | | +--| PWM1 |
+ * | | | +-------------+
+ * | | +->| TRIGGER |
+ * | | | |
+ * | ADC | | SPI |
+ * | | | controller |
+ * | | | |
+ * | SDI |<--------| SDO |
+ * | SDO |-------->| SDI |
+ * | SCLK |<--------| SCLK |
+ * +-------------+ +-------------+
+ *
+ */
+static int ltc2378_update_conversion_rate(struct ltc2378_state *st, int freq_Hz)
+{
+ struct spi_offload_trigger_config config = st->offload_trigger_config;
+ unsigned int min_read_offset, offload_period_ns;
+ struct pwm_waveform cnv_wf = { };
+ u64 target = LTC2378_TCNV_HIGH_NS;
+ unsigned int count;
+ u64 offload_offset_ns;
+ int ret;
+
+ if (freq_Hz == 0)
+ return -EINVAL;
+
+ if (!in_range(freq_Hz, 1, st->info->max_sample_rate_Hz))
+ return -ERANGE;
+
+ /* Configure CNV PWM waveform */
+ cnv_wf.period_length_ns = DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq_Hz);
+
+ /*
+ * Ensure CNV high time meets minimum requirement (20ns). The PWM
+ * hardware may round the duty cycle, so iterate until we get at least
+ * the minimum required high time (or reach a try count limit).
+ */
+ count = 100;
+ do {
+ cnv_wf.duty_length_ns = target;
+ ret = pwm_round_waveform_might_sleep(st->cnv_trigger, &cnv_wf);
+ if (ret)
+ return ret;
+ target += 10; /* Increment by PWM duty cycle period */
+ } while (count-- && cnv_wf.duty_length_ns < LTC2378_TCNV_HIGH_NS);
+
+ /* Check the minimum CNV high time is met */
+ if (cnv_wf.duty_length_ns < LTC2378_TCNV_HIGH_NS)
+ return -EDOM;
+
+ /*
+ * Configure SPI offload PWM trigger.
+ * The trigger should fire after tBUSYLH + tCONV + tDSDOBUSYL.
+ * Minimum time needed: TBUSYLH (13ns) + TCONV (part-specific) + TDSDOBUSYL (5ns)
+ *
+ * Use the same period as CNV PWM to avoid timing issues.
+ * Convert back from period to frequency for the SPI offload API.
+ */
+ offload_period_ns = cnv_wf.period_length_ns;
+ config.periodic.frequency_hz = div_u64(HZ_PER_GHZ, offload_period_ns);
+ min_read_offset = LTC2378_TBUSYLH_NS + st->info->tconv_ns + LTC2378_TDSDOBUSYL_NS;
+ offload_offset_ns = min_read_offset;
+ count = 100;
+ do {
+ config.periodic.offset_ns = offload_offset_ns;
+ ret = spi_offload_trigger_validate(st->offload_trigger, &config);
+ if (ret)
+ return ret;
+ offload_offset_ns += 10;
+ } while (count-- && config.periodic.offset_ns < min_read_offset);
+
+ /* Check the minimum CNV to SCLK delay is met */
+ if (config.periodic.offset_ns < min_read_offset)
+ return -EDOM;
+
+ /* Check the PWM periods remain the same */
+ offload_period_ns = div64_u64(HZ_PER_GHZ, config.periodic.frequency_hz);
+ if (cnv_wf.period_length_ns != offload_period_ns)
+ return -EDOM;
+
+ st->offload_trigger_config = config;
+ st->cnv_wf = cnv_wf;
+ st->cnv_Hz = DIV_ROUND_CLOSEST_ULL(HZ_PER_GHZ, cnv_wf.period_length_ns);
+
+ return 0;
+}
+
+static int ltc2378_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ltc2378_state *st = iio_priv(indio_dev);
+
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ltc2378_update_conversion_rate(st, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info ltc2378_iio_info = {
+ .read_raw = &ltc2378_read_raw,
+};
+
+static const struct iio_info ltc2378_offload_iio_info = {
+ .read_raw = &ltc2378_read_raw,
+ .read_avail = &ltc2378_read_avail,
+ .write_raw = &ltc2378_write_raw,
+};
+
+static int ltc2378_offload_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ltc2378_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = pwm_set_waveform_might_sleep(st->cnv_trigger, &st->cnv_wf, true);
+ if (ret)
+ return ret;
+
+ ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
+ &st->offload_trigger_config);
+ if (ret)
+ goto out_pwm_disable;
+
+ return 0;
+
+out_pwm_disable:
+ pwm_disable(st->cnv_trigger);
+ return ret;
+}
+
+static int ltc2378_offload_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ltc2378_state *st = iio_priv(indio_dev);
+
+ spi_offload_trigger_disable(st->offload, st->offload_trigger);
+ pwm_disable(st->cnv_trigger);
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ltc2378_offload_buffer_ops = {
+ .postenable = &ltc2378_offload_buffer_postenable,
+ .predisable = &ltc2378_offload_buffer_predisable,
+};
+
+static int ltc2378_prepare_offload_message(struct device *dev,
+ struct ltc2378_state *st)
+{
+ unsigned int resolution = st->info->offload_chan.scan_type.realbits;
+
+ st->offload_xfer.bits_per_word = resolution;
+ st->offload_xfer.len = spi_bpw_to_bytes(resolution);
+ st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
+
+ /* Initialize message with offload */
+ spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1);
+ st->offload_msg.offload = st->offload;
+
+ return devm_spi_optimize_message(dev, st->spi, &st->offload_msg);
+}
+
+static int ltc2378_spi_offload_setup(struct iio_dev *indio_dev,
+ struct ltc2378_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ struct dma_chan *rx_dma;
+
+ indio_dev->setup_ops = &ltc2378_offload_buffer_ops;
+
+ st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload,
+ SPI_OFFLOAD_TRIGGER_PERIODIC);
+ if (IS_ERR(st->offload_trigger))
+ return dev_err_probe(dev, PTR_ERR(st->offload_trigger),
+ "failed to get offload trigger\n");
+
+ st->offload_trigger_config.type = SPI_OFFLOAD_TRIGGER_PERIODIC;
+
+ rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload);
+ if (IS_ERR(rx_dma))
+ return dev_err_probe(dev, PTR_ERR(rx_dma), "failed to get offload RX DMA\n");
+
+ return devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma,
+ IIO_BUFFER_DIRECTION_IN);
+}
+
+static int ltc2378_pwm_get(struct ltc2378_state *st)
+{
+ struct device *dev = &st->spi->dev;
+
+ st->cnv_trigger = devm_pwm_get(dev, NULL);
+ if (IS_ERR(st->cnv_trigger))
+ return dev_err_probe(dev, PTR_ERR(st->cnv_trigger),
+ "failed to get cnv pwm\n");
+
+ /*
+ * Disable the PWM connected to CNV in case it was left running by
+ * something else.
+ */
+ pwm_disable(st->cnv_trigger);
+
+ return 0;
+}
+
+static const struct spi_offload_config ltc2378_offload_config = {
+ .capability_flags = SPI_OFFLOAD_CAP_TRIGGER |
+ SPI_OFFLOAD_CAP_RX_STREAM_DMA,
+};
+
+static int ltc2378_refin_setup(struct device *dev, struct ltc2378_state *st)
+{
+ int ret;
+
+ /*
+ * The internal reference buffer amplifies both the internal reference
+ * and REFIN by a factor of 2.
+ */
+ ret = devm_regulator_get_enable_read_voltage(dev, "refin");
+ if (ret == -ENODEV) { /* refin is optional */
+ st->ref_uV = st->info->internal_ref_uV * 2;
+ return 0;
+ }
+
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read refin regulator\n");
+
+ st->ref_uV = ret * 2;
+
+ return 0;
+}
+
+static int ltc2378_ref_setup(struct device *dev, struct ltc2378_state *st)
+{
+ int ret;
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "ref");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read ref regulator\n");
+
+ st->ref_uV = ret;
+
+ return 0;
+}
+
+static int ltc2378_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct ltc2378_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ st->info = spi_get_device_match_data(spi);
+ if (!st->info)
+ return -EINVAL;
+
+ if (st->info->internal_ref_uV)
+ ret = ltc2378_refin_setup(dev, st);
+ else
+ ret = ltc2378_ref_setup(dev, st);
+ if (ret)
+ return ret;
+
+ indio_dev->name = st->info->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ st->cnv_gpio = devm_gpiod_get(dev, "cnv", GPIOD_OUT_LOW);
+ if (IS_ERR(st->cnv_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->cnv_gpio),
+ "failed to get CNV GPIO");
+
+ st->offload = devm_spi_offload_get(dev, spi, &ltc2378_offload_config);
+ ret = PTR_ERR_OR_ZERO(st->offload);
+ /* Fall back to low speed usage when no SPI offload is available. */
+ if (ret == -ENODEV) {
+ indio_dev->info = &ltc2378_iio_info;
+ indio_dev->channels = st->info->chan;
+ indio_dev->num_channels = ARRAY_SIZE(st->info->chan);
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ iio_pollfunc_store_time,
+ ltc2378_trigger_handler,
+ NULL);
+ if (ret)
+ return ret;
+ } else if (ret) {
+ return dev_err_probe(dev, ret, "failed to get offload\n");
+ } else {
+ indio_dev->info = &ltc2378_offload_iio_info;
+ indio_dev->channels = &st->info->offload_chan;
+ indio_dev->num_channels = 1;
+ ret = ltc2378_spi_offload_setup(indio_dev, st);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to setup SPI offload\n");
+
+ ret = ltc2378_pwm_get(st);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get PWM\n");
+
+ st->sample_freq_range[0] = 1; /* min */
+ st->sample_freq_range[1] = 1; /* step */
+ st->sample_freq_range[2] = st->info->max_sample_rate_Hz; /* max */
+
+ /*
+ * Start with a slower sampling rate so there is some room for
+ * adjusting the sample averaging and the sampling frequency
+ * without hitting the maximum conversion rate.
+ */
+ ret = ltc2378_update_conversion_rate(st, st->info->max_sample_rate_Hz >> 4);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to set offload samp freq\n");
+
+ ret = ltc2378_prepare_offload_message(&spi->dev, st);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to optimize SPI message\n");
+
+ /*
+ * Set single-read transfer bits_per_word so the SPI subsystem
+ * rearranges data to CPU endianness, enabling us to reuse
+ * offload_chan specifications for single-shot reads.
+ */
+ st->xfer.bits_per_word = st->info->offload_chan.scan_type.realbits;
+ }
+
+ st->xfer.rx_buf = &st->scan.data;
+ st->xfer.len = spi_bpw_to_bytes(indio_dev->channels[0].scan_type.realbits);
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct of_device_id ltc2378_of_match[] = {
+ { .compatible = "adi,ltc2338-18", .data = &ltc2338_18_chip_info },
+ { .compatible = "adi,ltc2364-16", .data = &ltc2364_16_chip_info },
+ { .compatible = "adi,ltc2364-18", .data = &ltc2364_18_chip_info },
+ { .compatible = "adi,ltc2367-16", .data = &ltc2367_16_chip_info },
+ { .compatible = "adi,ltc2367-18", .data = &ltc2367_18_chip_info },
+ { .compatible = "adi,ltc2368-16", .data = &ltc2368_16_chip_info },
+ { .compatible = "adi,ltc2368-18", .data = &ltc2368_18_chip_info },
+ { .compatible = "adi,ltc2369-18", .data = &ltc2369_18_chip_info },
+ { .compatible = "adi,ltc2370-16", .data = &ltc2370_16_chip_info },
+ { .compatible = "adi,ltc2376-16", .data = &ltc2376_16_chip_info },
+ { .compatible = "adi,ltc2376-18", .data = &ltc2376_18_chip_info },
+ { .compatible = "adi,ltc2376-20", .data = &ltc2376_20_chip_info },
+ { .compatible = "adi,ltc2377-16", .data = &ltc2377_16_chip_info },
+ { .compatible = "adi,ltc2377-18", .data = &ltc2377_18_chip_info },
+ { .compatible = "adi,ltc2377-20", .data = &ltc2377_20_chip_info },
+ { .compatible = "adi,ltc2378-16", .data = &ltc2378_16_chip_info },
+ { .compatible = "adi,ltc2378-18", .data = &ltc2378_18_chip_info },
+ { .compatible = "adi,ltc2378-20", .data = &ltc2378_20_chip_info },
+ { .compatible = "adi,ltc2379-18", .data = &ltc2379_18_chip_info },
+ { .compatible = "adi,ltc2380-16", .data = &ltc2380_16_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ltc2378_of_match);
+
+static const struct spi_device_id ltc2378_spi_id[] = {
+ { .name = "ltc2338-18", .driver_data = (kernel_ulong_t)&ltc2338_18_chip_info },
+ { .name = "ltc2364-16", .driver_data = (kernel_ulong_t)&ltc2364_16_chip_info },
+ { .name = "ltc2364-18", .driver_data = (kernel_ulong_t)&ltc2364_18_chip_info },
+ { .name = "ltc2367-16", .driver_data = (kernel_ulong_t)&ltc2367_16_chip_info },
+ { .name = "ltc2367-18", .driver_data = (kernel_ulong_t)&ltc2367_18_chip_info },
+ { .name = "ltc2368-16", .driver_data = (kernel_ulong_t)&ltc2368_16_chip_info },
+ { .name = "ltc2368-18", .driver_data = (kernel_ulong_t)&ltc2368_18_chip_info },
+ { .name = "ltc2369-18", .driver_data = (kernel_ulong_t)&ltc2369_18_chip_info },
+ { .name = "ltc2370-16", .driver_data = (kernel_ulong_t)&ltc2370_16_chip_info },
+ { .name = "ltc2376-16", .driver_data = (kernel_ulong_t)&ltc2376_16_chip_info },
+ { .name = "ltc2376-18", .driver_data = (kernel_ulong_t)&ltc2376_18_chip_info },
+ { .name = "ltc2376-20", .driver_data = (kernel_ulong_t)&ltc2376_20_chip_info },
+ { .name = "ltc2377-16", .driver_data = (kernel_ulong_t)&ltc2377_16_chip_info },
+ { .name = "ltc2377-18", .driver_data = (kernel_ulong_t)&ltc2377_18_chip_info },
+ { .name = "ltc2377-20", .driver_data = (kernel_ulong_t)&ltc2377_20_chip_info },
+ { .name = "ltc2378-16", .driver_data = (kernel_ulong_t)&ltc2378_16_chip_info },
+ { .name = "ltc2378-18", .driver_data = (kernel_ulong_t)&ltc2378_18_chip_info },
+ { .name = "ltc2378-20", .driver_data = (kernel_ulong_t)&ltc2378_20_chip_info },
+ { .name = "ltc2379-18", .driver_data = (kernel_ulong_t)&ltc2379_18_chip_info },
+ { .name = "ltc2380-16", .driver_data = (kernel_ulong_t)&ltc2380_16_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ltc2378_spi_id);
+
+static struct spi_driver ltc2378_driver = {
+ .driver = {
+ .name = "ltc2378",
+ .of_match_table = ltc2378_of_match
+ },
+ .probe = ltc2378_probe,
+ .id_table = ltc2378_spi_id,
+};
+module_spi_driver(ltc2378_driver);
+
+MODULE_AUTHOR("Marcelo Schmitt <marcelo.schmitt@analog.com>");
+MODULE_DESCRIPTION("Analog Devices LTC2378 ADC series driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
+MODULE_IMPORT_NS("SPI_OFFLOAD");
diff --git a/drivers/iio/adc/ltc2471.c b/drivers/iio/adc/ltc2471.c
index a579107fd5c9..369af700969f 100644
--- a/drivers/iio/adc/ltc2471.c
+++ b/drivers/iio/adc/ltc2471.c
@@ -136,8 +136,8 @@ static int ltc2471_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id ltc2471_i2c_id[] = {
- { "ltc2471", ltc2471 },
- { "ltc2473", ltc2473 },
+ { .name = "ltc2471", .driver_data = ltc2471 },
+ { .name = "ltc2473", .driver_data = ltc2473 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc2471_i2c_id);
diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c
index 060651dd4130..8c3806e061dd 100644
--- a/drivers/iio/adc/ltc2485.c
+++ b/drivers/iio/adc/ltc2485.c
@@ -124,7 +124,7 @@ static int ltc2485_probe(struct i2c_client *client)
}
static const struct i2c_device_id ltc2485_id[] = {
- { "ltc2485" },
+ { .name = "ltc2485" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc2485_id);
diff --git a/drivers/iio/adc/ltc2496.c b/drivers/iio/adc/ltc2496.c
index f06dd0b9a858..5b5b6ab28850 100644
--- a/drivers/iio/adc/ltc2496.c
+++ b/drivers/iio/adc/ltc2496.c
@@ -14,7 +14,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include "ltc2497.h"
diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index eb9d521e86e5..c1668b5a351e 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -11,7 +11,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/unaligned.h>
@@ -142,8 +141,8 @@ static const struct ltc2497_chip_info ltc2497_info[] = {
};
static const struct i2c_device_id ltc2497_id[] = {
- { "ltc2497", (kernel_ulong_t)&ltc2497_info[TYPE_LTC2497] },
- { "ltc2499", (kernel_ulong_t)&ltc2497_info[TYPE_LTC2499] },
+ { .name = "ltc2497", .driver_data = (kernel_ulong_t)&ltc2497_info[TYPE_LTC2497] },
+ { .name = "ltc2499", .driver_data = (kernel_ulong_t)&ltc2497_info[TYPE_LTC2499] },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc2497_id);
diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c
index 7e736e77d8bb..fb6f12316724 100644
--- a/drivers/iio/adc/max1027.c
+++ b/drivers/iio/adc/max1027.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
@@ -73,12 +72,12 @@ enum max1027_id {
};
static const struct spi_device_id max1027_id[] = {
- { "max1027", max1027 },
- { "max1029", max1029 },
- { "max1031", max1031 },
- { "max1227", max1227 },
- { "max1229", max1229 },
- { "max1231", max1231 },
+ { .name = "max1027", .driver_data = max1027 },
+ { .name = "max1029", .driver_data = max1029 },
+ { .name = "max1031", .driver_data = max1031 },
+ { .name = "max1227", .driver_data = max1227 },
+ { .name = "max1229", .driver_data = max1229 },
+ { .name = "max1231", .driver_data = max1231 },
{ }
};
MODULE_DEVICE_TABLE(spi, max1027_id);
diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
index 520e37f75aac..549dea6bf95c 100644
--- a/drivers/iio/adc/max11100.c
+++ b/drivers/iio/adc/max11100.c
@@ -8,7 +8,6 @@
*/
#include <linux/delay.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
diff --git a/drivers/iio/adc/max1118.c b/drivers/iio/adc/max1118.c
index 7d7001e8e3d9..75e51ce3077e 100644
--- a/drivers/iio/adc/max1118.c
+++ b/drivers/iio/adc/max1118.c
@@ -18,7 +18,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
@@ -257,9 +256,9 @@ static int max1118_probe(struct spi_device *spi)
}
static const struct spi_device_id max1118_id[] = {
- { "max1117", max1117 },
- { "max1118", max1118 },
- { "max1119", max1119 },
+ { .name = "max1117", .driver_data = max1117 },
+ { .name = "max1118", .driver_data = max1118 },
+ { .name = "max1119", .driver_data = max1119 },
{ }
};
MODULE_DEVICE_TABLE(spi, max1118_id);
diff --git a/drivers/iio/adc/max11205.c b/drivers/iio/adc/max11205.c
index 6c803df220b6..63b6561dcf47 100644
--- a/drivers/iio/adc/max11205.c
+++ b/drivers/iio/adc/max11205.c
@@ -145,8 +145,8 @@ static int max11205_probe(struct spi_device *spi)
}
static const struct spi_device_id max11205_spi_ids[] = {
- { "max11205a", (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205A] },
- { "max11205b", (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205B] },
+ { .name = "max11205a", .driver_data = (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205A] },
+ { .name = "max11205b", .driver_data = (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205B] },
{ }
};
MODULE_DEVICE_TABLE(spi, max11205_spi_ids);
diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c
index 511b2f14dfaf..23ae684cf08b 100644
--- a/drivers/iio/adc/max11410.c
+++ b/drivers/iio/adc/max11410.c
@@ -804,7 +804,7 @@ static int max11410_parse_channels(struct max11410_state *st,
chan_idx++;
}
- channels[chan_idx] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(chan_idx);
+ channels[chan_idx] = IIO_CHAN_SOFT_TIMESTAMP(chan_idx);
indio_dev->num_channels = chan_idx + 1;
indio_dev->channels = channels;
@@ -912,8 +912,8 @@ static int max11410_self_calibrate(struct max11410_state *st)
static int max11410_probe(struct spi_device *spi)
{
- const char *vrefp_regs[] = { "vref0p", "vref1p", "vref2p" };
- const char *vrefn_regs[] = { "vref0n", "vref1n", "vref2n" };
+ static const char * const vrefp_regs[] = { "vref0p", "vref1p", "vref2p" };
+ static const char * const vrefn_regs[] = { "vref0n", "vref1n", "vref2n" };
struct device *dev = &spi->dev;
struct max11410_state *st;
struct iio_dev *indio_dev;
@@ -1025,7 +1025,7 @@ static const struct of_device_id max11410_spi_of_id[] = {
MODULE_DEVICE_TABLE(of, max11410_spi_of_id);
static const struct spi_device_id max11410_id[] = {
- { "max11410" },
+ { .name = "max11410" },
{ }
};
MODULE_DEVICE_TABLE(spi, max11410_id);
diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
index d62c1a011659..b3cecbf9a89e 100644
--- a/drivers/iio/adc/max1241.c
+++ b/drivers/iio/adc/max1241.c
@@ -15,10 +15,6 @@
#define MAX1241_VAL_MASK GENMASK(11, 0)
#define MAX1241_SHUTDOWN_DELAY_USEC 4
-enum max1241_id {
- max1241,
-};
-
struct max1241 {
struct spi_device *spi;
struct mutex lock;
@@ -166,7 +162,7 @@ static int max1241_probe(struct spi_device *spi)
else
dev_dbg(dev, "no shutdown pin passed, low-power mode disabled");
- indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->name = "max1241";
indio_dev->info = &max1241_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = max1241_channels;
@@ -176,9 +172,10 @@ static int max1241_probe(struct spi_device *spi)
}
static const struct spi_device_id max1241_id[] = {
- { "max1241", max1241 },
+ { .name = "max1241" },
{ }
};
+MODULE_DEVICE_TABLE(spi, max1241_id);
static const struct of_device_id max1241_dt_ids[] = {
{ .compatible = "maxim,max1241" },
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index 9dd547e62b6c..65a2d92bb112 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -23,7 +23,6 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/unaligned.h>
@@ -121,7 +120,7 @@ enum max1363_modes {
};
/**
- * struct max1363_chip_info - chip specifc information
+ * struct max1363_chip_info - chip specific information
* @info: iio core function callbacks structure
* @channels: channel specification
* @num_channels: number of channels
@@ -149,7 +148,6 @@ struct max1363_chip_info {
* @configbyte: cache of current device config byte
* @chip_info: chip model specific constants, available modes, etc.
* @current_mode: the scan mode of this chip
- * @requestedmask: a valid requested set of channels
* @lock: lock to ensure state is consistent
* @monitor_on: whether monitor mode is enabled
* @monitor_speed: parameter corresponding to device monitor speed setting
@@ -169,7 +167,6 @@ struct max1363_state {
u8 configbyte;
const struct max1363_chip_info *chip_info;
const struct max1363_mode *current_mode;
- u32 requestedmask;
struct mutex lock;
/* Using monitor modes and buffer at the same time is
@@ -637,48 +634,51 @@ static const enum max1363_modes max11644_mode_list[] = {
static const struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10);
static const struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12);
-enum { max1361,
- max1362,
- max1363,
- max1364,
- max1036,
- max1037,
- max1038,
- max1039,
- max1136,
- max1137,
- max1138,
- max1139,
- max1236,
- max1237,
- max1238,
- max1239,
- max11600,
- max11601,
- max11602,
- max11603,
- max11604,
- max11605,
- max11606,
- max11607,
- max11608,
- max11609,
- max11610,
- max11611,
- max11612,
- max11613,
- max11614,
- max11615,
- max11616,
- max11617,
- max11644,
- max11645,
- max11646,
- max11647
+enum {
+ max1361,
+ max1362,
+ max1363,
+ max1364,
+ max1036,
+ max1037,
+ max1038,
+ max1039,
+ max1136,
+ max1137,
+ max1138,
+ max1139,
+ max1236,
+ max1237,
+ max1238,
+ max1239,
+ max11600,
+ max11601,
+ max11602,
+ max11603,
+ max11604,
+ max11605,
+ max11606,
+ max11607,
+ max11608,
+ max11609,
+ max11610,
+ max11611,
+ max11612,
+ max11613,
+ max11614,
+ max11615,
+ max11616,
+ max11617,
+ max11644,
+ max11645,
+ max11646,
+ max11647,
};
-static const int max1363_monitor_speeds[] = { 133000, 665000, 33300, 16600,
- 8300, 4200, 2000, 1000 };
+static const int max1363_monitor_speeds[] = {
+ 133000, 665000, 33300, 16600,
+ 8300, 4200, 2000, 1000,
+};
static ssize_t max1363_monitor_show_freq(struct device *dev,
struct device_attribute *attr,
diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c
index 90ad4cb5868d..58adeac62dde 100644
--- a/drivers/iio/adc/max14001.c
+++ b/drivers/iio/adc/max14001.c
@@ -15,7 +15,6 @@
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/device.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -363,8 +362,8 @@ static struct max14001_chip_info max14002_chip_info = {
};
static const struct spi_device_id max14001_id_table[] = {
- { "max14001", (kernel_ulong_t)&max14001_chip_info },
- { "max14002", (kernel_ulong_t)&max14002_chip_info },
+ { .name = "max14001", .driver_data = (kernel_ulong_t)&max14001_chip_info },
+ { .name = "max14002", .driver_data = (kernel_ulong_t)&max14002_chip_info },
{ }
};
diff --git a/drivers/iio/adc/max34408.c b/drivers/iio/adc/max34408.c
index 4f45fd22a90c..c96dfed6322d 100644
--- a/drivers/iio/adc/max34408.c
+++ b/drivers/iio/adc/max34408.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -256,8 +255,8 @@ static const struct of_device_id max34408_of_match[] = {
MODULE_DEVICE_TABLE(of, max34408_of_match);
static const struct i2c_device_id max34408_id[] = {
- { "max34408", (kernel_ulong_t)&max34408_model_data },
- { "max34409", (kernel_ulong_t)&max34409_model_data },
+ { .name = "max34408", .driver_data = (kernel_ulong_t)&max34408_model_data },
+ { .name = "max34409", .driver_data = (kernel_ulong_t)&max34409_model_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, max34408_id);
diff --git a/drivers/iio/adc/max77541-adc.c b/drivers/iio/adc/max77541-adc.c
index 0aa04d143ad4..6e68cad5b5ce 100644
--- a/drivers/iio/adc/max77541-adc.c
+++ b/drivers/iio/adc/max77541-adc.c
@@ -6,7 +6,6 @@
#include <linux/bitfield.h>
#include <linux/iio/iio.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/units.h>
@@ -175,7 +174,7 @@ static int max77541_adc_probe(struct platform_device *pdev)
}
static const struct platform_device_id max77541_adc_platform_id[] = {
- { "max77541-adc" },
+ { .name = "max77541-adc" },
{ }
};
MODULE_DEVICE_TABLE(platform, max77541_adc_platform_id);
diff --git a/drivers/iio/adc/max9611.c b/drivers/iio/adc/max9611.c
index 826566d7a85e..45cea84c5d4a 100644
--- a/drivers/iio/adc/max9611.c
+++ b/drivers/iio/adc/max9611.c
@@ -22,7 +22,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
/* max9611 register addresses */
diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c
index 57cff3772ebe..18cb957e7095 100644
--- a/drivers/iio/adc/mcp320x.c
+++ b/drivers/iio/adc/mcp320x.c
@@ -41,7 +41,6 @@
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
@@ -477,19 +476,19 @@ static const struct of_device_id mcp320x_dt_ids[] = {
MODULE_DEVICE_TABLE(of, mcp320x_dt_ids);
static const struct spi_device_id mcp320x_id[] = {
- { "mcp3001", mcp3001 },
- { "mcp3002", mcp3002 },
- { "mcp3004", mcp3004 },
- { "mcp3008", mcp3008 },
- { "mcp3201", mcp3201 },
- { "mcp3202", mcp3202 },
- { "mcp3204", mcp3204 },
- { "mcp3208", mcp3208 },
- { "mcp3301", mcp3301 },
- { "mcp3550-50", mcp3550_50 },
- { "mcp3550-60", mcp3550_60 },
- { "mcp3551", mcp3551 },
- { "mcp3553", mcp3553 },
+ { .name = "mcp3001", .driver_data = mcp3001 },
+ { .name = "mcp3002", .driver_data = mcp3002 },
+ { .name = "mcp3004", .driver_data = mcp3004 },
+ { .name = "mcp3008", .driver_data = mcp3008 },
+ { .name = "mcp3201", .driver_data = mcp3201 },
+ { .name = "mcp3202", .driver_data = mcp3202 },
+ { .name = "mcp3204", .driver_data = mcp3204 },
+ { .name = "mcp3208", .driver_data = mcp3208 },
+ { .name = "mcp3301", .driver_data = mcp3301 },
+ { .name = "mcp3550-50", .driver_data = mcp3550_50 },
+ { .name = "mcp3550-60", .driver_data = mcp3550_60 },
+ { .name = "mcp3551", .driver_data = mcp3551 },
+ { .name = "mcp3553", .driver_data = mcp3553 },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp320x_id);
diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c
index 50834fdcf738..36ba00edf301 100644
--- a/drivers/iio/adc/mcp3422.c
+++ b/drivers/iio/adc/mcp3422.c
@@ -13,10 +13,11 @@
* voltage unit is nV.
*/
+#include <linux/bitfield.h>
+#include <linux/bits.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/sysfs.h>
#include <linux/unaligned.h>
@@ -24,10 +25,10 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-/* Masks */
-#define MCP3422_CHANNEL_MASK 0x60
-#define MCP3422_PGA_MASK 0x03
-#define MCP3422_SRATE_MASK 0x0C
+#define MCP3422_CHANNEL_MASK GENMASK(6, 5)
+#define MCP3422_SRATE_MASK GENMASK(3, 2)
+#define MCP3422_PGA_MASK GENMASK(1, 0)
+
#define MCP3422_SRATE_240 0x0
#define MCP3422_SRATE_60 0x1
#define MCP3422_SRATE_15 0x2
@@ -36,15 +37,7 @@
#define MCP3422_PGA_2 1
#define MCP3422_PGA_4 2
#define MCP3422_PGA_8 3
-#define MCP3422_CONT_SAMPLING 0x10
-
-#define MCP3422_CHANNEL(config) (((config) & MCP3422_CHANNEL_MASK) >> 5)
-#define MCP3422_PGA(config) ((config) & MCP3422_PGA_MASK)
-#define MCP3422_SAMPLE_RATE(config) (((config) & MCP3422_SRATE_MASK) >> 2)
-
-#define MCP3422_CHANNEL_VALUE(value) (((value) << 5) & MCP3422_CHANNEL_MASK)
-#define MCP3422_PGA_VALUE(value) ((value) & MCP3422_PGA_MASK)
-#define MCP3422_SAMPLE_RATE_VALUE(value) ((value << 2) & MCP3422_SRATE_MASK)
+#define MCP3422_CONT_SAMPLING BIT(4)
#define MCP3422_CHAN(_index) \
{ \
@@ -108,7 +101,7 @@ static int mcp3422_update_config(struct mcp3422 *adc, u8 newconfig)
static int mcp3422_read(struct mcp3422 *adc, int *value, u8 *config)
{
int ret = 0;
- u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config);
+ u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config);
u8 buf[4] = {0, 0, 0, 0};
u32 temp;
@@ -136,18 +129,18 @@ static int mcp3422_read_channel(struct mcp3422 *adc,
mutex_lock(&adc->lock);
- if (req_channel != MCP3422_CHANNEL(adc->config)) {
+ if (req_channel != FIELD_GET(MCP3422_CHANNEL_MASK, adc->config)) {
config = adc->config;
- config &= ~MCP3422_CHANNEL_MASK;
- config |= MCP3422_CHANNEL_VALUE(req_channel);
- config &= ~MCP3422_PGA_MASK;
- config |= MCP3422_PGA_VALUE(adc->pga[req_channel]);
+
+ FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel);
+ FIELD_MODIFY(MCP3422_PGA_MASK, &config, adc->pga[req_channel]);
+
ret = mcp3422_update_config(adc, config);
if (ret < 0) {
mutex_unlock(&adc->lock);
return ret;
}
- msleep(mcp3422_read_times[MCP3422_SAMPLE_RATE(adc->config)]);
+ msleep(mcp3422_read_times[FIELD_GET(MCP3422_SRATE_MASK, adc->config)]);
}
ret = mcp3422_read(adc, value, &config);
@@ -163,9 +156,8 @@ static int mcp3422_read_raw(struct iio_dev *iio,
{
struct mcp3422 *adc = iio_priv(iio);
int err;
-
- u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config);
- u8 pga = MCP3422_PGA(adc->config);
+ u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config);
+ u8 pga = FIELD_GET(MCP3422_PGA_MASK, adc->config);
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -181,7 +173,7 @@ static int mcp3422_read_raw(struct iio_dev *iio,
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_SAMP_FREQ:
- *val1 = mcp3422_sample_rates[MCP3422_SAMPLE_RATE(adc->config)];
+ *val1 = mcp3422_sample_rates[FIELD_GET(MCP3422_SRATE_MASK, adc->config)];
return IIO_VAL_INT;
default:
@@ -199,7 +191,7 @@ static int mcp3422_write_raw(struct iio_dev *iio,
u8 temp;
u8 config = adc->config;
u8 req_channel = channel->channel;
- u8 sample_rate = MCP3422_SAMPLE_RATE(config);
+ u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, config);
u8 i;
switch (mask) {
@@ -211,10 +203,8 @@ static int mcp3422_write_raw(struct iio_dev *iio,
if (val2 == mcp3422_scales[sample_rate][i]) {
adc->pga[req_channel] = i;
- config &= ~MCP3422_CHANNEL_MASK;
- config |= MCP3422_CHANNEL_VALUE(req_channel);
- config &= ~MCP3422_PGA_MASK;
- config |= MCP3422_PGA_VALUE(adc->pga[req_channel]);
+ FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel);
+ FIELD_MODIFY(MCP3422_PGA_MASK, &config, adc->pga[req_channel]);
return mcp3422_update_config(adc, config);
}
@@ -241,10 +231,8 @@ static int mcp3422_write_raw(struct iio_dev *iio,
return -EINVAL;
}
- config &= ~MCP3422_CHANNEL_MASK;
- config |= MCP3422_CHANNEL_VALUE(req_channel);
- config &= ~MCP3422_SRATE_MASK;
- config |= MCP3422_SAMPLE_RATE_VALUE(temp);
+ FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel);
+ FIELD_MODIFY(MCP3422_SRATE_MASK, &config, temp);
return mcp3422_update_config(adc, config);
@@ -283,7 +271,7 @@ static ssize_t mcp3422_show_scales(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev));
- u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config);
+ u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config);
return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n",
mcp3422_scales[sample_rate][0],
@@ -376,10 +364,10 @@ static int mcp3422_probe(struct i2c_client *client)
}
/* meaningful default configuration */
- config = (MCP3422_CONT_SAMPLING
- | MCP3422_CHANNEL_VALUE(0)
- | MCP3422_PGA_VALUE(MCP3422_PGA_1)
- | MCP3422_SAMPLE_RATE_VALUE(MCP3422_SRATE_240));
+ config = MCP3422_CONT_SAMPLING |
+ FIELD_PREP(MCP3422_CHANNEL_MASK, 0) |
+ FIELD_PREP(MCP3422_PGA_MASK, MCP3422_PGA_1) |
+ FIELD_PREP(MCP3422_SRATE_MASK, MCP3422_SRATE_240);
err = mcp3422_update_config(adc, config);
if (err < 0)
return err;
@@ -394,14 +382,14 @@ static int mcp3422_probe(struct i2c_client *client)
}
static const struct i2c_device_id mcp3422_id[] = {
- { "mcp3421", 1 },
- { "mcp3422", 2 },
- { "mcp3423", 3 },
- { "mcp3424", 4 },
- { "mcp3425", 5 },
- { "mcp3426", 6 },
- { "mcp3427", 7 },
- { "mcp3428", 8 },
+ { .name = "mcp3421", .driver_data = 1 },
+ { .name = "mcp3422", .driver_data = 2 },
+ { .name = "mcp3423", .driver_data = 3 },
+ { .name = "mcp3424", .driver_data = 4 },
+ { .name = "mcp3425", .driver_data = 5 },
+ { .name = "mcp3426", .driver_data = 6 },
+ { .name = "mcp3427", .driver_data = 7 },
+ { .name = "mcp3428", .driver_data = 8 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp3422_id);
diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c
index fcdf13f49c48..259ac4ebdedf 100644
--- a/drivers/iio/adc/mcp3564.c
+++ b/drivers/iio/adc/mcp3564.c
@@ -349,7 +349,7 @@ struct mcp3564_chip_info {
* struct mcp3564_state - working data for a ADC device
* @chip_info: chip specific data
* @spi: SPI device structure
- * @vref_mv: voltage reference value in miliVolts
+ * @vref_mv: voltage reference value in millivolts
* @lock: synchronize access to driver's state members
* @dev_addr: hardware device address
* @oversampling: the index inside oversampling list of the ADC
@@ -1451,18 +1451,18 @@ static const struct of_device_id mcp3564_dt_ids[] = {
MODULE_DEVICE_TABLE(of, mcp3564_dt_ids);
static const struct spi_device_id mcp3564_id[] = {
- { "mcp3461", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461] },
- { "mcp3462", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462] },
- { "mcp3464", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464] },
- { "mcp3561", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561] },
- { "mcp3562", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562] },
- { "mcp3564", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564] },
- { "mcp3461r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461r] },
- { "mcp3462r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462r] },
- { "mcp3464r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464r] },
- { "mcp3561r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561r] },
- { "mcp3562r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562r] },
- { "mcp3564r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564r] },
+ { .name = "mcp3461", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461] },
+ { .name = "mcp3462", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462] },
+ { .name = "mcp3464", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464] },
+ { .name = "mcp3561", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561] },
+ { .name = "mcp3562", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562] },
+ { .name = "mcp3564", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564] },
+ { .name = "mcp3461r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461r] },
+ { .name = "mcp3462r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462r] },
+ { .name = "mcp3464r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464r] },
+ { .name = "mcp3561r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561r] },
+ { .name = "mcp3562r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562r] },
+ { .name = "mcp3564r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564r] },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp3564_id);
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
index ddc3721f3f68..797424f59f74 100644
--- a/drivers/iio/adc/mcp3911.c
+++ b/drivers/iio/adc/mcp3911.c
@@ -14,7 +14,6 @@
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
@@ -928,13 +927,13 @@ static const struct of_device_id mcp3911_dt_ids[] = {
MODULE_DEVICE_TABLE(of, mcp3911_dt_ids);
static const struct spi_device_id mcp3911_id[] = {
- { "mcp3910", (kernel_ulong_t)&mcp3911_chip_info[MCP3910] },
- { "mcp3911", (kernel_ulong_t)&mcp3911_chip_info[MCP3911] },
- { "mcp3912", (kernel_ulong_t)&mcp3911_chip_info[MCP3912] },
- { "mcp3913", (kernel_ulong_t)&mcp3911_chip_info[MCP3913] },
- { "mcp3914", (kernel_ulong_t)&mcp3911_chip_info[MCP3914] },
- { "mcp3918", (kernel_ulong_t)&mcp3911_chip_info[MCP3918] },
- { "mcp3919", (kernel_ulong_t)&mcp3911_chip_info[MCP3919] },
+ { .name = "mcp3910", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3910] },
+ { .name = "mcp3911", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3911] },
+ { .name = "mcp3912", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3912] },
+ { .name = "mcp3913", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3913] },
+ { .name = "mcp3914", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3914] },
+ { .name = "mcp3918", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3918] },
+ { .name = "mcp3919", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3919] },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp3911_id);
diff --git a/drivers/iio/adc/men_z188_adc.c b/drivers/iio/adc/men_z188_adc.c
index 90919d282e7b..5bd334ec5655 100644
--- a/drivers/iio/adc/men_z188_adc.c
+++ b/drivers/iio/adc/men_z188_adc.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * MEN 16z188 Analog to Digial Converter
+ * MEN 16z188 Analog to Digital Converter
*
* Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
* Author: Johannes Thumshirn <johannes.thumshirn@men.de>
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 47cd350498a0..000e39ca5c62 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -792,7 +792,7 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
size_t read_len;
int ret;
- temperature_calib = devm_nvmem_cell_get(dev, "temperature_calib");
+ temperature_calib = nvmem_cell_get(dev, "temperature_calib");
if (IS_ERR(temperature_calib)) {
ret = PTR_ERR(temperature_calib);
@@ -806,13 +806,9 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
return dev_err_probe(dev, ret, "failed to get temperature_calib cell\n");
}
- priv->tsc_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "amlogic,hhi-sysctrl");
- if (IS_ERR(priv->tsc_regmap))
- return dev_err_probe(dev, PTR_ERR(priv->tsc_regmap),
- "failed to get amlogic,hhi-sysctrl regmap\n");
-
read_len = MESON_SAR_ADC_EFUSE_BYTES;
buf = nvmem_cell_read(temperature_calib, &read_len);
+ nvmem_cell_put(temperature_calib);
if (IS_ERR(buf))
return dev_err_probe(dev, PTR_ERR(buf), "failed to read temperature_calib cell\n");
if (read_len != MESON_SAR_ADC_EFUSE_BYTES) {
@@ -820,6 +816,13 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
return dev_err_probe(dev, -EINVAL, "invalid read size of temperature_calib cell\n");
}
+ priv->tsc_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "amlogic,hhi-sysctrl");
+ if (IS_ERR(priv->tsc_regmap)) {
+ kfree(buf);
+ return dev_err_probe(dev, PTR_ERR(priv->tsc_regmap),
+ "failed to get amlogic,hhi-sysctrl regmap\n");
+ }
+
trimming_bits = priv->param->temperature_trimming_bits;
trimming_mask = BIT(trimming_bits) - 1;
@@ -1313,6 +1316,11 @@ static const struct meson_sar_adc_data meson_sar_adc_g12a_data = {
.name = "meson-g12a-saradc",
};
+static const struct meson_sar_adc_data meson_sar_adc_s4_data = {
+ .param = &meson_sar_adc_g12a_param,
+ .name = "meson-s4-saradc",
+};
+
static const struct of_device_id meson_sar_adc_of_match[] = {
{
.compatible = "amlogic,meson8-saradc",
@@ -1341,6 +1349,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = {
}, {
.compatible = "amlogic,meson-g12a-saradc",
.data = &meson_sar_adc_g12a_data,
+ }, {
+ .compatible = "amlogic,meson-s4-saradc",
+ .data = &meson_sar_adc_s4_data,
},
{ }
};
diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c
index 5a1d516f8dad..c03f89ddbd13 100644
--- a/drivers/iio/adc/mp2629_adc.c
+++ b/drivers/iio/adc/mp2629_adc.c
@@ -11,7 +11,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
#include <linux/mfd/mp2629.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
diff --git a/drivers/iio/adc/mt6323-auxadc.c b/drivers/iio/adc/mt6323-auxadc.c
new file mode 100644
index 000000000000..4f73ac42abb7
--- /dev/null
+++ b/drivers/iio/adc/mt6323-auxadc.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2026 Roman Vivchar <rva333@protonmail.com>
+ *
+ * Based on drivers/iio/adc/mt6359-auxadc.c
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/stringify.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <linux/mfd/mt6323/registers.h>
+
+#include <dt-bindings/iio/adc/mediatek,mt6323-auxadc.h>
+
+#define AUXADC_STRUP_CON10_RSTB_SEL BIT(7)
+#define AUXADC_STRUP_CON10_RSTB_SW BIT(5)
+
+#define AUXADC_TOP_CKPDN2_CTL_CK BIT(5)
+
+#define AUXADC_TRIM_CH2_MASK GENMASK(11, 10)
+#define AUXADC_TRIM_CH4_MASK GENMASK(9, 8)
+#define AUXADC_TRIM_CH5_MASK GENMASK(5, 4)
+#define AUXADC_TRIM_CH6_MASK GENMASK(3, 2)
+
+#define AUXADC_CON27_VREF18_ENB_MD BIT(15)
+#define AUXADC_CON27_MD_STATUS BIT(0)
+
+#define AUXADC_CON19_GPS_STATUS BIT(1)
+
+#define AUXADC_CON26_VREF18_SELB BIT(1)
+#define AUXADC_CON26_DECI_GDLY_SEL BIT(0)
+
+#define AUXADC_CON11_VBUF_EN BIT(4)
+
+#define AUXADC_CON19_DECI_GDLY_MASK GENMASK(15, 14)
+#define AUXADC_ADC19_BUSY_MASK GENMASK(15, 1)
+#define AUXADC_READY_MASK BIT(15)
+#define AUXADC_DATA_MASK GENMASK(14, 0)
+
+#define AUXADC_CON9_OSR_MASK GENMASK(12, 10)
+#define AUXADC_DEFAULT_OSR 3
+
+#define MTK_PMIC_IIO_CHAN(_name, _chan, _addr) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = _chan, \
+ .address = _addr, \
+ .datasheet_name = __stringify(_name), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+/*
+ * AUXADC reports everything in mV, including temperature and
+ * current channels. Channel macros are mapped such that their
+ * ID matches their respective hardware bit position in CON22.
+ */
+static const struct iio_chan_spec mt6323_auxadc_channels[] = {
+ MTK_PMIC_IIO_CHAN(baton2, MT6323_AUXADC_BATON2, MT6323_AUXADC_ADC6),
+ MTK_PMIC_IIO_CHAN(ch6, MT6323_AUXADC_CH6, MT6323_AUXADC_ADC11),
+ MTK_PMIC_IIO_CHAN(bat_temp, MT6323_AUXADC_BAT_TEMP, MT6323_AUXADC_ADC5),
+ MTK_PMIC_IIO_CHAN(chip_temp, MT6323_AUXADC_CHIP_TEMP, MT6323_AUXADC_ADC4),
+ MTK_PMIC_IIO_CHAN(vcdt, MT6323_AUXADC_VCDT, MT6323_AUXADC_ADC2),
+ MTK_PMIC_IIO_CHAN(baton1, MT6323_AUXADC_BATON1, MT6323_AUXADC_ADC3),
+ MTK_PMIC_IIO_CHAN(isense, MT6323_AUXADC_ISENSE, MT6323_AUXADC_ADC1),
+ MTK_PMIC_IIO_CHAN(batsns, MT6323_AUXADC_BATSNS, MT6323_AUXADC_ADC0),
+ MTK_PMIC_IIO_CHAN(accdet, MT6323_AUXADC_ACCDET, MT6323_AUXADC_ADC7),
+};
+
+/*
+ * The MediaTek MT6323 (as well as a lot of other PMICs) has the following hierarchy:
+ * PMIC AUXADC <- PMIC MFD <- SoC PWRAP (wrapper for PWRAP FSM)
+ *
+ * Therefore, PWRAP regmap should be obtained using dev->parent->parent.
+ */
+struct mt6323_auxadc {
+ struct regmap *regmap;
+ /* AUXADC doesn't support reading multiple channels simultaneously. */
+ struct mutex lock;
+};
+
+static int mt6323_auxadc_prepare_channel(struct mt6323_auxadc *auxadc)
+{
+ struct regmap *map = auxadc->regmap;
+ u32 val;
+ int ret;
+
+ ret = regmap_read(map, MT6323_AUXADC_CON19, &val);
+ if (ret)
+ return ret;
+
+ /* The ADC is idle. */
+ if (!(val & AUXADC_CON19_DECI_GDLY_MASK))
+ return 0;
+
+ ret = regmap_read_poll_timeout(map, MT6323_AUXADC_ADC19,
+ val, !(val & AUXADC_ADC19_BUSY_MASK),
+ 10, 500);
+ if (ret)
+ return ret;
+
+ return regmap_clear_bits(map, MT6323_AUXADC_CON19,
+ AUXADC_CON19_DECI_GDLY_MASK);
+}
+
+static int mt6323_auxadc_request(struct mt6323_auxadc *auxadc,
+ unsigned long channel)
+{
+ struct regmap *map = auxadc->regmap;
+ int ret;
+
+ ret = regmap_set_bits(map, MT6323_AUXADC_CON11, AUXADC_CON11_VBUF_EN);
+ if (ret)
+ return ret;
+
+ return regmap_set_bits(map, MT6323_AUXADC_CON22, BIT(channel));
+}
+
+static int mt6323_auxadc_release(struct mt6323_auxadc *auxadc,
+ unsigned long channel)
+{
+ struct regmap *map = auxadc->regmap;
+ int ret;
+
+ ret = regmap_clear_bits(map, MT6323_AUXADC_CON22, BIT(channel));
+ if (ret)
+ return ret;
+
+ return regmap_clear_bits(map, MT6323_AUXADC_CON11, AUXADC_CON11_VBUF_EN);
+}
+
+static int mt6323_auxadc_read(struct mt6323_auxadc *auxadc,
+ const struct iio_chan_spec *chan, int *out)
+{
+ struct regmap *map = auxadc->regmap;
+ u32 val;
+ int ret;
+
+ ret = regmap_read_poll_timeout(map, chan->address,
+ val, (val & AUXADC_READY_MASK),
+ 1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC);
+ if (ret)
+ return ret;
+
+ *out = FIELD_GET(AUXADC_DATA_MASK, val);
+
+ return 0;
+}
+
+static int mt6323_auxadc_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct mt6323_auxadc *auxadc = iio_priv(indio_dev);
+ int ret, mult;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->channel == MT6323_AUXADC_ISENSE ||
+ chan->channel == MT6323_AUXADC_BATSNS)
+ mult = 4;
+ else
+ mult = 1;
+
+ /* 1800mV full range with 15-bit resolution. */
+ *val = mult * 1800;
+ *val2 = 15;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_RAW: {
+ guard(mutex)(&auxadc->lock);
+
+ ret = mt6323_auxadc_prepare_channel(auxadc);
+ if (ret)
+ return ret;
+
+ ret = mt6323_auxadc_request(auxadc, chan->channel);
+ if (ret)
+ return ret;
+
+ /* Hardware limitation: the AUXADC needs a delay to become ready. */
+ fsleep(300);
+
+ ret = mt6323_auxadc_read(auxadc, chan, val);
+
+ if (mt6323_auxadc_release(auxadc, chan->channel))
+ dev_err(&indio_dev->dev,
+ "failed to release channel %d\n", chan->channel);
+
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mt6323_auxadc_init(struct mt6323_auxadc *auxadc)
+{
+ struct regmap *map = auxadc->regmap;
+ int ret;
+
+ ret = regmap_set_bits(map, MT6323_STRUP_CON10,
+ AUXADC_STRUP_CON10_RSTB_SW |
+ AUXADC_STRUP_CON10_RSTB_SEL);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(map, MT6323_TOP_CKPDN2, AUXADC_TOP_CKPDN2_CTL_CK);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(map, MT6323_AUXADC_CON10,
+ AUXADC_TRIM_CH2_MASK | AUXADC_TRIM_CH4_MASK |
+ AUXADC_TRIM_CH5_MASK | AUXADC_TRIM_CH6_MASK,
+ FIELD_PREP(AUXADC_TRIM_CH2_MASK, 1) |
+ FIELD_PREP(AUXADC_TRIM_CH4_MASK, 1) |
+ FIELD_PREP(AUXADC_TRIM_CH5_MASK, 1) |
+ FIELD_PREP(AUXADC_TRIM_CH6_MASK, 1));
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(map, MT6323_AUXADC_CON27,
+ AUXADC_CON27_VREF18_ENB_MD |
+ AUXADC_CON27_MD_STATUS);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(map, MT6323_AUXADC_CON19, AUXADC_CON19_GPS_STATUS);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(map, MT6323_AUXADC_CON26,
+ AUXADC_CON26_VREF18_SELB |
+ AUXADC_CON26_DECI_GDLY_SEL);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(map, MT6323_AUXADC_CON9, AUXADC_CON9_OSR_MASK,
+ FIELD_PREP(AUXADC_CON9_OSR_MASK, AUXADC_DEFAULT_OSR));
+}
+
+static const struct iio_info mt6323_auxadc_iio_info = {
+ .read_raw = mt6323_auxadc_read_raw,
+};
+
+static int mt6323_auxadc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mt6323_auxadc *auxadc;
+ struct regmap *regmap;
+ struct iio_dev *iio;
+ int ret;
+
+ regmap = dev_get_regmap(dev->parent->parent, NULL);
+ if (!regmap)
+ return dev_err_probe(dev, -ENODEV, "failed to get regmap\n");
+
+ iio = devm_iio_device_alloc(dev, sizeof(*auxadc));
+ if (!iio)
+ return -ENOMEM;
+
+ auxadc = iio_priv(iio);
+ auxadc->regmap = regmap;
+
+ ret = devm_mutex_init(dev, &auxadc->lock);
+ if (ret)
+ return ret;
+
+ ret = mt6323_auxadc_init(auxadc);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize auxadc\n");
+
+ iio->name = "mt6323-auxadc";
+ iio->info = &mt6323_auxadc_iio_info;
+ iio->modes = INDIO_DIRECT_MODE;
+ iio->channels = mt6323_auxadc_channels;
+ iio->num_channels = ARRAY_SIZE(mt6323_auxadc_channels);
+
+ return devm_iio_device_register(dev, iio);
+}
+
+static const struct of_device_id mt6323_auxadc_of_match[] = {
+ { .compatible = "mediatek,mt6323-auxadc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt6323_auxadc_of_match);
+
+static struct platform_driver mt6323_auxadc_driver = {
+ .driver = {
+ .name = "mt6323-auxadc",
+ .of_match_table = mt6323_auxadc_of_match,
+ },
+ .probe = mt6323_auxadc_probe,
+};
+module_platform_driver(mt6323_auxadc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MediaTek MT6323 PMIC AUXADC Driver");
diff --git a/drivers/iio/adc/mt6359-auxadc.c b/drivers/iio/adc/mt6359-auxadc.c
index f426a289e867..88b0e26309e5 100644
--- a/drivers/iio/adc/mt6359-auxadc.c
+++ b/drivers/iio/adc/mt6359-auxadc.c
@@ -12,7 +12,6 @@
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -322,7 +321,7 @@ static const struct mtk_pmic_auxadc_chan mt6359_auxadc_ch_desc[] = {
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2),
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP1, 15, 8, 5, 2),
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP1, 15 ,8, 1, 1),
+ MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, PMIC_AUXADC_IMP1, 15, 8, 3, 2),
MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP1, 15, 128, 1, 1),
MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP1, 15, 256, 1, 1),
@@ -497,6 +496,7 @@ static int mt6358_read_imp(struct mt6359_auxadc *adc_dev,
return ret;
/* Read the params before stopping */
+ val_v = 0;
regmap_read(regmap, reg_adc0 + (cinfo->imp_adc_num << 1), &val_v);
mt6358_stop_imp_conv(adc_dev);
diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c
index e0e4df418612..e59b13e88aa2 100644
--- a/drivers/iio/adc/mt6360-adc.c
+++ b/drivers/iio/adc/mt6360-adc.c
@@ -5,7 +5,6 @@
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c
index 7c71fe5e8d31..c250385f9d34 100644
--- a/drivers/iio/adc/mt6370-adc.c
+++ b/drivers/iio/adc/mt6370-adc.c
@@ -9,7 +9,6 @@
#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>
diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
index fe9e3ece3fda..ecbae90ac2ed 100644
--- a/drivers/iio/adc/mt6577_auxadc.c
+++ b/drivers/iio/adc/mt6577_auxadc.c
@@ -9,7 +9,6 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/iopoll.h>
diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c
index 458544cb8ee4..dccf11fbf88a 100644
--- a/drivers/iio/adc/nau7802.c
+++ b/drivers/iio/adc/nau7802.c
@@ -8,7 +8,6 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/wait.h>
@@ -55,7 +54,6 @@ struct nau7802_state {
struct mutex data_lock;
u32 vref_mv;
u32 conversion_count;
- u32 min_conversions;
u8 sample_rate;
u32 scale_avail[8];
struct completion value_ok;
@@ -257,7 +255,7 @@ static int nau7802_read_poll(struct iio_dev *indio_dev,
/*
* Because there is actually only one ADC for both channels, we have to
* wait for enough conversions to happen before getting a significant
- * value when changing channels and the values are far appart.
+ * value when changing channels and the values are far apart.
*/
do {
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
@@ -532,7 +530,7 @@ static int nau7802_probe(struct i2c_client *client)
}
static const struct i2c_device_id nau7802_i2c_id[] = {
- { "nau7802" },
+ { .name = "nau7802" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id);
diff --git a/drivers/iio/adc/nct7201.c b/drivers/iio/adc/nct7201.c
index d87824e5490f..bea88a9b9440 100644
--- a/drivers/iio/adc/nct7201.c
+++ b/drivers/iio/adc/nct7201.c
@@ -12,7 +12,6 @@
#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/time.h>
diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c
index c8283873cdee..a25c15b38759 100644
--- a/drivers/iio/adc/npcm_adc.c
+++ b/drivers/iio/adc/npcm_adc.c
@@ -8,7 +8,6 @@
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -38,7 +37,7 @@ struct npcm_adc {
* read access from userspace. Reading a raw value requires a sequence
* of register writes, then a wait for a event and finally a register
* read, during which userspace could issue another read request.
- * This lock protects a read access from ocurring before another one
+ * This lock protects a read access from occurring before another one
* has finished.
*/
struct mutex lock;
@@ -231,7 +230,7 @@ static int npcm_adc_probe(struct platform_device *pdev)
if (IS_ERR(info->reset))
return PTR_ERR(info->reset);
- info->adc_clk = devm_clk_get(&pdev->dev, NULL);
+ info->adc_clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(info->adc_clk)) {
dev_warn(&pdev->dev, "ADC clock failed: can't read clk\n");
return PTR_ERR(info->adc_clk);
@@ -244,17 +243,13 @@ static int npcm_adc_probe(struct platform_device *pdev)
info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2);
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- ret = irq;
- goto err_disable_clk;
- }
+ if (irq < 0)
+ return irq;
ret = devm_request_irq(&pdev->dev, irq, npcm_adc_isr, 0,
"NPCM_ADC", indio_dev);
- if (ret < 0) {
- dev_err(dev, "failed requesting interrupt\n");
- goto err_disable_clk;
- }
+ if (ret < 0)
+ return ret;
reg_con = ioread32(info->regs + NPCM_ADCCON);
info->vref = devm_regulator_get_optional(&pdev->dev, "vref");
@@ -262,7 +257,7 @@ static int npcm_adc_probe(struct platform_device *pdev)
ret = regulator_enable(info->vref);
if (ret) {
dev_err(&pdev->dev, "Can't enable ADC reference voltage\n");
- goto err_disable_clk;
+ return ret;
}
iowrite32(reg_con & ~NPCM_ADCCON_REFSEL,
@@ -272,10 +267,8 @@ static int npcm_adc_probe(struct platform_device *pdev)
* Any error which is not ENODEV indicates the regulator
* has been specified and so is a failure case.
*/
- if (PTR_ERR(info->vref) != -ENODEV) {
- ret = PTR_ERR(info->vref);
- goto err_disable_clk;
- }
+ if (PTR_ERR(info->vref) != -ENODEV)
+ return PTR_ERR(info->vref);
/* Use internal reference */
iowrite32(reg_con | NPCM_ADCCON_REFSEL,
@@ -314,8 +307,6 @@ err_iio_register:
iowrite32(reg_con & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
if (!IS_ERR(info->vref))
regulator_disable(info->vref);
-err_disable_clk:
- clk_disable_unprepare(info->adc_clk);
return ret;
}
@@ -332,7 +323,6 @@ static void npcm_adc_remove(struct platform_device *pdev)
iowrite32(regtemp & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
if (!IS_ERR(info->vref))
regulator_disable(info->vref);
- clk_disable_unprepare(info->adc_clk);
}
static struct platform_driver npcm_adc_driver = {
diff --git a/drivers/iio/adc/nxp-sar-adc.c b/drivers/iio/adc/nxp-sar-adc.c
index 9efa883c277d..894d3211b283 100644
--- a/drivers/iio/adc/nxp-sar-adc.c
+++ b/drivers/iio/adc/nxp-sar-adc.c
@@ -21,7 +21,6 @@
#include <linux/iopoll.h>
#include <linux/math64.h>
#include <linux/minmax.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
@@ -198,6 +197,15 @@ static void nxp_sar_adc_irq_cfg(struct nxp_sar_adc *info, bool enable)
writel(0, NXP_SAR_ADC_IMR(info->regs));
}
+static void nxp_sar_adc_wait_for(struct nxp_sar_adc *info, u64 cycles)
+{
+ u64 rate;
+
+ rate = clk_get_rate(info->clk);
+ if (rate)
+ ndelay(div64_u64(NSEC_PER_SEC * cycles, rate));
+}
+
static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable)
{
u32 mcr;
@@ -221,7 +229,7 @@ static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable)
* configuration of NCMR and the setting of NSTART.
*/
if (enable)
- ndelay(div64_u64(NSEC_PER_SEC, clk_get_rate(info->clk) * 3));
+ nxp_sar_adc_wait_for(info, 3);
return pwdn;
}
@@ -247,7 +255,8 @@ static inline void nxp_sar_adc_calibration_start(void __iomem *base)
static inline int nxp_sar_adc_calibration_wait(void __iomem *base)
{
- u32 msr, ret;
+ u32 msr;
+ int ret;
ret = readl_poll_timeout(NXP_SAR_ADC_MSR(base), msr,
!FIELD_GET(NXP_SAR_ADC_MSR_CALBUSY, msr),
@@ -316,11 +325,7 @@ static int nxp_sar_adc_read_data(struct nxp_sar_adc *info, unsigned int chan)
ceocfr = readl(NXP_SAR_ADC_CEOCFR0(info->regs));
- /*
- * FIELD_GET() can not be used here because EOC_CH is not constant.
- * TODO: Switch to field_get() when it will be available.
- */
- if (!(NXP_SAR_ADC_EOC_CH(chan) & ceocfr))
+ if (!field_get(NXP_SAR_ADC_EOC_CH(chan), ceocfr))
return -EIO;
cdr = readl(NXP_SAR_ADC_CDR(info->regs, chan));
@@ -340,6 +345,7 @@ static void nxp_sar_adc_isr_buffer(struct iio_dev *indio_dev)
ret = nxp_sar_adc_read_data(info, info->buffered_chan[i]);
if (ret < 0) {
nxp_sar_adc_read_notify(info);
+ iio_trigger_notify_done(indio_dev->trig);
return;
}
@@ -468,7 +474,7 @@ static void nxp_sar_adc_stop_conversion(struct nxp_sar_adc *info)
* only when the capture finishes. The delay will be very
* short, usec-ish, which is acceptable in the atomic context.
*/
- ndelay(div64_u64(NSEC_PER_SEC, clk_get_rate(info->clk)) * 80);
+ nxp_sar_adc_wait_for(info, 80);
}
static int nxp_sar_adc_start_conversion(struct nxp_sar_adc *info, bool raw)
@@ -559,6 +565,9 @@ static int nxp_sar_adc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
+ if (val <= 0)
+ return -EINVAL;
+
/*
* Configures the sample period duration in terms of the SAR
* controller clock. The minimum acceptable value is 8.
@@ -567,7 +576,11 @@ static int nxp_sar_adc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec
* sampling timing which gives us the number of cycles expected.
* The value is 8-bit wide, consequently the max value is 0xFF.
*/
- inpsamp = clk_get_rate(info->clk) / val - NXP_SAR_ADC_CONV_TIME;
+ inpsamp = clk_get_rate(info->clk) / val;
+ if (inpsamp < NXP_SAR_ADC_CONV_TIME)
+ return -EINVAL;
+
+ inpsamp -= NXP_SAR_ADC_CONV_TIME;
nxp_sar_adc_conversion_timing_set(info, inpsamp);
return 0;
@@ -659,7 +672,7 @@ static void nxp_sar_adc_dma_cb(void *data)
static int nxp_sar_adc_start_cyclic_dma(struct iio_dev *indio_dev)
{
struct nxp_sar_adc *info = iio_priv(indio_dev);
- struct dma_slave_config config;
+ struct dma_slave_config config = { };
struct dma_async_tx_descriptor *desc;
int ret;
@@ -718,6 +731,10 @@ static int nxp_sar_adc_buffer_software_do_postenable(struct iio_dev *indio_dev)
struct nxp_sar_adc *info = iio_priv(indio_dev);
int ret;
+ info->dma_chan = dma_request_chan(indio_dev->dev.parent, "rx");
+ if (IS_ERR(info->dma_chan))
+ return PTR_ERR(info->dma_chan);
+
nxp_sar_adc_dma_channels_enable(info, *indio_dev->active_scan_mask);
nxp_sar_adc_dma_cfg(info, true);
@@ -738,6 +755,7 @@ out_stop_cyclic_dma:
out_dma_channels_disable:
nxp_sar_adc_dma_cfg(info, false);
nxp_sar_adc_dma_channels_disable(info, *indio_dev->active_scan_mask);
+ dma_release_channel(info->dma_chan);
return ret;
}
@@ -765,10 +783,6 @@ static int nxp_sar_adc_buffer_postenable(struct iio_dev *indio_dev)
unsigned long channel;
int ret;
- info->dma_chan = dma_request_chan(indio_dev->dev.parent, "rx");
- if (IS_ERR(info->dma_chan))
- return PTR_ERR(info->dma_chan);
-
info->channels_used = 0;
/*
diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c
index a0227b57f238..f0bab94462f4 100644
--- a/drivers/iio/adc/pac1921.c
+++ b/drivers/iio/adc/pac1921.c
@@ -856,7 +856,7 @@ static ssize_t pac1921_format_scale_avail(const int (*const scales_tbl)[2],
/*
* Read available scales for a specific channel
*
- * NOTE: using extended info insted of iio.read_avail() because access to
+ * NOTE: using extended info instead of iio.read_avail() because access to
* current scales must be locked as they depend on shunt resistor which may
* change runtime. Caller of iio.read_avail() would access the table unlocked
* instead.
@@ -1037,7 +1037,7 @@ static irqreturn_t pac1921_trigger_handler(int irq, void *p)
iio_for_each_active_channel(idev, bit) {
u16 val;
- ret = pac1921_read_res(priv, idev->channels[ch].address, &val);
+ ret = pac1921_read_res(priv, idev->channels[bit].address, &val);
if (ret)
goto done;
@@ -1310,7 +1310,7 @@ static int pac1921_probe(struct i2c_client *client)
}
static const struct i2c_device_id pac1921_id[] = {
- { .name = "pac1921", 0 },
+ { .name = "pac1921" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pac1921_id);
diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c
index 712b5e9caba6..23055405a6e0 100644
--- a/drivers/iio/adc/pac1934.c
+++ b/drivers/iio/adc/pac1934.c
@@ -1351,7 +1351,7 @@ static int pac1934_prep_iio_channels(struct pac1934_chip_info *info, struct iio_
dyn_ch_struct = devm_kzalloc(dev, channel_size, GFP_KERNEL);
if (!dyn_ch_struct)
- return -EINVAL;
+ return -ENOMEM;
tmp_data = dyn_ch_struct;
diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c
index 3f433064618e..f777986a6aba 100644
--- a/drivers/iio/adc/palmas_gpadc.c
+++ b/drivers/iio/adc/palmas_gpadc.c
@@ -105,7 +105,7 @@ struct palmas_gpadc_thresholds {
* of register writes, then a wait for a completion callback,
* and finally a register read, during which userspace could issue
* another read request. This lock protects a read access from
- * ocurring before another one has finished.
+ * occurring before another one has finished.
*
* This is the palmas_gpadc structure to store run-time information
* and pointers for this driver instance.
@@ -521,16 +521,16 @@ static int palmas_gpadc_get_low_threshold_raw(struct palmas_gpadc *adc,
val = (val * 1000) / adc->adc_info[adc_chan].gain;
- if (adc->adc_info[adc_chan].is_uncalibrated) {
+ if (adc->adc_info[adc_chan].is_uncalibrated) {
/* 2% worse */
min_gain_error -= 20;
min_offset_error = -36;
- } else {
+ } else {
val = (val * adc->adc_info[adc_chan].gain_error -
adc->adc_info[adc_chan].offset) /
1000;
min_offset_error = -2;
- }
+ }
return palmas_gpadc_threshold_with_tolerance(val,
min_INL,
diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c
index 31f88cf7f7f1..3cdf90c4444b 100644
--- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c
+++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c
@@ -14,7 +14,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -369,7 +368,7 @@ static const struct xoadc_channel pm8921_xoadc_channels[] = {
/**
* struct pm8xxx_chan_info - ADC channel information
- * @name: name of this channel
+ * @label: label of this channel from device tree (defaults to datasheet name if not specified)
* @hwchan: pointer to hardware channel information (muxing & scaling settings)
* @calibration: whether to use absolute or ratiometric calibration
* @decimation: 0,1,2,3
@@ -377,7 +376,7 @@ static const struct xoadc_channel pm8921_xoadc_channels[] = {
* calibration: 0, 1, 2, 4, 5.
*/
struct pm8xxx_chan_info {
- const char *name;
+ const char *label;
const struct xoadc_channel *hwchan;
enum vadc_calibration calibration;
u8 decimation:2;
@@ -446,7 +445,7 @@ static int pm8xxx_read_channel_rsv(struct pm8xxx_xoadc *adc,
u8 lsb, msb;
dev_dbg(adc->dev, "read channel \"%s\", amux %d, prescale/mux: %d, rsv %d\n",
- ch->name, ch->hwchan->amux_channel, ch->hwchan->pre_scale_mux, rsv);
+ ch->label, ch->hwchan->amux_channel, ch->hwchan->pre_scale_mux, rsv);
mutex_lock(&adc->lock);
@@ -535,10 +534,7 @@ static int pm8xxx_read_channel_rsv(struct pm8xxx_xoadc *adc,
goto unlock;
/* Next the interrupt occurs */
- ret = wait_for_completion_timeout(&adc->complete,
- VADC_CONV_TIME_MAX_US);
- if (!ret) {
- dev_err(adc->dev, "conversion timed out\n");
+ if (!wait_for_completion_timeout(&adc->complete, VADC_CONV_TIME_MAX_US)) {
ret = -ETIMEDOUT;
goto unlock;
}
@@ -657,11 +653,8 @@ static int pm8xxx_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
ch = pm8xxx_get_channel(adc, chan->address);
- if (!ch) {
- dev_err(adc->dev, "no such channel %lu\n",
- chan->address);
+ if (!ch)
return -EINVAL;
- }
ret = pm8xxx_read_channel(adc, ch, &adc_code);
if (ret)
return ret;
@@ -677,11 +670,8 @@ static int pm8xxx_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_RAW:
ch = pm8xxx_get_channel(adc, chan->address);
- if (!ch) {
- dev_err(adc->dev, "no such channel %lu\n",
- chan->address);
+ if (!ch)
return -EINVAL;
- }
ret = pm8xxx_read_channel(adc, ch, &adc_code);
if (ret)
return ret;
@@ -725,8 +715,21 @@ static int pm8xxx_fwnode_xlate(struct iio_dev *indio_dev,
return -EINVAL;
}
+static int pm8xxx_read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, char *label)
+{
+ struct pm8xxx_xoadc *adc = iio_priv(indio_dev);
+ const struct pm8xxx_chan_info *ch;
+
+ ch = pm8xxx_get_channel(adc, chan->address);
+ if (!ch)
+ return -EINVAL;
+ return sysfs_emit(label, "%s\n", ch->label);
+}
+
static const struct iio_info pm8xxx_xoadc_info = {
.fwnode_xlate = pm8xxx_fwnode_xlate,
+ .read_label = pm8xxx_read_label,
.read_raw = pm8xxx_read_raw,
};
@@ -770,7 +773,8 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev,
pre_scale_mux, amux_channel);
return -EINVAL;
}
- ch->name = name;
+ ch->label = hwchan->datasheet_name;
+ fwnode_property_read_string(fwnode, "label", &ch->label);
ch->hwchan = hwchan;
/* Everyone seems to use absolute calibration except in special cases */
ch->calibration = VADC_CALIB_ABSOLUTE;
@@ -812,7 +816,7 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev,
dev_dbg(dev,
"channel [PRESCALE/MUX: %02x AMUX: %02x] \"%s\" ref voltage: %d, decimation %d prescale %d/%d, scale function %d\n",
- hwchan->pre_scale_mux, hwchan->amux_channel, ch->name,
+ hwchan->pre_scale_mux, hwchan->amux_channel, ch->label,
ch->amux_ip_rsv, ch->decimation, hwchan->prescale.numerator,
hwchan->prescale.denominator, hwchan->scale_fn_type);
diff --git a/drivers/iio/adc/qcom-spmi-adc5-gen3.c b/drivers/iio/adc/qcom-spmi-adc5-gen3.c
new file mode 100644
index 000000000000..c68c6c5f6aca
--- /dev/null
+++ b/drivers/iio/adc/qcom-spmi-adc5-gen3.c
@@ -0,0 +1,828 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/completion.h>
+#include <linux/container_of.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/device/devres.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/iio/adc/qcom-adc5-gen3-common.h>
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#define ADC5_GEN3_VADC_SDAM 0x0
+
+struct adc5_chip;
+
+/**
+ * struct adc5_channel_prop - ADC channel structure
+ * @common_props: structure with ADC channel properties (common to TM usage).
+ * @adc_tm: indicates TM type if the channel is used for TM measurements.
+ * @chip: pointer to top-level ADC device structure.
+ */
+struct adc5_channel_prop {
+ struct adc5_channel_common_prop common_props;
+ int adc_tm;
+ struct adc5_chip *chip;
+};
+
+/**
+ * struct adc5_chip - ADC private structure.
+ * @dev: SPMI ADC5 Gen3 device.
+ * @dev_data: Top-level ADC device data.
+ * @nchannels: number of ADC channels.
+ * @chan_props: array of ADC channel properties.
+ * @iio_chans: array of IIO channels specification.
+ * @complete: ADC result notification after interrupt is received.
+ * @lock: ADC lock for access to the peripheral, to prevent concurrent
+ * requests from multiple clients.
+ * @data: software configuration data.
+ * @n_tm_channels: number of ADC channels used for TM measurements.
+ */
+struct adc5_chip {
+ struct device *dev;
+ struct adc5_device_data dev_data;
+ unsigned int nchannels;
+ struct adc5_channel_prop *chan_props;
+ struct iio_chan_spec *iio_chans;
+ struct completion complete;
+ struct mutex lock;
+ const struct adc5_data *data;
+ unsigned int n_tm_channels;
+};
+
+int adc5_gen3_read(struct adc5_device_data *adc, unsigned int sdam_index,
+ u16 offset, u8 *data, int len)
+{
+ return regmap_bulk_read(adc->regmap,
+ adc->base[sdam_index].base_addr + offset,
+ data, len);
+}
+EXPORT_SYMBOL_NS_GPL(adc5_gen3_read, "QCOM_SPMI_ADC5_GEN3");
+
+int adc5_gen3_write(struct adc5_device_data *adc, unsigned int sdam_index,
+ u16 offset, u8 *data, int len)
+{
+ return regmap_bulk_write(adc->regmap,
+ adc->base[sdam_index].base_addr + offset,
+ data, len);
+}
+EXPORT_SYMBOL_NS_GPL(adc5_gen3_write, "QCOM_SPMI_ADC5_GEN3");
+
+static int adc5_gen3_read_voltage_data(struct adc5_chip *adc, u16 *data)
+{
+ u8 rslt[2];
+ int ret;
+
+ ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
+ ADC5_GEN3_CH_DATA0(0), rslt, sizeof(rslt));
+ if (ret)
+ return ret;
+
+ *data = get_unaligned_le16(rslt);
+
+ if (*data == ADC5_USR_DATA_CHECK) {
+ dev_err(adc->dev, "Invalid data:%#x\n", *data);
+ return -EINVAL;
+ }
+
+ dev_dbg(adc->dev, "voltage raw code:%#x\n", *data);
+
+ return 0;
+}
+
+void adc5_gen3_update_dig_param(struct adc5_channel_common_prop *prop, u8 *data)
+{
+ /* Update calibration select and decimation ratio select */
+ *data &= ~(ADC5_GEN3_DIG_PARAM_CAL_SEL_MASK | ADC5_GEN3_DIG_PARAM_DEC_RATIO_SEL_MASK);
+ *data |= FIELD_PREP(ADC5_GEN3_DIG_PARAM_CAL_SEL_MASK, prop->cal_method);
+ *data |= FIELD_PREP(ADC5_GEN3_DIG_PARAM_DEC_RATIO_SEL_MASK, prop->decimation);
+}
+EXPORT_SYMBOL_NS_GPL(adc5_gen3_update_dig_param, "QCOM_SPMI_ADC5_GEN3");
+
+#define ADC5_GEN3_READ_CONFIG_REGS 7
+
+static int adc5_gen3_configure(struct adc5_chip *adc,
+ struct adc5_channel_common_prop *prop)
+{
+ u8 buf[ADC5_GEN3_READ_CONFIG_REGS];
+ u8 conv_req = 0;
+ int ret;
+
+ ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM, ADC5_GEN3_SID,
+ buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ /* Write SID */
+ buf[0] = FIELD_PREP(ADC5_GEN3_SID_MASK, prop->sid);
+
+ /*
+ * Use channel 0 by default for immediate conversion and to indicate
+ * there is an actual conversion request
+ */
+ buf[1] = ADC5_GEN3_CHAN_CONV_REQ | 0;
+
+ buf[2] = ADC5_GEN3_TIME_IMMEDIATE;
+
+ /* Digital param selection */
+ adc5_gen3_update_dig_param(prop, &buf[3]);
+
+ /* Update fast average sample value */
+ buf[4] = FIELD_PREP(ADC5_GEN3_FAST_AVG_CTL_SAMPLES_MASK,
+ prop->avg_samples) | ADC5_GEN3_FAST_AVG_CTL_EN;
+
+ /* Select ADC channel */
+ buf[5] = prop->channel;
+
+ /* Select HW settle delay for channel */
+ buf[6] = FIELD_PREP(ADC5_GEN3_HW_SETTLE_DELAY_MASK,
+ prop->hw_settle_time_us);
+
+ reinit_completion(&adc->complete);
+
+ ret = adc5_gen3_write(&adc->dev_data, ADC5_GEN3_VADC_SDAM, ADC5_GEN3_SID,
+ buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ conv_req = ADC5_GEN3_CONV_REQ_REQ;
+ return adc5_gen3_write(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
+ ADC5_GEN3_CONV_REQ, &conv_req, sizeof(conv_req));
+}
+
+/*
+ * Worst case delay from PBS in readying handshake bit can be up to 15ms, when
+ * PBS is busy running other simultaneous transactions, while in the best case,
+ * it is already ready at this point. Assigning polling delay and retry count
+ * accordingly.
+ */
+
+#define ADC5_GEN3_HS_DELAY_US 100
+#define ADC5_GEN3_HS_RETRY_COUNT 150
+
+int adc5_gen3_poll_wait_hs(struct adc5_device_data *adc,
+ unsigned int sdam_index)
+{
+ u8 conv_req = ADC5_GEN3_CONV_REQ_REQ;
+ int ret, count;
+ u8 status = 0;
+
+ for (count = 0; count < ADC5_GEN3_HS_RETRY_COUNT; count++) {
+ ret = adc5_gen3_read(adc, sdam_index, ADC5_GEN3_HS, &status, sizeof(status));
+ if (ret)
+ return ret;
+
+ if (status == ADC5_GEN3_HS_READY) {
+ ret = adc5_gen3_read(adc, sdam_index, ADC5_GEN3_CONV_REQ,
+ &conv_req, sizeof(conv_req));
+ if (ret)
+ return ret;
+
+ if (!conv_req)
+ return 0;
+ }
+
+ fsleep(ADC5_GEN3_HS_DELAY_US);
+ }
+
+ pr_err("Setting HS ready bit timed out, sdam_index:%d, status:%#x\n",
+ sdam_index, status);
+ return -ETIMEDOUT;
+}
+EXPORT_SYMBOL_NS_GPL(adc5_gen3_poll_wait_hs, "QCOM_SPMI_ADC5_GEN3");
+
+int adc5_gen3_status_clear(struct adc5_device_data *adc,
+ int sdam_index, u16 offset, u8 *val, int len)
+{
+ u8 value;
+ int ret;
+
+ ret = adc5_gen3_write(adc, sdam_index, offset, val, len);
+ if (ret)
+ return ret;
+
+ /* To indicate conversion request is only to clear a status */
+ value = 0;
+ ret = adc5_gen3_write(adc, sdam_index, ADC5_GEN3_PERPH_CH, &value,
+ sizeof(value));
+ if (ret)
+ return ret;
+
+ value = ADC5_GEN3_CONV_REQ_REQ;
+ return adc5_gen3_write(adc, sdam_index, ADC5_GEN3_CONV_REQ, &value,
+ sizeof(value));
+}
+EXPORT_SYMBOL_NS_GPL(adc5_gen3_status_clear, "QCOM_SPMI_ADC5_GEN3");
+
+/*
+ * Worst case delay from PBS for conversion time can be up to 500ms, when PBS
+ * has timed out twice, once for the initial attempt and once for a retry of
+ * the same transaction.
+ */
+
+#define ADC5_GEN3_CONV_TIMEOUT_MS 501
+
+static int adc5_gen3_do_conversion(struct adc5_chip *adc,
+ struct adc5_channel_common_prop *prop,
+ u16 *data_volt)
+{
+ unsigned long rc;
+ int ret;
+ u8 val;
+
+ guard(mutex)(&adc->lock);
+ ret = adc5_gen3_poll_wait_hs(&adc->dev_data, ADC5_GEN3_VADC_SDAM);
+ if (ret)
+ return ret;
+
+ ret = adc5_gen3_configure(adc, prop);
+ if (ret) {
+ dev_err(adc->dev, "ADC configure failed with %d\n", ret);
+ return ret;
+ }
+
+ /* No support for polling mode at present */
+ rc = wait_for_completion_timeout(&adc->complete,
+ msecs_to_jiffies(ADC5_GEN3_CONV_TIMEOUT_MS));
+ if (!rc) {
+ dev_err(adc->dev, "Reading ADC channel %s timed out\n",
+ prop->label);
+ return -ETIMEDOUT;
+ }
+
+ ret = adc5_gen3_read_voltage_data(adc, data_volt);
+ if (ret)
+ return ret;
+
+ val = BIT(0);
+ return adc5_gen3_status_clear(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
+ ADC5_GEN3_EOC_CLR, &val, 1);
+}
+
+static irqreturn_t adc5_gen3_isr(int irq, void *dev_id)
+{
+ struct adc5_chip *adc = dev_id;
+ struct device *dev = adc->dev;
+ u8 status, eoc_status, val;
+ int ret;
+
+ ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
+ ADC5_GEN3_STATUS1, &status, sizeof(status));
+ if (ret) {
+ dev_err(dev, "adc read status1 failed with %d\n", ret);
+ return IRQ_NONE;
+ }
+
+ ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
+ ADC5_GEN3_EOC_STS, &eoc_status, sizeof(eoc_status));
+ if (ret) {
+ dev_err(dev, "adc read eoc status failed with %d\n", ret);
+ return IRQ_NONE;
+ }
+
+ if (status & ADC5_GEN3_STATUS1_CONV_FAULT) {
+ dev_err_ratelimited(dev,
+ "Unexpected conversion fault, status:%#x, eoc_status:%#x\n",
+ status, eoc_status);
+ val = ADC5_GEN3_CONV_ERR_CLR_REQ;
+ adc5_gen3_status_clear(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
+ ADC5_GEN3_CONV_ERR_CLR, &val, 1);
+ return IRQ_HANDLED;
+ }
+
+ dev_dbg(dev, "Interrupt status:%#x, EOC status:%#x\n", status, eoc_status);
+
+ /* CHAN0 is the preconfigured channel for immediate conversion */
+ if (!(eoc_status & ADC5_GEN3_EOC_CHAN_0))
+ return IRQ_NONE;
+
+ complete(&adc->complete);
+ return IRQ_HANDLED;
+}
+
+static int adc5_gen3_fwnode_xlate(struct iio_dev *indio_dev,
+ const struct fwnode_reference_args *iiospec)
+{
+ struct adc5_chip *adc = iio_priv(indio_dev);
+ int i, v_channel;
+
+ for (i = 0; i < adc->nchannels; i++) {
+ v_channel = ADC5_GEN3_V_CHAN(adc->chan_props[i].common_props);
+ if (v_channel == iiospec->args[0])
+ return i;
+ }
+
+ return -ENOENT;
+}
+
+static int adc5_gen3_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct adc5_chip *adc = iio_priv(indio_dev);
+ struct adc5_channel_common_prop *prop;
+ u16 adc_code_volt;
+ int ret;
+
+ prop = &adc->chan_props[chan->address].common_props;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = adc5_gen3_do_conversion(adc, prop, &adc_code_volt);
+ if (ret)
+ return ret;
+
+ ret = qcom_adc5_hw_scale(prop->scale_fn_type, prop->prescale,
+ adc->data, adc_code_volt, val);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adc5_gen3_read_label(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, char *label)
+{
+ struct adc5_chip *adc = iio_priv(indio_dev);
+ struct adc5_channel_prop *prop;
+
+ prop = &adc->chan_props[chan->address];
+ return sprintf(label, "%s\n", prop->common_props.label);
+}
+
+static const struct iio_info adc5_gen3_info = {
+ .read_raw = adc5_gen3_read_raw,
+ .read_label = adc5_gen3_read_label,
+ .fwnode_xlate = adc5_gen3_fwnode_xlate,
+};
+
+struct adc5_channels {
+ unsigned int prescale_index;
+ enum iio_chan_type type;
+ long info_mask;
+ enum vadc_scale_fn_type scale_fn_type;
+};
+
+/* In these definitions, _pre refers to an index into adc5_prescale_ratios. */
+#define ADC5_CHAN(_type, _mask, _pre, _scale) \
+ { \
+ .prescale_index = _pre, \
+ .type = _type, \
+ .info_mask = _mask, \
+ .scale_fn_type = _scale, \
+ }, \
+
+#define ADC5_CHAN_TEMP(_pre, _scale) \
+ ADC5_CHAN(IIO_TEMP, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \
+
+#define ADC5_CHAN_VOLT(_pre, _scale) \
+ ADC5_CHAN(IIO_VOLTAGE, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \
+
+#define ADC5_CHAN_CUR(_pre, _scale) \
+ ADC5_CHAN(IIO_CURRENT, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \
+
+static const struct adc5_channels adc5_gen3_chans_pmic[ADC5_MAX_CHANNEL] = {
+ [ADC5_GEN3_REF_GND] = ADC5_CHAN_VOLT(0, SCALE_HW_CALIB_DEFAULT)
+ [ADC5_GEN3_1P25VREF] = ADC5_CHAN_VOLT(0, SCALE_HW_CALIB_DEFAULT)
+ [ADC5_GEN3_VPH_PWR] = ADC5_CHAN_VOLT(1, SCALE_HW_CALIB_DEFAULT)
+ [ADC5_GEN3_VBAT_SNS_QBG] = ADC5_CHAN_VOLT(1, SCALE_HW_CALIB_DEFAULT)
+ [ADC5_GEN3_USB_SNS_V_16] = ADC5_CHAN_TEMP(8, SCALE_HW_CALIB_DEFAULT)
+ [ADC5_GEN3_VIN_DIV16_MUX] = ADC5_CHAN_TEMP(8, SCALE_HW_CALIB_DEFAULT)
+ [ADC5_GEN3_DIE_TEMP] = ADC5_CHAN_TEMP(0,
+ SCALE_HW_CALIB_PMIC_THERM_PM7)
+ [ADC5_GEN3_AMUX1_THM_100K_PU] = ADC5_CHAN_TEMP(0,
+ SCALE_HW_CALIB_THERM_100K_PU_PM7)
+ [ADC5_GEN3_AMUX2_THM_100K_PU] = ADC5_CHAN_TEMP(0,
+ SCALE_HW_CALIB_THERM_100K_PU_PM7)
+ [ADC5_GEN3_AMUX3_THM_100K_PU] = ADC5_CHAN_TEMP(0,
+ SCALE_HW_CALIB_THERM_100K_PU_PM7)
+ [ADC5_GEN3_AMUX4_THM_100K_PU] = ADC5_CHAN_TEMP(0,
+ SCALE_HW_CALIB_THERM_100K_PU_PM7)
+ [ADC5_GEN3_AMUX5_THM_100K_PU] = ADC5_CHAN_TEMP(0,
+ SCALE_HW_CALIB_THERM_100K_PU_PM7)
+ [ADC5_GEN3_AMUX6_THM_100K_PU] = ADC5_CHAN_TEMP(0,
+ SCALE_HW_CALIB_THERM_100K_PU_PM7)
+ [ADC5_GEN3_AMUX1_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
+ SCALE_HW_CALIB_THERM_100K_PU_PM7)
+ [ADC5_GEN3_AMUX2_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
+ SCALE_HW_CALIB_THERM_100K_PU_PM7)
+ [ADC5_GEN3_AMUX3_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
+ SCALE_HW_CALIB_THERM_100K_PU_PM7)
+ [ADC5_GEN3_AMUX4_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
+ SCALE_HW_CALIB_THERM_100K_PU_PM7)
+};
+
+static int adc5_gen3_get_fw_channel_data(struct adc5_chip *adc,
+ struct adc5_channel_prop *prop,
+ struct fwnode_handle *fwnode)
+{
+ const char *name = fwnode_get_name(fwnode);
+ const struct adc5_data *data = adc->data;
+ struct device *dev = adc->dev;
+ const char *channel_name;
+ u32 chan, value, sid;
+ u32 varr[2];
+ int ret;
+
+ ret = fwnode_property_read_u32(fwnode, "reg", &chan);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "invalid channel number %s\n",
+ name);
+
+ /*
+ * Value read from "reg" is virtual channel number
+ * virtual channel number = sid << 8 | channel number
+ */
+ sid = FIELD_GET(ADC5_GEN3_VIRTUAL_SID_MASK, chan);
+ chan = FIELD_GET(ADC5_GEN3_CHANNEL_MASK, chan);
+
+ if (chan >= ADC5_MAX_CHANNEL)
+ return dev_err_probe(dev, -EINVAL,
+ "%s invalid channel number %d\n",
+ name, chan);
+
+ prop->common_props.channel = chan;
+ prop->common_props.sid = sid;
+
+ if (!adc->data->adc_chans[chan].info_mask)
+ return dev_err_probe(dev, -EINVAL, "Channel %#x not supported\n", chan);
+
+ channel_name = name;
+ fwnode_property_read_string(fwnode, "label", &channel_name);
+ prop->common_props.label = channel_name;
+
+ value = data->decimation[ADC5_DECIMATION_DEFAULT];
+ fwnode_property_read_u32(fwnode, "qcom,decimation", &value);
+ ret = qcom_adc5_decimation_from_dt(value, data->decimation);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "%#x invalid decimation %d\n",
+ chan, value);
+ prop->common_props.decimation = ret;
+
+ prop->common_props.prescale = adc->data->adc_chans[chan].prescale_index;
+ ret = fwnode_property_read_u32_array(fwnode, "qcom,pre-scaling", varr, 2);
+ if (!ret) {
+ ret = qcom_adc5_prescaling_from_dt(varr[0], varr[1]);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "%#x invalid pre-scaling <%d %d>\n",
+ chan, varr[0], varr[1]);
+ prop->common_props.prescale = ret;
+ }
+
+ value = data->hw_settle_1[VADC_DEF_HW_SETTLE_TIME];
+ fwnode_property_read_u32(fwnode, "qcom,hw-settle-time", &value);
+ ret = qcom_adc5_hw_settle_time_from_dt(value, data->hw_settle_1);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "%#x invalid hw-settle-time %d us\n",
+ chan, value);
+ prop->common_props.hw_settle_time_us = ret;
+
+ value = BIT(VADC_DEF_AVG_SAMPLES);
+ fwnode_property_read_u32(fwnode, "qcom,avg-samples", &value);
+ ret = qcom_adc5_avg_samples_from_dt(value);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "%#x invalid avg-samples %d\n",
+ chan, value);
+ prop->common_props.avg_samples = ret;
+
+ if (fwnode_property_read_bool(fwnode, "qcom,ratiometric"))
+ prop->common_props.cal_method = ADC5_RATIOMETRIC_CAL;
+ else
+ prop->common_props.cal_method = ADC5_ABSOLUTE_CAL;
+
+ prop->adc_tm = fwnode_property_read_bool(fwnode, "qcom,adc-tm");
+ if (prop->adc_tm) {
+ adc->n_tm_channels++;
+ if (adc->n_tm_channels > (adc->dev_data.num_sdams * 8 - 1))
+ return dev_err_probe(dev, -EINVAL,
+ "Number of TM nodes %u greater than channels supported:%u\n",
+ adc->n_tm_channels,
+ adc->dev_data.num_sdams * 8 - 1);
+ }
+
+ return 0;
+}
+
+static const struct adc5_data adc5_gen3_data_pmic = {
+ .full_scale_code_volt = 0x70e4,
+ .adc_chans = adc5_gen3_chans_pmic,
+ .info = &adc5_gen3_info,
+ .decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX])
+ { 85, 340, 1360 },
+ .hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
+ { 15, 100, 200, 300,
+ 400, 500, 600, 700,
+ 1000, 2000, 4000, 8000,
+ 16000, 32000, 64000, 128000 },
+};
+
+static const struct of_device_id adc5_match_table[] = {
+ {
+ .compatible = "qcom,spmi-adc5-gen3",
+ .data = &adc5_gen3_data_pmic,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adc5_match_table);
+
+static int adc5_get_fw_data(struct adc5_chip *adc)
+{
+ const struct adc5_channels *adc_chan;
+ struct adc5_channel_prop *chan_props;
+ struct iio_chan_spec *iio_chan;
+ struct device *dev = adc->dev;
+ unsigned int index = 0;
+ int ret;
+
+ adc->nchannels = device_get_child_node_count(dev);
+ if (!adc->nchannels)
+ return dev_err_probe(dev, -EINVAL, "No ADC channels found\n");
+
+ adc->iio_chans = devm_kcalloc(dev, adc->nchannels,
+ sizeof(*adc->iio_chans), GFP_KERNEL);
+ if (!adc->iio_chans)
+ return -ENOMEM;
+
+ adc->chan_props = devm_kcalloc(dev, adc->nchannels,
+ sizeof(*adc->chan_props), GFP_KERNEL);
+ if (!adc->chan_props)
+ return -ENOMEM;
+
+ chan_props = adc->chan_props;
+ adc->n_tm_channels = 0;
+ iio_chan = adc->iio_chans;
+ adc->data = device_get_match_data(dev);
+
+ device_for_each_child_node_scoped(dev, child) {
+ ret = adc5_gen3_get_fw_channel_data(adc, chan_props, child);
+ if (ret)
+ return ret;
+
+ chan_props->chip = adc;
+ adc_chan = &adc->data->adc_chans[chan_props->common_props.channel];
+ chan_props->common_props.scale_fn_type = adc_chan->scale_fn_type;
+
+ iio_chan->channel = ADC5_GEN3_V_CHAN(chan_props->common_props);
+ iio_chan->info_mask_separate = adc_chan->info_mask;
+ iio_chan->type = adc_chan->type;
+ iio_chan->address = index;
+ iio_chan->indexed = 1;
+ iio_chan++;
+ chan_props++;
+ index++;
+ }
+
+ return 0;
+}
+
+static void adc5_gen3_uninit_aux(void *data)
+{
+ auxiliary_device_uninit(data);
+}
+
+static void adc5_gen3_delete_aux(void *data)
+{
+ auxiliary_device_delete(data);
+}
+
+static void adc5_gen3_aux_device_release(struct device *dev) {}
+
+static int adc5_gen3_add_aux_tm_device(struct adc5_chip *adc)
+{
+ struct tm5_aux_dev_wrapper *aux_device;
+ int i, ret, i_tm = 0;
+
+ aux_device = devm_kzalloc(adc->dev, sizeof(*aux_device), GFP_KERNEL);
+ if (!aux_device)
+ return -ENOMEM;
+
+ aux_device->aux_dev.name = "adc5_tm_gen3";
+ aux_device->aux_dev.dev.parent = adc->dev;
+ aux_device->aux_dev.dev.release = adc5_gen3_aux_device_release;
+
+ aux_device->tm_props = devm_kcalloc(adc->dev, adc->n_tm_channels,
+ sizeof(*aux_device->tm_props),
+ GFP_KERNEL);
+ if (!aux_device->tm_props)
+ return -ENOMEM;
+
+ aux_device->dev_data = &adc->dev_data;
+
+ for (i = 0; i < adc->nchannels; i++) {
+ if (!adc->chan_props[i].adc_tm)
+ continue;
+ aux_device->tm_props[i_tm] = adc->chan_props[i].common_props;
+ i_tm++;
+ }
+
+ device_set_of_node_from_dev(&aux_device->aux_dev.dev, adc->dev);
+
+ aux_device->n_tm_channels = adc->n_tm_channels;
+
+ ret = auxiliary_device_init(&aux_device->aux_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(adc->dev, adc5_gen3_uninit_aux,
+ &aux_device->aux_dev);
+ if (ret)
+ return ret;
+
+ ret = auxiliary_device_add(&aux_device->aux_dev);
+ if (ret)
+ return ret;
+ ret = devm_add_action_or_reset(adc->dev, adc5_gen3_delete_aux,
+ &aux_device->aux_dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void adc5_gen3_mutex_lock(struct device *dev)
+ __acquires(&adc->lock)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
+ struct adc5_chip *adc = iio_priv(indio_dev);
+
+ mutex_lock(&adc->lock);
+}
+EXPORT_SYMBOL_NS_GPL(adc5_gen3_mutex_lock, "QCOM_SPMI_ADC5_GEN3");
+
+void adc5_gen3_mutex_unlock(struct device *dev)
+ __releases(&adc->lock)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
+ struct adc5_chip *adc = iio_priv(indio_dev);
+
+ mutex_unlock(&adc->lock);
+}
+EXPORT_SYMBOL_NS_GPL(adc5_gen3_mutex_unlock, "QCOM_SPMI_ADC5_GEN3");
+
+int adc5_gen3_get_scaled_reading(struct device *dev,
+ struct adc5_channel_common_prop *common_props,
+ int *val)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
+ struct adc5_chip *adc = iio_priv(indio_dev);
+ u16 adc_code_volt;
+ int ret;
+
+ ret = adc5_gen3_do_conversion(adc, common_props, &adc_code_volt);
+ if (ret)
+ return ret;
+
+ return qcom_adc5_hw_scale(common_props->scale_fn_type,
+ common_props->prescale,
+ adc->data, adc_code_volt, val);
+}
+EXPORT_SYMBOL_NS_GPL(adc5_gen3_get_scaled_reading, "QCOM_SPMI_ADC5_GEN3");
+
+int adc5_gen3_therm_code_to_temp(struct device *dev,
+ struct adc5_channel_common_prop *common_props,
+ u16 code, int *val)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
+ struct adc5_chip *adc = iio_priv(indio_dev);
+
+ return qcom_adc5_hw_scale(common_props->scale_fn_type,
+ common_props->prescale,
+ adc->data, code, val);
+}
+EXPORT_SYMBOL_NS_GPL(adc5_gen3_therm_code_to_temp, "QCOM_SPMI_ADC5_GEN3");
+
+static int adc5_gen3_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct adc5_chip *adc;
+ struct regmap *regmap;
+ int ret, i;
+ u32 *reg;
+
+ regmap = dev_get_regmap(dev->parent, NULL);
+ if (!regmap)
+ return -ENODEV;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ adc = iio_priv(indio_dev);
+ adc->dev_data.regmap = regmap;
+ adc->dev = dev;
+
+ ret = device_property_count_u32(dev, "reg");
+ if (ret < 0)
+ return ret;
+
+ adc->dev_data.num_sdams = ret;
+
+ reg = devm_kcalloc(dev, adc->dev_data.num_sdams, sizeof(u32),
+ GFP_KERNEL);
+ if (!reg)
+ return -ENOMEM;
+
+ ret = device_property_read_u32_array(dev, "reg", reg,
+ adc->dev_data.num_sdams);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to read reg property\n");
+
+ adc->dev_data.base = devm_kcalloc(dev, adc->dev_data.num_sdams,
+ sizeof(*adc->dev_data.base),
+ GFP_KERNEL);
+ if (!adc->dev_data.base)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, indio_dev);
+ init_completion(&adc->complete);
+ ret = devm_mutex_init(dev, &adc->lock);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < adc->dev_data.num_sdams; i++) {
+ adc->dev_data.base[i].base_addr = reg[i];
+
+ ret = platform_get_irq(pdev, i);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Getting IRQ %d failed\n", i);
+
+ adc->dev_data.base[i].irq = ret;
+
+ adc->dev_data.base[i].irq_name = devm_kasprintf(dev, GFP_KERNEL,
+ "sdam%d", i);
+ if (!adc->dev_data.base[i].irq_name)
+ return -ENOMEM;
+ }
+
+ /*
+ * This interrupt is shared with the ADC_TM auxiliary driver, which
+ * is threaded and uses IRQF_ONESHOT. Since shared interrupts need
+ * to agree on IRQF_ONESHOT configuration and there is a kernel
+ * warning for using IRQF_ONESHOT with non-threaded interrupts,
+ * make this also a threaded IRQ.
+ */
+ ret = devm_request_threaded_irq(dev, adc->dev_data.base[ADC5_GEN3_VADC_SDAM].irq,
+ NULL, adc5_gen3_isr, IRQF_ONESHOT | IRQF_SHARED,
+ adc->dev_data.base[ADC5_GEN3_VADC_SDAM].irq_name,
+ adc);
+ if (ret)
+ return ret;
+
+ ret = adc5_get_fw_data(adc);
+ if (ret)
+ return ret;
+
+ if (adc->n_tm_channels > 0) {
+ ret = adc5_gen3_add_aux_tm_device(adc);
+ if (ret)
+ dev_err_probe(dev, ret,
+ "Failed to add auxiliary TM device\n");
+ }
+
+ indio_dev->name = "spmi-adc5-gen3";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &adc5_gen3_info;
+ indio_dev->channels = adc->iio_chans;
+ indio_dev->num_channels = adc->nchannels;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static struct platform_driver adc5_gen3_driver = {
+ .driver = {
+ .name = "qcom-spmi-adc5-gen3",
+ .of_match_table = adc5_match_table,
+ },
+ .probe = adc5_gen3_probe,
+};
+module_platform_driver(adc5_gen3_driver);
+
+MODULE_DESCRIPTION("Qualcomm Technologies Inc. PMIC5 Gen3 ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("QCOM_SPMI_ADC5_GEN3");
diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c
index af3c2f659f5e..83ecd3adf65f 100644
--- a/drivers/iio/adc/qcom-spmi-adc5.c
+++ b/drivers/iio/adc/qcom-spmi-adc5.c
@@ -14,7 +14,6 @@
#include <linux/log2.h>
#include <linux/math64.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
diff --git a/drivers/iio/adc/qcom-spmi-iadc.c b/drivers/iio/adc/qcom-spmi-iadc.c
index b64a8a407168..0ec3a0c4b1de 100644
--- a/drivers/iio/adc/qcom-spmi-iadc.c
+++ b/drivers/iio/adc/qcom-spmi-iadc.c
@@ -481,6 +481,11 @@ static const struct iio_chan_spec iadc_channels[] = {
},
};
+static void iadc_disable_irq_wake(void *data)
+{
+ disable_irq_wake((unsigned long)data);
+}
+
static int iadc_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -538,9 +543,16 @@ static int iadc_probe(struct platform_device *pdev)
if (!iadc->poll_eoc) {
ret = devm_request_irq(dev, irq_eoc, iadc_isr, 0,
"spmi-iadc", iadc);
- if (!ret)
- enable_irq_wake(irq_eoc);
- else
+ if (ret)
+ return ret;
+
+ ret = enable_irq_wake(irq_eoc);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, iadc_disable_irq_wake,
+ (void *)(unsigned long)irq_eoc);
+ if (ret)
return ret;
} else {
ret = devm_device_init_wakeup(iadc->dev);
diff --git a/drivers/iio/adc/qcom-spmi-rradc.c b/drivers/iio/adc/qcom-spmi-rradc.c
index 8e75665204d1..1682c6faf62c 100644
--- a/drivers/iio/adc/qcom-spmi-rradc.c
+++ b/drivers/iio/adc/qcom-spmi-rradc.c
@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c
index 00a7f0982025..d7a2df3c810e 100644
--- a/drivers/iio/adc/qcom-spmi-vadc.c
+++ b/drivers/iio/adc/qcom-spmi-vadc.c
@@ -13,7 +13,6 @@
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c
index 3a17b3898bf6..d38cf3caeae0 100644
--- a/drivers/iio/adc/rcar-gyroadc.c
+++ b/drivers/iio/adc/rcar-gyroadc.c
@@ -159,16 +159,6 @@ static const struct iio_chan_spec rcar_gyroadc_iio_channels_3[] = {
RCAR_GYROADC_CHAN(7),
};
-static int rcar_gyroadc_set_power(struct rcar_gyroadc *priv, bool on)
-{
- struct device *dev = priv->dev;
-
- if (on)
- return pm_runtime_resume_and_get(dev);
-
- return pm_runtime_put_autosuspend(dev);
-}
-
static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -200,7 +190,7 @@ static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev,
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
- ret = rcar_gyroadc_set_power(priv, true);
+ ret = pm_runtime_resume_and_get(priv->dev);
if (ret < 0) {
iio_device_release_direct(indio_dev);
return ret;
@@ -209,7 +199,7 @@ static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev,
*val = readl(priv->regs + datareg);
*val &= BIT(priv->sample_width) - 1;
- ret = rcar_gyroadc_set_power(priv, false);
+ ret = pm_runtime_put_autosuspend(priv->dev);
iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
diff --git a/drivers/iio/adc/rohm-bd79112.c b/drivers/iio/adc/rohm-bd79112.c
index 7420aa6627d5..2506fec7be84 100644
--- a/drivers/iio/adc/rohm-bd79112.c
+++ b/drivers/iio/adc/rohm-bd79112.c
@@ -14,7 +14,6 @@
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -530,7 +529,7 @@ static const struct of_device_id bd79112_of_match[] = {
MODULE_DEVICE_TABLE(of, bd79112_of_match);
static const struct spi_device_id bd79112_id[] = {
- { "bd79112" },
+ { .name = "bd79112" },
{ }
};
MODULE_DEVICE_TABLE(spi, bd79112_id);
diff --git a/drivers/iio/adc/rohm-bd79124.c b/drivers/iio/adc/rohm-bd79124.c
index fc0452749b79..ed5427288961 100644
--- a/drivers/iio/adc/rohm-bd79124.c
+++ b/drivers/iio/adc/rohm-bd79124.c
@@ -19,7 +19,6 @@
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/types.h>
@@ -75,7 +74,7 @@
/*
* The high limit, low limit and last measurement result are each stored in
- * 2 consequtive registers. 4 bits are in the high bits of the first register
+ * 2 consecutive registers. 4 bits are in the high bits of the first register
* and 8 bits in the next register.
*
* These macros return the address of the first reg for the given channel.
@@ -962,7 +961,7 @@ static int bd79124_hw_init(struct bd79124_data *data)
if (ret)
return ret;
- /* Enable writing the measured values to the regsters */
+ /* Enable writing the measured values to the registers */
ret = regmap_set_bits(data->map, BD79124_REG_GEN_CFG,
BD79124_MSK_STATS_EN);
if (ret)
@@ -1104,7 +1103,7 @@ static const struct of_device_id bd79124_of_match[] = {
MODULE_DEVICE_TABLE(of, bd79124_of_match);
static const struct i2c_device_id bd79124_id[] = {
- { "bd79124" },
+ { .name = "bd79124" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bd79124_id);
diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c
index 2bf3a09ac6b0..2083c4351e43 100644
--- a/drivers/iio/adc/rtq6056.c
+++ b/drivers/iio/adc/rtq6056.c
@@ -9,7 +9,6 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -728,7 +727,7 @@ static int rtq6056_probe(struct i2c_client *i2c)
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
- devdata = device_get_match_data(dev);
+ devdata = i2c_get_match_data(i2c);
if (!devdata)
return dev_err_probe(dev, -EINVAL, "Invalid dev data\n");
@@ -871,6 +870,13 @@ static const struct richtek_dev_data rtq6059_devdata = {
.set_average = rtq6059_adc_set_average,
};
+static const struct i2c_device_id rtq6056_id[] = {
+ { .name = "rtq6056", .driver_data = (kernel_ulong_t)&rtq6056_devdata },
+ { .name = "rtq6059", .driver_data = (kernel_ulong_t)&rtq6059_devdata },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rtq6056_id);
+
static const struct of_device_id rtq6056_device_match[] = {
{ .compatible = "richtek,rtq6056", .data = &rtq6056_devdata },
{ .compatible = "richtek,rtq6059", .data = &rtq6059_devdata },
@@ -885,6 +891,7 @@ static struct i2c_driver rtq6056_driver = {
.pm = pm_ptr(&rtq6056_pm_ops),
},
.probe = rtq6056_probe,
+ .id_table = rtq6056_id,
};
module_i2c_driver(rtq6056_driver);
diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c
index 1010e0511b3e..408fbf8c29cc 100644
--- a/drivers/iio/adc/rzg2l_adc.c
+++ b/drivers/iio/adc/rzg2l_adc.c
@@ -16,7 +16,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/iio/adc/rzn1-adc.c b/drivers/iio/adc/rzn1-adc.c
index 93b0feef8ea0..f921cd49b789 100644
--- a/drivers/iio/adc/rzn1-adc.c
+++ b/drivers/iio/adc/rzn1-adc.c
@@ -21,7 +21,6 @@
#include <linux/iio/iio.h>
#include <linux/io.h>
#include <linux/iopoll.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
diff --git a/drivers/iio/adc/rzt2h_adc.c b/drivers/iio/adc/rzt2h_adc.c
index 33ce5cc44ff4..4e0eb02d3d14 100644
--- a/drivers/iio/adc/rzt2h_adc.c
+++ b/drivers/iio/adc/rzt2h_adc.c
@@ -9,7 +9,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c
index 9f7a75168aac..def44d8831dc 100644
--- a/drivers/iio/adc/sd_adc_modulator.c
+++ b/drivers/iio/adc/sd_adc_modulator.c
@@ -10,7 +10,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
@@ -77,6 +76,7 @@ static const struct iio_backend_ops sd_backend_ops = {
static const struct iio_backend_info sd_backend_info = {
.name = "sd-modulator",
.ops = &sd_backend_ops,
+ .caps = IIO_BACKEND_CAP_ENABLE,
};
static int iio_sd_mod_register(struct platform_device *pdev)
diff --git a/drivers/iio/adc/sophgo-cv1800b-adc.c b/drivers/iio/adc/sophgo-cv1800b-adc.c
index 0951deb7b111..bdc3e1326a9a 100644
--- a/drivers/iio/adc/sophgo-cv1800b-adc.c
+++ b/drivers/iio/adc/sophgo-cv1800b-adc.c
@@ -15,7 +15,6 @@
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c
index 50b0a607baeb..91c0fb1f4da7 100644
--- a/drivers/iio/adc/spear_adc.c
+++ b/drivers/iio/adc/spear_adc.c
@@ -5,22 +5,24 @@
* Copyright 2012 Stefan Roese <sr@denx.de>
*/
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/property.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/io.h>
+#include <linux/array_size.h>
#include <linux/bitfield.h>
+#include <linux/bits.h>
#include <linux/clk.h>
-#include <linux/err.h>
#include <linux/completion.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/types.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
+#include <linux/iio/types.h>
/* SPEAR registers definitions */
#define SPEAR600_ADC_SCAN_RATE_LO(x) ((x) & 0xFFFF)
@@ -82,7 +84,7 @@ struct spear_adc_state {
* of register writes, then a wait for a completion callback,
* and finally a register read, during which userspace could issue
* another read request. This lock protects a read access from
- * ocurring before another one has finished.
+ * occurring before another one has finished.
*/
struct mutex lock;
u32 current_clk;
@@ -280,6 +282,7 @@ static int spear_adc_probe(struct platform_device *pdev)
st = iio_priv(indio_dev);
st->dev = dev;
+ init_completion(&st->completion);
mutex_init(&st->lock);
/*
@@ -326,8 +329,6 @@ static int spear_adc_probe(struct platform_device *pdev)
spear_adc_configure(st);
- init_completion(&st->completion);
-
indio_dev->name = SPEAR_ADC_MOD_NAME;
indio_dev->info = &spear_adc_info;
indio_dev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index e39a4c0db25e..a42d82d61cb8 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -227,7 +227,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (priv->aclk) {
/*
* Asynchronous clock modes (e.g. ckmode == 0)
- * From spec: PLL output musn't exceed max rate
+ * From spec: PLL output mustn't exceed max rate
*/
rate = clk_get_rate(priv->aclk);
if (!rate) {
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 2d7f88459c7c..5c6c06b269be 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -23,7 +23,6 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/nvmem-consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -1662,7 +1661,7 @@ static irqreturn_t stm32_adc_threaded_isr(int irq, void *data)
/*
* Clear ovr bit to avoid subsequent calls to IRQ handler.
* This requires to stop ADC first. OVR bit state in ISR,
- * is propaged to CSR register by hardware.
+ * is propagated to CSR register by hardware.
*/
adc->cfg->stop_conv(indio_dev);
stm32_adc_irq_clear(indio_dev, regs->isr_ovr.mask);
@@ -2443,15 +2442,7 @@ static int stm32_adc_chan_fw_init(struct iio_dev *indio_dev, bool timestamping)
scan_index = ret;
if (timestamping) {
- struct iio_chan_spec *timestamp = &channels[scan_index];
-
- timestamp->type = IIO_TIMESTAMP;
- timestamp->channel = -1;
- timestamp->scan_index = scan_index;
- timestamp->scan_type.sign = 's';
- timestamp->scan_type.realbits = 64;
- timestamp->scan_type.storagebits = 64;
-
+ channels[scan_index] = IIO_CHAN_SOFT_TIMESTAMP(scan_index);
scan_index++;
}
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index 9664b9bd75d4..00f05e167afc 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -660,11 +660,8 @@ static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm,
}
df_ch->src = val;
- ret = of_property_read_u32_index(indio_dev->dev.of_node,
- "st,adc-alt-channel", chan_idx,
- &df_ch->alt_si);
- if (ret < 0)
- df_ch->alt_si = 0;
+ df_ch->alt_si = of_property_present(indio_dev->dev.of_node,
+ "st,adc-alt-channel");
return 0;
}
@@ -1815,9 +1812,8 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
adc->dfsdm->fl_list[adc->fl_id].ford = val;
- ret = of_property_read_u32(dev->of_node, "st,filter0-sync", &val);
- if (!ret)
- adc->dfsdm->fl_list[adc->fl_id].sync_mode = val;
+ adc->dfsdm->fl_list[adc->fl_id].sync_mode =
+ of_property_read_bool(dev->of_node, "st,filter0-sync");
adc->dev_data = dev_data;
ret = dev_data->init(dev, iio);
diff --git a/drivers/iio/adc/sun20i-gpadc-iio.c b/drivers/iio/adc/sun20i-gpadc-iio.c
index e4dfe76e6362..baa7661db13b 100644
--- a/drivers/iio/adc/sun20i-gpadc-iio.c
+++ b/drivers/iio/adc/sun20i-gpadc-iio.c
@@ -9,7 +9,6 @@
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -55,7 +54,7 @@ struct sun20i_gpadc_iio {
* of register writes, then a wait for a completion callback,
* and finally a register read, during which userspace could issue
* another read request. This lock protects a read access from
- * ocurring before another one has finished.
+ * occurring before another one has finished.
*/
struct mutex lock;
};
@@ -139,8 +138,23 @@ static irqreturn_t sun20i_gpadc_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
+static int
+sun20i_gpadc_fwnode_xlate(struct iio_dev *indio_dev,
+ const struct fwnode_reference_args *iiospec)
+{
+ if (iiospec->nargs != 1)
+ return -EINVAL;
+
+ for (unsigned int i = 0; i < indio_dev->num_channels; i++)
+ if (indio_dev->channels[i].channel == iiospec->args[0])
+ return i;
+
+ return -EINVAL;
+}
+
static const struct iio_info sun20i_gpadc_iio_info = {
.read_raw = sun20i_gpadc_read_raw,
+ .fwnode_xlate = sun20i_gpadc_fwnode_xlate,
};
static void sun20i_gpadc_reset_assert(void *data)
@@ -177,10 +191,10 @@ static int sun20i_gpadc_alloc_channels(struct iio_dev *indio_dev,
static int sun20i_gpadc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct iio_dev *indio_dev;
struct sun20i_gpadc_iio *info;
+ struct clk_bulk_data *clks;
struct reset_control *rst;
- struct clk *clk;
+ struct iio_dev *indio_dev;
int irq;
int ret;
@@ -205,9 +219,11 @@ static int sun20i_gpadc_probe(struct platform_device *pdev)
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
- clk = devm_clk_get_enabled(dev, NULL);
- if (IS_ERR(clk))
- return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock\n");
+ ret = devm_clk_bulk_get_all_enabled(dev, &clks);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to enable clocks\n");
+ if (ret == 0)
+ return dev_err_probe(dev, -ENODEV, "needs at least one clocks\n");
rst = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(rst))
@@ -243,6 +259,7 @@ static int sun20i_gpadc_probe(struct platform_device *pdev)
static const struct of_device_id sun20i_gpadc_of_id[] = {
{ .compatible = "allwinner,sun20i-d1-gpadc" },
+ { .compatible = "allwinner,sun55i-a523-gpadc" },
{ }
};
MODULE_DEVICE_TABLE(of, sun20i_gpadc_of_id);
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 479115ea50bf..203459ca9907 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -679,9 +679,9 @@ static void sun4i_gpadc_remove(struct platform_device *pdev)
}
static const struct platform_device_id sun4i_gpadc_id[] = {
- { "sun4i-a10-gpadc-iio", (kernel_ulong_t)&sun4i_gpadc_data },
- { "sun5i-a13-gpadc-iio", (kernel_ulong_t)&sun5i_gpadc_data },
- { "sun6i-a31-gpadc-iio", (kernel_ulong_t)&sun6i_gpadc_data },
+ { .name = "sun4i-a10-gpadc-iio", .driver_data = (kernel_ulong_t)&sun4i_gpadc_data },
+ { .name = "sun5i-a13-gpadc-iio", .driver_data = (kernel_ulong_t)&sun5i_gpadc_data },
+ { .name = "sun6i-a31-gpadc-iio", .driver_data = (kernel_ulong_t)&sun6i_gpadc_data },
{ }
};
MODULE_DEVICE_TABLE(platform, sun4i_gpadc_id);
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index 8ef51c57912d..2df8f1c21c2a 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -18,7 +18,6 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/iio/iio.h>
@@ -190,18 +189,16 @@ static int adc081c_probe(struct i2c_client *client)
err = devm_iio_triggered_buffer_setup(&client->dev, iio, NULL,
adc081c_trigger_handler, NULL);
- if (err < 0) {
- dev_err(&client->dev, "iio triggered buffer setup failed\n");
- return err;
- }
+ if (err < 0)
+ return dev_err_probe(&client->dev, err, "iio triggered buffer setup failed\n");
return devm_iio_device_register(&client->dev, iio);
}
static const struct i2c_device_id adc081c_id[] = {
- { "adc081c", (kernel_ulong_t)&adc081c_model },
- { "adc101c", (kernel_ulong_t)&adc101c_model },
- { "adc121c", (kernel_ulong_t)&adc121c_model },
+ { .name = "adc081c", .driver_data = (kernel_ulong_t)&adc081c_model },
+ { .name = "adc101c", .driver_data = (kernel_ulong_t)&adc101c_model },
+ { .name = "adc121c", .driver_data = (kernel_ulong_t)&adc121c_model },
{ }
};
MODULE_DEVICE_TABLE(i2c, adc081c_id);
diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c
index cfcdafbe284b..a522d8676034 100644
--- a/drivers/iio/adc/ti-adc0832.c
+++ b/drivers/iio/adc/ti-adc0832.c
@@ -8,7 +8,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
@@ -314,10 +313,10 @@ static const struct of_device_id adc0832_dt_ids[] = {
MODULE_DEVICE_TABLE(of, adc0832_dt_ids);
static const struct spi_device_id adc0832_id[] = {
- { "adc0831", adc0831 },
- { "adc0832", adc0832 },
- { "adc0834", adc0834 },
- { "adc0838", adc0838 },
+ { .name = "adc0831", .driver_data = adc0831 },
+ { .name = "adc0832", .driver_data = adc0832 },
+ { .name = "adc0834", .driver_data = adc0834 },
+ { .name = "adc0838", .driver_data = adc0838 },
{ }
};
MODULE_DEVICE_TABLE(spi, adc0832_id);
diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c
index a100f770fa1c..cf2f6ee59411 100644
--- a/drivers/iio/adc/ti-adc084s021.c
+++ b/drivers/iio/adc/ti-adc084s021.c
@@ -10,7 +10,6 @@
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
@@ -229,10 +228,8 @@ static int adc084s021_probe(struct spi_device *spi)
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
adc084s021_buffer_trigger_handler,
&adc084s021_buffer_setup_ops);
- if (ret) {
- dev_err(&spi->dev, "Failed to setup triggered buffer\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&spi->dev, ret, "Failed to setup triggered buffer\n");
return devm_iio_device_register(&spi->dev, indio_dev);
}
@@ -244,7 +241,7 @@ static const struct of_device_id adc084s021_of_match[] = {
MODULE_DEVICE_TABLE(of, adc084s021_of_match);
static const struct spi_device_id adc084s021_id[] = {
- { ADC084S021_DRIVER_NAME, 0 },
+ { .name = ADC084S021_DRIVER_NAME },
{ }
};
MODULE_DEVICE_TABLE(spi, adc084s021_id);
diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c
index 7d615e2bbf39..10959e835cb8 100644
--- a/drivers/iio/adc/ti-adc108s102.c
+++ b/drivers/iio/adc/ti-adc108s102.c
@@ -20,7 +20,6 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
@@ -277,7 +276,7 @@ static const struct acpi_device_id adc108s102_acpi_ids[] = {
MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids);
static const struct spi_device_id adc108s102_id[] = {
- { "adc108s102", 0 },
+ { .name = "adc108s102" },
{ }
};
MODULE_DEVICE_TABLE(spi, adc108s102_id);
diff --git a/drivers/iio/adc/ti-adc12138.c b/drivers/iio/adc/ti-adc12138.c
index e5ec4b073daa..279e4999eb49 100644
--- a/drivers/iio/adc/ti-adc12138.c
+++ b/drivers/iio/adc/ti-adc12138.c
@@ -516,9 +516,9 @@ static const struct of_device_id adc12138_dt_ids[] = {
MODULE_DEVICE_TABLE(of, adc12138_dt_ids);
static const struct spi_device_id adc12138_id[] = {
- { "adc12130", adc12130 },
- { "adc12132", adc12132 },
- { "adc12138", adc12138 },
+ { .name = "adc12130", .driver_data = adc12130 },
+ { .name = "adc12132", .driver_data = adc12132 },
+ { .name = "adc12138", .driver_data = adc12138 },
{ }
};
MODULE_DEVICE_TABLE(spi, adc12138_id);
diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c
index 4ae65793ad9b..1899813c1aee 100644
--- a/drivers/iio/adc/ti-adc128s052.c
+++ b/drivers/iio/adc/ti-adc128s052.c
@@ -12,7 +12,6 @@
#include <linux/cleanup.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
@@ -248,18 +247,18 @@ static const struct of_device_id adc128_of_match[] = {
MODULE_DEVICE_TABLE(of, adc128_of_match);
static const struct spi_device_id adc128_id[] = {
- { "adc128s052", (kernel_ulong_t)&adc128s_config },
- { "adc122s021", (kernel_ulong_t)&adc122s_config },
- { "adc122s051", (kernel_ulong_t)&adc122s_config },
- { "adc122s101", (kernel_ulong_t)&adc122s_config },
- { "adc124s021", (kernel_ulong_t)&adc124s_config },
- { "adc124s051", (kernel_ulong_t)&adc124s_config },
- { "adc124s101", (kernel_ulong_t)&adc124s_config },
- { "bd79100", (kernel_ulong_t)&bd79100_config },
- { "bd79101", (kernel_ulong_t)&bd79101_config },
- { "bd79102", (kernel_ulong_t)&bd79102_config },
- { "bd79103", (kernel_ulong_t)&bd79104_config },
- { "bd79104", (kernel_ulong_t)&bd79104_config },
+ { .name = "adc128s052", .driver_data = (kernel_ulong_t)&adc128s_config },
+ { .name = "adc122s021", .driver_data = (kernel_ulong_t)&adc122s_config },
+ { .name = "adc122s051", .driver_data = (kernel_ulong_t)&adc122s_config },
+ { .name = "adc122s101", .driver_data = (kernel_ulong_t)&adc122s_config },
+ { .name = "adc124s021", .driver_data = (kernel_ulong_t)&adc124s_config },
+ { .name = "adc124s051", .driver_data = (kernel_ulong_t)&adc124s_config },
+ { .name = "adc124s101", .driver_data = (kernel_ulong_t)&adc124s_config },
+ { .name = "bd79100", .driver_data = (kernel_ulong_t)&bd79100_config },
+ { .name = "bd79101", .driver_data = (kernel_ulong_t)&bd79101_config },
+ { .name = "bd79102", .driver_data = (kernel_ulong_t)&bd79102_config },
+ { .name = "bd79103", .driver_data = (kernel_ulong_t)&bd79104_config },
+ { .name = "bd79104", .driver_data = (kernel_ulong_t)&bd79104_config },
{ }
};
MODULE_DEVICE_TABLE(spi, adc128_id);
diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c
index 28aa6b80160c..422df0685580 100644
--- a/drivers/iio/adc/ti-adc161s626.c
+++ b/drivers/iio/adc/ti-adc161s626.c
@@ -11,10 +11,10 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
+#include <linux/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/buffer.h>
@@ -70,8 +70,7 @@ struct ti_adc_data {
u8 read_size;
u8 shift;
-
- u8 buffer[16] __aligned(IIO_DMA_MINALIGN);
+ u8 buf[3] __aligned(IIO_DMA_MINALIGN);
};
static int ti_adc_read_measurement(struct ti_adc_data *data,
@@ -80,26 +79,20 @@ static int ti_adc_read_measurement(struct ti_adc_data *data,
int ret;
switch (data->read_size) {
- case 2: {
- __be16 buf;
-
- ret = spi_read(data->spi, (void *) &buf, 2);
+ case 2:
+ ret = spi_read(data->spi, data->buf, 2);
if (ret)
return ret;
- *val = be16_to_cpu(buf);
+ *val = get_unaligned_be16(data->buf);
break;
- }
- case 3: {
- __be32 buf;
-
- ret = spi_read(data->spi, (void *) &buf, 3);
+ case 3:
+ ret = spi_read(data->spi, data->buf, 3);
if (ret)
return ret;
- *val = be32_to_cpu(buf) >> 8;
+ *val = get_unaligned_be24(data->buf);
break;
- }
default:
return -EINVAL;
}
@@ -114,15 +107,20 @@ static irqreturn_t ti_adc_trigger_handler(int irq, void *private)
struct iio_poll_func *pf = private;
struct iio_dev *indio_dev = pf->indio_dev;
struct ti_adc_data *data = iio_priv(indio_dev);
- int ret;
+ struct {
+ s16 data;
+ aligned_s64 timestamp;
+ } scan = { };
+ int ret, val;
+
+ ret = ti_adc_read_measurement(data, &indio_dev->channels[0], &val);
+ if (ret)
+ goto exit_notify_done;
- ret = ti_adc_read_measurement(data, &indio_dev->channels[0],
- (int *) &data->buffer);
- if (!ret)
- iio_push_to_buffers_with_timestamp(indio_dev,
- data->buffer,
- iio_get_time_ns(indio_dev));
+ scan.data = val;
+ iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev));
+ exit_notify_done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
@@ -231,8 +229,8 @@ static const struct of_device_id ti_adc_dt_ids[] = {
MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
static const struct spi_device_id ti_adc_id[] = {
- { "adc141s626", TI_ADC141S626 },
- { "adc161s626", TI_ADC161S626 },
+ { .name = "adc141s626", .driver_data = TI_ADC141S626 },
+ { .name = "adc161s626", .driver_data = TI_ADC161S626 },
{ }
};
MODULE_DEVICE_TABLE(spi, ti_adc_id);
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index f2a93c63ca14..0fbfa4e499aa 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -231,7 +231,6 @@ static const struct iio_event_spec ads1015_events[] = {
}
struct ads1015_channel_data {
- bool enabled;
unsigned int pga;
unsigned int data_rate;
};
@@ -931,6 +930,17 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode)
mode << ADS1015_CFG_MOD_SHIFT);
}
+static void ads1015_power_down(void *p)
+{
+ struct ads1015_data *data = p;
+ int ret;
+
+ ret = ads1015_set_conv_mode(data, ADS1015_SINGLESHOT);
+ if (ret)
+ dev_warn(regmap_get_device(data->regmap),
+ "Failed to power down (%pe)\n", ERR_PTR(ret));
+}
+
static int ads1015_probe(struct i2c_client *client)
{
const struct ads1015_chip_data *chip;
@@ -1031,6 +1041,10 @@ static int ads1015_probe(struct i2c_client *client)
if (ret)
return ret;
+ ret = devm_add_action_or_reset(&client->dev, ads1015_power_down, data);
+ if (ret)
+ return ret;
+
data->conv_invalid = true;
ret = pm_runtime_set_active(&client->dev);
@@ -1038,33 +1052,11 @@ static int ads1015_probe(struct i2c_client *client)
return ret;
pm_runtime_set_autosuspend_delay(&client->dev, ADS1015_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
- pm_runtime_enable(&client->dev);
-
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "Failed to register IIO device\n");
+ ret = devm_pm_runtime_enable(&client->dev);
+ if (ret)
return ret;
- }
-
- return 0;
-}
-static void ads1015_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct ads1015_data *data = iio_priv(indio_dev);
- int ret;
-
- iio_device_unregister(indio_dev);
-
- pm_runtime_disable(&client->dev);
- pm_runtime_set_suspended(&client->dev);
-
- /* power down single shot mode */
- ret = ads1015_set_conv_mode(data, ADS1015_SINGLESHOT);
- if (ret)
- dev_warn(&client->dev, "Failed to power down (%pe)\n",
- ERR_PTR(ret));
+ return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM
@@ -1129,9 +1121,9 @@ static const struct ads1015_chip_data tla2024_data = {
};
static const struct i2c_device_id ads1015_id[] = {
- { "ads1015", (kernel_ulong_t)&ads1015_data },
- { "ads1115", (kernel_ulong_t)&ads1115_data },
- { "tla2024", (kernel_ulong_t)&tla2024_data },
+ { .name = "ads1015", .driver_data = (kernel_ulong_t)&ads1015_data },
+ { .name = "ads1115", .driver_data = (kernel_ulong_t)&ads1115_data },
+ { .name = "tla2024", .driver_data = (kernel_ulong_t)&tla2024_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, ads1015_id);
@@ -1151,7 +1143,6 @@ static struct i2c_driver ads1015_driver = {
.pm = &ads1015_pm_ops,
},
.probe = ads1015_probe,
- .remove = ads1015_remove,
.id_table = ads1015_id,
};
diff --git a/drivers/iio/adc/ti-ads1018.c b/drivers/iio/adc/ti-ads1018.c
index 6246b3cab71f..d9ec4a8d7ce5 100644
--- a/drivers/iio/adc/ti-ads1018.c
+++ b/drivers/iio/adc/ti-ads1018.c
@@ -12,7 +12,6 @@
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/math.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
@@ -249,7 +248,7 @@ static int ads1018_single_shot(struct ads1018 *ads1018,
struct iio_chan_spec const *chan, u16 *cnv)
{
u8 max_drate_mode = ads1018->chip_info->num_data_rate_mode_to_hz - 1;
- u8 drate = ads1018->chip_info->data_rate_mode_to_hz[max_drate_mode];
+ u32 drate = ads1018->chip_info->data_rate_mode_to_hz[max_drate_mode];
u8 pga_mode = ads1018->chan_data[chan->scan_index].pga_mode;
struct spi_transfer xfer[2] = {
{
@@ -718,8 +717,8 @@ static const struct of_device_id ads1018_of_match[] = {
MODULE_DEVICE_TABLE(of, ads1018_of_match);
static const struct spi_device_id ads1018_spi_match[] = {
- { "ads1018", (kernel_ulong_t)&ads1018_chip_info },
- { "ads1118", (kernel_ulong_t)&ads1118_chip_info },
+ { .name = "ads1018", .driver_data = (kernel_ulong_t)&ads1018_chip_info },
+ { .name = "ads1118", .driver_data = (kernel_ulong_t)&ads1118_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ads1018_spi_match);
diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c
index aa8946063c7d..9fe8d54cce83 100644
--- a/drivers/iio/adc/ti-ads1100.c
+++ b/drivers/iio/adc/ti-ads1100.c
@@ -400,8 +400,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ads1100_pm_ops,
NULL);
static const struct i2c_device_id ads1100_id[] = {
- { "ads1100" },
- { "ads1000" },
+ { .name = "ads1100" },
+ { .name = "ads1000" },
{ }
};
diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c
index c9cedc59cdcd..b0f04741ddc6 100644
--- a/drivers/iio/adc/ti-ads1119.c
+++ b/drivers/iio/adc/ti-ads1119.c
@@ -274,12 +274,15 @@ static int ads1119_single_conversion(struct ads1119_state *st,
ret = pm_runtime_resume_and_get(dev);
if (ret)
- goto pdown;
+ return ret;
ret = ads1119_configure_channel(st, mux, gain, datarate);
if (ret)
goto pdown;
+ if (st->client->irq)
+ reinit_completion(&st->completion);
+
ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
if (ret)
goto pdown;
@@ -456,7 +459,11 @@ static int ads1119_triggered_buffer_preenable(struct iio_dev *indio_dev)
if (ret)
return ret;
- return i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
+ ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
+ if (ret)
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
}
static int ads1119_triggered_buffer_postdisable(struct iio_dev *indio_dev)
@@ -735,13 +742,10 @@ static int ads1119_probe(struct i2c_client *client)
return dev_err_probe(dev, ret, "Failed to setup IIO buffer\n");
if (client->irq > 0) {
- ret = devm_request_threaded_irq(dev, client->irq,
- ads1119_irq_handler,
- NULL, IRQF_ONESHOT,
- "ads1119", indio_dev);
+ ret = devm_request_irq(dev, client->irq, ads1119_irq_handler,
+ IRQF_NO_THREAD, "ads1119", indio_dev);
if (ret)
- return dev_err_probe(dev, ret,
- "Failed to allocate irq\n");
+ return ret;
st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
@@ -804,7 +808,7 @@ static const struct of_device_id __maybe_unused ads1119_of_match[] = {
MODULE_DEVICE_TABLE(of, ads1119_of_match);
static const struct i2c_device_id ads1119_id[] = {
- { "ads1119" },
+ { .name = "ads1119" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ads1119_id);
diff --git a/drivers/iio/adc/ti-ads112c14.c b/drivers/iio/adc/ti-ads112c14.c
new file mode 100644
index 000000000000..60eab4852ba2
--- /dev/null
+++ b/drivers/iio/adc/ti-ads112c14.c
@@ -0,0 +1,1454 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * IIO driver for Texas Instruments ADS112C14 and similar ADCs.
+ *
+ * Copyright (C) 2026 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2026 Baylibre Inc.
+ *
+ * Datasheet: https://www.ti.com/lit/ds/symlink/ads122c14.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/device/devres.h>
+#include <linux/i2c.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sysfs.h>
+#include <linux/time64.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+#include <linux/units.h>
+
+/* Arbitrary limit since channels are dynamic. */
+#define ADS112C14_MAX_MEASUREMENT_CHANNELS 16
+
+/* Datasheet t_d(RST) - time to wait after reset before next I2C use. */
+#define ADS112C14_DELAY_RESET_US 500
+
+#define ADS112C14_CMD_RDATA 0x00
+#define ADS112C14_CMD_RREG 0x40
+#define ADS112C14_CMD_WREG 0x80
+
+#define ADS112C14_REG_DEVICE_ID 0x00
+#define ADS112C14_DEVICE_ID_BITS GENMASK(3, 0)
+
+#define ADS112C14_REG_REVISION_ID 0x01
+
+#define ADS112C14_REG_STATUS_MSB 0x02
+#define ADS112C14_STATUS_MSB_RESETN BIT(7)
+#define ADS112C14_STATUS_MSB_AVDD_UVN BIT(6)
+#define ADS112C14_STATUS_MSB_REF_UVN BIT(5)
+#define ADS112C14_STATUS_MSB_REG_MAP_CRC_FAULTN BIT(3)
+#define ADS112C14_STATUS_MSB_MEM_FAULTN BIT(2)
+#define ADS112C14_STATUS_MSB_REG_WRITE_FAULTN BIT(1)
+#define ADS112C14_STATUS_MSB_DRDY BIT(0)
+
+#define ADS112C14_REG_STATUS_LSB 0x03
+#define ADS112C14_STATUS_LSB_CONV_COUNT GENMASK(7, 4)
+#define ADS112C14_STATUS_LSB_GPIO3_DAT_IN BIT(3)
+#define ADS112C14_STATUS_LSB_GPIO2_DAT_IN BIT(2)
+#define ADS112C14_STATUS_LSB_GPIO1_DAT_IN BIT(1)
+#define ADS112C14_STATUS_LSB_GPIO0_DAT_IN BIT(0)
+
+#define ADS112C14_REG_CONVERSION_CTRL 0x04
+#define ADS112C14_CONVERSION_CTRL_RESET GENMASK(7, 2)
+#define ADS112C14_CONVERSION_CTRL_START BIT(1)
+#define ADS112C14_CONVERSION_CTRL_STOP BIT(0)
+
+#define ADS112C14_REG_DEVICE_CFG 0x05
+#define ADS112C14_DEVICE_CFG_PWDN BIT(7)
+#define ADS112C14_DEVICE_CFG_STBY_MODE BIT(6)
+#define ADS112C14_DEVICE_CFG_BOCS GENMASK(5, 4)
+#define ADS112C14_DEVICE_CFG_CLK_SEL BIT(3)
+#define ADS112C14_DEVICE_CFG_CONV_MODE BIT(2)
+#define ADS112C14_DEVICE_CFG_CONV_MODE_CONTINUOUS 0
+#define ADS112C14_DEVICE_CFG_CONV_MODE_SINGLE_SHOT 1
+#define ADS112C14_DEVICE_CFG_SPEED_MODE GENMASK(1, 0)
+
+#define ADS112C14_REG_DATA_RATE_CFG 0x06
+#define ADS112C14_DATA_RATE_CFG_DELAY GENMASK(7, 4)
+#define ADS112C14_DATA_RATE_CFG_GC_EN BIT(3)
+#define ADS112C14_DATA_RATE_CFG_FLTR_OSR GENMASK(2, 0)
+
+#define ADS112C14_REG_MUX_CFG 0x07
+#define ADS112C14_MUX_CFG_AINP GENMASK(7, 4)
+#define ADS112C14_MUX_CFG_AINN GENMASK(3, 0)
+#define ADS112C14_MUX_CFG_AIN_GND 8
+
+#define ADS112C14_REG_GAIN_CFG 0x08
+#define ADS112C14_GAIN_CFG_SPARE BIT(7)
+#define ADS112C14_GAIN_CFG_SYS_MON GENMASK(6, 4)
+#define ADS112C14_GAIN_CFG_GAIN GENMASK(3, 0)
+
+#define ADS112C14_REG_REFERENCE_CFG 0x09
+#define ADS112C14_REFERENCE_CFG_REF_UV_EN BIT(7)
+#define ADS112C14_REFERENCE_CFG_REFP_BUF_EN BIT(5)
+#define ADS112C14_REFERENCE_CFG_REFN_BUF_EN BIT(4)
+#define ADS112C14_REFERENCE_CFG_REF_VAL BIT(2)
+#define ADS112C14_REFERENCE_CFG_REF_VAL_1_25V 0
+#define ADS112C14_REFERENCE_CFG_REF_VAL_2_5V 1
+#define ADS112C14_REFERENCE_CFG_REF_SEL GENMASK(1, 0)
+#define ADS112C14_REFERENCE_CFG_REF_SEL_INTERNAL 0
+#define ADS112C14_REFERENCE_CFG_REF_SEL_EXTERNAL 1
+#define ADS112C14_REFERENCE_CFG_REF_SEL_AVDD 2
+
+#define ADS112C14_REG_DIGITAL_CFG 0x0A
+#define ADS112C14_DIGITAL_CFG_REG_MAP_CRC_EN BIT(6)
+#define ADS112C14_DIGITAL_CFG_I2C_CRC_EN BIT(5)
+#define ADS112C14_DIGITAL_CFG_STATUS_EN BIT(4)
+#define ADS112C14_DIGITAL_CFG_FAULT_PIN_BEHAVIOR BIT(3)
+#define ADS112C14_DIGITAL_CFG_CODING BIT(1)
+
+#define ADS112C14_REG_GPIO_CFG 0x0B
+#define ADS112C14_GPIO_CFG_GPIO3_CFG GENMASK(7, 6)
+#define ADS112C14_GPIO_CFG_GPIO2_CFG GENMASK(5, 4)
+#define ADS112C14_GPIO_CFG_GPIO1_CFG GENMASK(3, 2)
+#define ADS112C14_GPIO_CFG_GPIO0_CFG GENMASK(1, 0)
+
+#define ADS112C14_REG_GPIO_DATA_OUTPUT 0x0C
+#define ADS112C14_GPIO_DATA_OUTPUT_GPIO3_SRC BIT(7)
+#define ADS112C14_GPIO_DATA_OUTPUT_GPIO2_SRC BIT(6)
+#define ADS112C14_GPIO_DATA_OUTPUT_GPIO3_DAT_OUT BIT(3)
+#define ADS112C14_GPIO_DATA_OUTPUT_GPIO2_DAT_OUT BIT(2)
+#define ADS112C14_GPIO_DATA_OUTPUT_GPIO1_DAT_OUT BIT(1)
+#define ADS112C14_GPIO_DATA_OUTPUT_GPIO0_DAT_OUT BIT(0)
+
+#define ADS112C14_REG_IDAC_MAG_CFG 0x0D
+#define ADS112C14_IDAC_MAG_CFG_I2MAG GENMASK(7, 4)
+#define ADS112C14_IDAC_MAG_CFG_I1MAG GENMASK(3, 0)
+
+#define ADS112C14_REG_IDAC_MUX_CFG 0x0E
+#define ADS112C14_IDAC_MUX_CFG_IUNIT BIT(7)
+#define ADS112C14_IDAC_MUX_CFG_I2MUX GENMASK(6, 4)
+#define ADS112C14_IDAC_MUX_CFG_I1MUX GENMASK(2, 0)
+
+#define ADS112C14_REG_REG_MAP_CRC 0x0F
+
+#define ADS112C14_INT_REF0_mV 1250
+#define ADS112C14_INT_REF1_mV 2500
+
+enum {
+ ADS112C14_VREF_SOURCE_INTERNAL_2_5V,
+ ADS112C14_VREF_SOURCE_INTERNAL_1_25V,
+ ADS112C14_VREF_SOURCE_EXTERNAL,
+ ADS112C14_VREF_SOURCE_AVDD,
+};
+
+static const char * const ads112c14_vref_source_names[] = {
+ [ADS112C14_VREF_SOURCE_INTERNAL_2_5V] = "internal-2.5v",
+ [ADS112C14_VREF_SOURCE_INTERNAL_1_25V] = "internal-1.25v",
+ [ADS112C14_VREF_SOURCE_EXTERNAL] = "external",
+ [ADS112C14_VREF_SOURCE_AVDD] = "avdd",
+};
+
+/*
+ * Available gains as tenths (e.g. value 5 == 0.5 gain). Indexes correspond to
+ * ADS112C14_GAIN_CFG_GAIN values.
+ */
+static const u32 ads112c14_pga_gains_x10[] = {
+ 5, 10, 20, 40, 50, 80, 100, 160, /* 0 - 7 */
+ 200, 320, 500, 640, 1000, 1280, 2000, 2560, /* 8 - 15 */
+};
+
+#define ADS112C14_I2C_CRC8_POLYNOMIAL 0x07
+DECLARE_CRC8_TABLE(ads112c14_crc8_table);
+
+struct ads112c14_chip_info {
+ const char *name;
+ u8 device_id;
+ u32 resolution_bits;
+};
+
+/* Fixed channels for system monitor measurements. */
+
+#define ADS112C14_SYS_MON_CHANNEL_BASE 100
+
+enum {
+ ADS112C14_SYS_MON_CHANNEL_TEMP = ADS112C14_SYS_MON_CHANNEL_BASE,
+ ADS112C14_SYS_MON_CHANNEL_EXT_REF,
+ ADS112C14_SYS_MON_CHANNEL_AVDD,
+ ADS112C14_SYS_MON_CHANNEL_DVDD,
+ ADS112C14_SYS_MON_CHANNEL_SHORT,
+};
+
+static const struct iio_chan_spec ads112c14_sys_mon_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = ADS112C14_SYS_MON_CHANNEL_TEMP,
+ .address = 2,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
+ | BIT(IIO_CHAN_INFO_SCALE)
+ | BIT(IIO_CHAN_INFO_OFFSET),
+ },
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = ADS112C14_SYS_MON_CHANNEL_EXT_REF,
+ .address = 3,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
+ | BIT(IIO_CHAN_INFO_SCALE),
+ },
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = ADS112C14_SYS_MON_CHANNEL_AVDD,
+ .address = 4,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
+ | BIT(IIO_CHAN_INFO_SCALE),
+ },
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = ADS112C14_SYS_MON_CHANNEL_DVDD,
+ .address = 5,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
+ | BIT(IIO_CHAN_INFO_SCALE),
+ },
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = ADS112C14_SYS_MON_CHANNEL_SHORT,
+ .channel2 = ADS112C14_SYS_MON_CHANNEL_SHORT,
+ .differential = 1,
+ .address = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
+ | BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+struct ads112c14_measurement {
+ const char *label;
+ u32 vref_source;
+ u8 iunit;
+ u8 idac1_mag;
+ u8 idac2_mag;
+ u8 idac1_mux;
+ u8 idac2_mux;
+ u8 iadc_count;
+ u8 gain_val;
+ bool global_chop;
+ bool bipolar;
+ int scale_available[ARRAY_SIZE(ads112c14_pga_gains_x10)][2];
+};
+
+struct ads112c14_data {
+ const struct ads112c14_chip_info *chip_info;
+ struct regmap *regmap;
+ /* Synchronizes access to register value fields. */
+ struct mutex lock;
+ bool i2c_crc_enabled;
+ u32 avdd_uV;
+ u32 ext_ref_uV;
+ bool refp_is_avdd;
+ bool refn_is_gnd;
+ u32 ext_ref_ohms;
+ struct ads112c14_measurement *measurements;
+ u32 num_measurements;
+ u8 sys_mon_chan_short_gain_val;
+ int sys_mon_chan_short_scale_available[ARRAY_SIZE(ads112c14_pga_gains_x10)][2];
+ IIO_DECLARE_BUFFER_WITH_TS(__be32, scan, ADS112C14_MAX_MEASUREMENT_CHANNELS +
+ ARRAY_SIZE(ads112c14_sys_mon_channels));
+};
+
+static bool ads112c14_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ADS112C14_REG_DEVICE_ID:
+ case ADS112C14_REG_REVISION_ID:
+ case ADS112C14_REG_STATUS_LSB:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static bool ads112c14_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ADS112C14_REG_STATUS_MSB:
+ case ADS112C14_REG_STATUS_LSB:
+ case ADS112C14_REG_CONVERSION_CTRL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct reg_default ads112c14_reg_defaults[] = {
+ { ADS112C14_REG_DEVICE_CFG, 0 },
+ { ADS112C14_REG_DATA_RATE_CFG, 0 },
+ { ADS112C14_REG_MUX_CFG, 0 },
+ { ADS112C14_REG_GAIN_CFG, FIELD_PREP_CONST(ADS112C14_GAIN_CFG_GAIN, 1) },
+ { ADS112C14_REG_REFERENCE_CFG, 0 },
+ { ADS112C14_REG_DIGITAL_CFG, 0 },
+ { ADS112C14_REG_GPIO_CFG, 0 },
+ { ADS112C14_REG_GPIO_DATA_OUTPUT, 0 },
+ { ADS112C14_REG_IDAC_MAG_CFG, 0 },
+ { ADS112C14_REG_IDAC_MUX_CFG, FIELD_PREP_CONST(ADS112C14_IDAC_MUX_CFG_I2MUX, 1) },
+};
+
+/**
+ * ads112c14_i2c_read_bytes() - Read bytes from the device over I2C
+ * @client: I2C client for the device
+ * @cmd: Command to send to the device before reading
+ * @buf: Buffer to store the read bytes
+ * @len: Number of bytes to read
+ * @use_crc: Whether to use CRC8 for data integrity check
+ *
+ * If I2C_CRC is enabled, @use_crc may be set to true to perform a CRC8 check
+ * on the received data.
+ */
+static int ads112c14_i2c_read_bytes(struct i2c_client *client, u8 cmd,
+ u8 *buf, u8 len, bool use_crc)
+{
+ u8 rx_buf[4]; /* Up to 3 data bytes + 1 CRC byte. */
+ u8 rx_len;
+ int ret;
+
+ rx_len = len + (use_crc ? 1 : 0);
+
+ if (rx_len > sizeof(rx_buf))
+ return -EINVAL;
+
+ ret = i2c_smbus_read_i2c_block_data(client, cmd, rx_len, rx_buf);
+ if (ret < 0)
+ return ret;
+
+ if (use_crc) {
+ u8 crc = crc8(ads112c14_crc8_table, rx_buf, len, CRC8_INIT_VALUE);
+
+ if (crc != rx_buf[len])
+ return -EBADMSG;
+ }
+
+ memcpy(buf, rx_buf, len);
+
+ return 0;
+}
+
+/**
+ * ads112c14_regmap_bus_read() - Read a register from the device
+ * @context: Pointer to the device context
+ * @reg_buf: Register address to read
+ * @reg_size: Size of the register address (should be 1)
+ * @val_buf: Buffer to store the read value
+ * @val_size: Size of the value to read
+ *
+ * Custom regmap read function that also does CRC check when enabled.
+ */
+static int ads112c14_regmap_bus_read(void *context, const void *reg_buf,
+ size_t reg_size, void *val_buf,
+ size_t val_size)
+{
+ struct ads112c14_data *data = context;
+ struct device *dev = regmap_get_device(data->regmap);
+ struct i2c_client *client = to_i2c_client(dev);
+ const u8 *cmd = reg_buf;
+
+ if (reg_size != 1)
+ return -EINVAL;
+
+ return ads112c14_i2c_read_bytes(client, cmd[0], val_buf, val_size,
+ data->i2c_crc_enabled);
+}
+
+/**
+ * ads112c14_regmap_bus_write() - Write a register to the device
+ * @context: Pointer to the device context
+ * @data_buf: Buffer containing the register address and value to write
+ * @count: Number of bytes to write
+ *
+ * Custom regmap write function that also does readback with CRC check of
+ * nonvolatile registers when CRC is enabled.
+ */
+static int ads112c14_regmap_bus_write(void *context, const void *data_buf,
+ size_t count)
+{
+ struct ads112c14_data *data = context;
+ struct device *dev = regmap_get_device(data->regmap);
+ struct i2c_client *client = to_i2c_client(dev);
+ const u8 *tx = data_buf;
+ u8 reg, readback;
+ int ret;
+
+ if (count != 2)
+ return -EINVAL;
+
+ ret = i2c_smbus_write_byte_data(client, tx[0], tx[1]);
+ if (ret)
+ return ret;
+
+ reg = tx[0] & ~ADS112C14_CMD_WREG;
+
+ if (!data->i2c_crc_enabled || ads112c14_volatile_reg(dev, reg))
+ return 0;
+
+ ret = ads112c14_i2c_read_bytes(client, reg | ADS112C14_CMD_RREG,
+ &readback, sizeof(readback), true);
+ if (ret)
+ return ret;
+
+ if (readback != tx[1])
+ return -EIO;
+
+ return 0;
+}
+
+static const struct regmap_bus ads112c14_regmap_bus = {
+ .read = ads112c14_regmap_bus_read,
+ .write = ads112c14_regmap_bus_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_BIG,
+ .val_format_endian_default = REGMAP_ENDIAN_BIG,
+};
+
+static const struct regmap_config ads112c14_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .read_flag_mask = ADS112C14_CMD_RREG,
+ .write_flag_mask = ADS112C14_CMD_WREG,
+ .max_register = ADS112C14_REG_REG_MAP_CRC,
+ .writeable_reg = ads112c14_writeable_reg,
+ .volatile_reg = ads112c14_volatile_reg,
+ .reg_defaults = ads112c14_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(ads112c14_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int ads112c14_prepare_measurement_channel(struct ads112c14_data *data,
+ const struct iio_chan_spec *chan)
+{
+ struct ads112c14_measurement *measurement = &data->measurements[chan->scan_index];
+ u32 refp_buf_en, refn_buf_en, ref_val, ref_sel;
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, ADS112C14_REG_MUX_CFG,
+ ADS112C14_MUX_CFG_AINP | ADS112C14_MUX_CFG_AINN,
+ FIELD_PREP(ADS112C14_MUX_CFG_AINP, chan->channel) |
+ FIELD_PREP(ADS112C14_MUX_CFG_AINN, chan->channel2));
+ if (ret)
+ return ret;
+
+ ret = regmap_assign_bits(data->regmap, ADS112C14_REG_DIGITAL_CFG,
+ ADS112C14_DIGITAL_CFG_CODING,
+ !measurement->bipolar);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, ADS112C14_REG_GAIN_CFG,
+ ADS112C14_GAIN_CFG_SYS_MON |
+ ADS112C14_GAIN_CFG_GAIN,
+ FIELD_PREP(ADS112C14_GAIN_CFG_SYS_MON, 0) |
+ FIELD_PREP(ADS112C14_GAIN_CFG_GAIN,
+ measurement->gain_val));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, ADS112C14_REG_IDAC_MAG_CFG,
+ ADS112C14_IDAC_MAG_CFG_I2MAG |
+ ADS112C14_IDAC_MAG_CFG_I1MAG,
+ FIELD_PREP(ADS112C14_IDAC_MAG_CFG_I2MAG,
+ measurement->idac2_mag) |
+ FIELD_PREP(ADS112C14_IDAC_MAG_CFG_I1MAG,
+ measurement->idac1_mag));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, ADS112C14_REG_IDAC_MUX_CFG,
+ ADS112C14_IDAC_MUX_CFG_IUNIT |
+ ADS112C14_IDAC_MUX_CFG_I2MUX |
+ ADS112C14_IDAC_MUX_CFG_I1MUX,
+ FIELD_PREP(ADS112C14_IDAC_MUX_CFG_IUNIT,
+ measurement->iunit) |
+ FIELD_PREP(ADS112C14_IDAC_MUX_CFG_I2MUX,
+ measurement->idac2_mux) |
+ FIELD_PREP(ADS112C14_IDAC_MUX_CFG_I1MUX,
+ measurement->idac1_mux));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, ADS112C14_REG_DATA_RATE_CFG,
+ ADS112C14_DATA_RATE_CFG_GC_EN,
+ FIELD_PREP(ADS112C14_DATA_RATE_CFG_GC_EN,
+ measurement->global_chop));
+ if (ret)
+ return ret;
+
+ refp_buf_en = !data->refp_is_avdd &&
+ measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL;
+ refn_buf_en = !data->refn_is_gnd &&
+ measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL;
+
+ ref_val = measurement->vref_source == ADS112C14_VREF_SOURCE_INTERNAL_2_5V ?
+ ADS112C14_REFERENCE_CFG_REF_VAL_2_5V :
+ ADS112C14_REFERENCE_CFG_REF_VAL_1_25V;
+
+ switch (measurement->vref_source) {
+ case ADS112C14_VREF_SOURCE_AVDD:
+ ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_AVDD;
+ break;
+ case ADS112C14_VREF_SOURCE_EXTERNAL:
+ ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_EXTERNAL;
+ break;
+ default:
+ ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_INTERNAL;
+ break;
+ }
+
+ return regmap_update_bits(data->regmap, ADS112C14_REG_REFERENCE_CFG,
+ ADS112C14_REFERENCE_CFG_REFP_BUF_EN |
+ ADS112C14_REFERENCE_CFG_REFN_BUF_EN |
+ ADS112C14_REFERENCE_CFG_REF_VAL |
+ ADS112C14_REFERENCE_CFG_REF_SEL,
+ FIELD_PREP(ADS112C14_REFERENCE_CFG_REFP_BUF_EN,
+ refp_buf_en) |
+ FIELD_PREP(ADS112C14_REFERENCE_CFG_REFN_BUF_EN,
+ refn_buf_en) |
+ FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_VAL,
+ ref_val) |
+ FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_SEL,
+ ref_sel));
+}
+
+static int ads112c14_prepare_sys_mon_channel(struct ads112c14_data *data,
+ const struct iio_chan_spec *chan)
+{
+ u32 gain_val;
+ int ret;
+
+ /*
+ * NB: IDAC registers are left as-is in case they are generating current
+ * needed for the external reference measurement.
+ */
+
+ /*
+ * All SYS_MON channels use GAIN of 1 to keep it simple. Other than
+ * the internal short channel, where it is useful in practice.
+ */
+ gain_val = chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT ?
+ data->sys_mon_chan_short_gain_val : 1;
+
+ ret = regmap_update_bits(data->regmap, ADS112C14_REG_GAIN_CFG,
+ ADS112C14_GAIN_CFG_SYS_MON |
+ ADS112C14_GAIN_CFG_GAIN,
+ FIELD_PREP(ADS112C14_GAIN_CFG_SYS_MON, chan->address) |
+ FIELD_PREP(ADS112C14_GAIN_CFG_GAIN, gain_val));
+ if (ret)
+ return ret;
+
+ /* All SYS_MON channels use signed data to keep it simple. */
+ ret = regmap_clear_bits(data->regmap, ADS112C14_REG_DIGITAL_CFG,
+ ADS112C14_DIGITAL_CFG_CODING);
+ if (ret)
+ return ret;
+
+ /*
+ * REVISIT: if we implement regulator support for the REFOUT pin, we
+ * might need to make this voltage match what is required by that. In
+ * that case, we could also adjust GAIN so that we still get the same
+ * range.
+ */
+ /*
+ * NB: SYS_MON channels ignore REF_SEL except for the shorted input
+ * channel, so we set it here to internal reference to be consistent.
+ * If we ever need to make a measurement of shorted input with other
+ * reference source, we could add additional channels for that.
+ */
+ ret = regmap_update_bits(data->regmap, ADS112C14_REG_REFERENCE_CFG,
+ ADS112C14_REFERENCE_CFG_REF_VAL |
+ ADS112C14_REFERENCE_CFG_REF_SEL,
+ FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_VAL,
+ ADS112C14_REFERENCE_CFG_REF_VAL_2_5V) |
+ FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_SEL,
+ ADS112C14_REFERENCE_CFG_REF_SEL_INTERNAL));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ads112c14_single_conversion(struct ads112c14_data *data,
+ const struct iio_chan_spec *chan,
+ u8 *buf, bool for_scan)
+{
+ struct i2c_client *client = to_i2c_client(regmap_get_device(data->regmap));
+ u32 reg_val;
+ int ret;
+
+ guard(mutex)(&data->lock);
+
+ if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) {
+ ret = ads112c14_prepare_measurement_channel(data, chan);
+ if (ret)
+ return ret;
+ } else {
+ ret = ads112c14_prepare_sys_mon_channel(data, chan);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_write(data->regmap, ADS112C14_REG_CONVERSION_CTRL,
+ ADS112C14_CONVERSION_CTRL_START);
+ if (ret)
+ return ret;
+
+ ret = regmap_read_poll_timeout(data->regmap,
+ ADS112C14_REG_STATUS_MSB, reg_val,
+ FIELD_GET(ADS112C14_STATUS_MSB_DRDY, reg_val),
+ 1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC);
+ if (ret)
+ return ret;
+
+ /*
+ * When doing buffered read, we don't check the CRC, but rather pass it
+ * along with the raw data. This way, we don't silently drop samples
+ * with CRC errors, but rather leave it to userspace to decide what to
+ * do.
+ */
+ if (for_scan) {
+ u8 len = BITS_TO_BYTES(data->chip_info->resolution_bits) +
+ (data->i2c_crc_enabled ? 1 : 0);
+
+ ret = i2c_smbus_read_i2c_block_data(client, ADS112C14_CMD_RDATA,
+ len, buf);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+ }
+
+ return ads112c14_i2c_read_bytes(client, ADS112C14_CMD_RDATA, buf,
+ BITS_TO_BYTES(data->chip_info->resolution_bits),
+ data->i2c_crc_enabled);
+}
+
+static int ads112c14_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ads112c14_data *data = iio_priv(indio_dev);
+ struct ads112c14_measurement *measurement = NULL;
+ const int *scale_avail;
+ u32 vref_uV, fsr_bits;
+
+ /* Selecting V_REF source is not implemented yet. */
+ vref_uV = ADS112C14_INT_REF1_mV * (MICRO / MILLI);
+
+ if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) {
+ measurement = &data->measurements[chan->scan_index];
+ fsr_bits = data->chip_info->resolution_bits - measurement->bipolar;
+ } else {
+ /* All SYS_MON channels are using signed coding. */
+ fsr_bits = data->chip_info->resolution_bits - 1;
+ }
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW: {
+ u8 buf[3];
+ int ret;
+
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
+
+ ret = ads112c14_single_conversion(data, chan, buf, false);
+ if (ret)
+ return ret;
+
+ switch (data->chip_info->resolution_bits) {
+ case 16:
+ *val = get_unaligned_be16(buf);
+ break;
+ case 24:
+ *val = get_unaligned_be24(buf);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!measurement || measurement->bipolar)
+ *val = sign_extend32(*val, fsr_bits);
+
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type == IIO_TEMP) {
+ /* TS_TC (typical) = 405 uV/°C */
+ *val = MILLI * vref_uV / 405;
+ *val2 = fsr_bits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ }
+
+ if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) {
+ guard(mutex)(&data->lock);
+
+ scale_avail = measurement->scale_available[measurement->gain_val];
+ *val = scale_avail[0];
+ *val2 = scale_avail[1];
+
+ return IIO_VAL_DECIMAL64_PICO;
+ }
+
+ if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) {
+ u8 idx;
+
+ guard(mutex)(&data->lock);
+
+ idx = data->sys_mon_chan_short_gain_val;
+ scale_avail = data->sys_mon_chan_short_scale_available[idx];
+ *val = scale_avail[0];
+ *val2 = scale_avail[1];
+
+ return IIO_VAL_DECIMAL64_PICO;
+ }
+
+ *val = vref_uV / (MICRO / MILLI);
+
+ /*
+ * Some SYS_MON channels (ext ref, AVDD, DVDD) need to be
+ * multiplied by 8 to account for internal attenuation of / 8.
+ */
+ switch (chan->address) {
+ case 3 ... 5:
+ *val2 = fsr_bits - 3;
+ break;
+ default:
+ *val2 = fsr_bits;
+ break;
+ }
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OFFSET:
+ /* Only the temperature channel has an offset. */
+ if (chan->type != IIO_TEMP)
+ return -EINVAL;
+ /*
+ * Die temperature [°C] = 25°C + (Measured voltage – TS_Offset) / TS_TC
+ * TS_TC (typical) = 405 uV/°C
+ * TS_Offset (typical) = 119.5 mV
+ */
+ *val = div_s64((s64)(25 * 405 - 119500) * BIT(fsr_bits), vref_uV);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ads112c14_read_avail(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, const int **vals,
+ int *type, int *length, long mask)
+{
+ struct ads112c14_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) {
+ struct ads112c14_measurement *measurement;
+
+ guard(mutex)(&data->lock);
+
+ measurement = &data->measurements[chan->scan_index];
+ *vals = (const int *)measurement->scale_available;
+ *length = 2 * ARRAY_SIZE(measurement->scale_available);
+ *type = IIO_VAL_DECIMAL64_PICO;
+ return IIO_AVAIL_LIST;
+ }
+
+ if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) {
+ guard(mutex)(&data->lock);
+
+ *vals = (const int *)data->sys_mon_chan_short_scale_available;
+ *length = 2 * ARRAY_SIZE(data->sys_mon_chan_short_scale_available);
+ *type = IIO_VAL_DECIMAL64_PICO;
+ return IIO_AVAIL_LIST;
+ }
+
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ads112c14_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct ads112c14_data *data = iio_priv(indio_dev);
+ const int (*scale_avail)[2];
+ u8 *gain_val;
+
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE: {
+ guard(mutex)(&data->lock);
+
+ if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) {
+ struct ads112c14_measurement *measurement;
+
+ measurement = &data->measurements[chan->scan_index];
+ scale_avail = measurement->scale_available;
+ gain_val = &measurement->gain_val;
+ } else if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) {
+ scale_avail = data->sys_mon_chan_short_scale_available;
+ gain_val = &data->sys_mon_chan_short_gain_val;
+ } else {
+ return -EINVAL;
+ }
+
+ for (u32 i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) {
+ if (iio_val_s64_compose(val, val2) ==
+ iio_val_s64_compose(scale_avail[i][0], scale_avail[i][1])) {
+ *gain_val = i;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ads112c14_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_DECIMAL64_PICO;
+ default:
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+}
+
+static int ads112c14_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg,
+ unsigned int writeval,
+ unsigned int *readval)
+{
+ struct ads112c14_data *data = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(data->regmap, reg, readval);
+
+ return regmap_write(data->regmap, reg, writeval);
+}
+
+static int ads112c14_read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, char *label)
+{
+ struct ads112c14_data *data = iio_priv(indio_dev);
+ const char *label_source;
+
+ /* measurement channels */
+ if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) {
+ struct ads112c14_measurement *measurement;
+
+ measurement = &data->measurements[chan->scan_index];
+ if (!measurement->label)
+ return -EINVAL;
+
+ return sysfs_emit(label, "%s\n", measurement->label);
+ }
+
+ /* System monitor channels. */
+ switch (chan->channel) {
+ case ADS112C14_SYS_MON_CHANNEL_TEMP:
+ label_source = "Internal temperature sensor";
+ break;
+ case ADS112C14_SYS_MON_CHANNEL_EXT_REF:
+ label_source = "External reference";
+ break;
+ case ADS112C14_SYS_MON_CHANNEL_AVDD:
+ label_source = "AVDD";
+ break;
+ case ADS112C14_SYS_MON_CHANNEL_DVDD:
+ label_source = "DVDD";
+ break;
+ case ADS112C14_SYS_MON_CHANNEL_SHORT:
+ label_source = "Internal short (internal reference source)";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return sysfs_emit(label, "%s\n", label_source);
+}
+
+static irqreturn_t ads112c14_trigger_handler(int irq, void *private)
+{
+ struct iio_poll_func *pf = private;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ads112c14_data *data = iio_priv(indio_dev);
+ u32 offset = 0;
+ u32 i;
+ int ret;
+
+ iio_for_each_active_channel(indio_dev, i) {
+ const struct iio_chan_spec *chan = &indio_dev->channels[i];
+
+ ret = ads112c14_single_conversion(data, chan,
+ (u8 *)&data->scan[offset++],
+ true);
+ if (ret) {
+ dev_err_once(indio_dev->dev.parent,
+ "failed to read channel %d: %pe; additional errors will be suppressed\n",
+ chan->channel, ERR_PTR(ret));
+ goto out;
+ }
+ }
+
+ iio_push_to_buffers_with_ts(indio_dev, data->scan,
+ sizeof(data->scan), pf->timestamp);
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_info ads112c14_info = {
+ .read_raw = ads112c14_read_raw,
+ .read_avail = ads112c14_read_avail,
+ .write_raw = ads112c14_write_raw,
+ .write_raw_get_fmt = ads112c14_write_raw_get_fmt,
+ .debugfs_reg_access = ads112c14_debugfs_reg_access,
+ .read_label = ads112c14_read_label,
+};
+
+static int ads112c14_populate_idac_mag(u32 current_nA, u8 *idac_mag)
+{
+ u32 current_uA = current_nA / (NANO / MICRO);
+
+ /* Convert microamps to IMAG bits */
+ if (current_uA == 1)
+ *idac_mag = 1;
+ else if (in_range(current_uA, 10, 100) && current_uA % 10 == 0)
+ *idac_mag = current_uA / 10 + 1;
+ else
+ return dev_err_probe(NULL, -EINVAL,
+ "invalid excitation-current-nanoamp value\n");
+
+ return 0;
+}
+
+static int ads112c14_parse_channels(struct iio_dev *indio_dev,
+ bool *need_avdd_ref, bool *need_ext_ref)
+{
+ struct ads112c14_data *data = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
+ struct iio_chan_spec *channels;
+ u32 num_child_nodes, i, pair[2];
+ int ret;
+
+ *need_avdd_ref = false;
+ *need_ext_ref = false;
+
+ num_child_nodes = device_get_named_child_node_count(dev, "channel");
+
+ data->measurements = devm_kcalloc(dev, num_child_nodes,
+ sizeof(*data->measurements), GFP_KERNEL);
+ if (!data->measurements)
+ return -ENOMEM;
+
+ channels = devm_kcalloc(dev, num_child_nodes +
+ ARRAY_SIZE(ads112c14_sys_mon_channels) + 1,
+ sizeof(*channels), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ i = 0;
+ device_for_each_named_child_node_scoped(dev, child, "channel") {
+ struct ads112c14_measurement *measurement = &data->measurements[i];
+ struct iio_chan_spec *spec = &channels[i];
+
+ spec->indexed = 1;
+ spec->scan_index = i;
+ measurement->gain_val = 1;
+
+ if (fwnode_property_present(child, "label")) {
+ ret = fwnode_property_read_string(child, "label", &measurement->label);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read label property\n");
+ }
+
+ if (fwnode_property_present(child, "single-channel")) {
+ ret = fwnode_property_read_u32(child, "single-channel",
+ &pair[0]);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read single-channel property\n");
+
+ if (pair[0] >= 8)
+ return dev_err_probe(dev, -EINVAL,
+ "single-channel value must be between 0 and 7\n");
+
+ spec->channel = pair[0];
+ /*
+ * NB: channel2 is unused by iio core code in this case.
+ * Let's us avoid special case for negative input mux
+ * for single-ended channels when taking measurements.
+ */
+ spec->channel2 = ADS112C14_MUX_CFG_AIN_GND;
+ } else if (fwnode_property_present(child, "diff-channels")) {
+ ret = fwnode_property_read_u32_array(child, "diff-channels",
+ pair, ARRAY_SIZE(pair));
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read diff-channels property\n");
+
+ if (pair[0] >= 8 || pair[1] >= 8)
+ return dev_err_probe(dev, -EINVAL,
+ "diff-channels values must be between 0 and 7\n");
+
+ spec->differential = 1;
+ spec->channel = pair[0];
+ spec->channel2 = pair[1];
+ } else {
+ return dev_err_probe(dev, -EINVAL,
+ "channel node missing channel type property\n");
+ }
+
+ if (fwnode_property_present(child, "excitation-channels")) {
+ ret = fwnode_property_count_u32(child, "excitation-channels");
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to read excitation-channels property\n");
+
+ if (ret < 1 || ret > 2)
+ return dev_err_probe(dev, -EINVAL,
+ "excitation-channels property must have 1 or 2 values\n");
+
+ measurement->iadc_count = ret;
+ pair[1] = 0;
+
+ ret = fwnode_property_read_u32_array(child, "excitation-channels",
+ pair, measurement->iadc_count);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read excitation-channels property\n");
+
+ if (pair[0] >= 8 || pair[1] >= 8)
+ return dev_err_probe(dev, -EINVAL,
+ "excitation-channels values must be between 0 and 7\n");
+
+ measurement->idac1_mux = pair[0];
+ measurement->idac2_mux = measurement->iadc_count > 1 ? pair[1] : 0;
+
+ ret = fwnode_property_read_u32_array(child, "excitation-current-nanoamp",
+ pair, measurement->iadc_count);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read excitation-current-nanoamp property\n");
+
+ if (pair[0] <= 100 * (NANO / MICRO) &&
+ (measurement->iadc_count == 1 || pair[1] <= 100 * (NANO / MICRO))) {
+ /*
+ * If both values are 100µA or less, then we can
+ * use IUNIT = 1µA for better precision.
+ */
+ ret = ads112c14_populate_idac_mag(pair[0],
+ &measurement->idac1_mag);
+ if (ret)
+ return ret;
+
+ if (measurement->iadc_count > 1) {
+ ret = ads112c14_populate_idac_mag(pair[1],
+ &measurement->idac2_mag);
+ if (ret)
+ return ret;
+ }
+ } else {
+ /*
+ * Otherwise, IUINT is 10µA (flag set) and so
+ * IxMAG is 1/10 of the actual current.
+ */
+ measurement->iunit = 1;
+
+ ret = ads112c14_populate_idac_mag(pair[0] / 10,
+ &measurement->idac1_mag);
+ if (ret)
+ return ret;
+
+ if (measurement->iadc_count > 1) {
+ ret = ads112c14_populate_idac_mag(pair[1] / 10,
+ &measurement->idac2_mag);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+
+ measurement->bipolar = fwnode_property_read_bool(child, "bipolar");
+ measurement->global_chop = fwnode_property_read_bool(child,
+ "input-chopping");
+
+ if (fwnode_property_present(child, "reference-sources")) {
+ ret = fwnode_property_match_property_string(child,
+ "reference-sources", ads112c14_vref_source_names,
+ ARRAY_SIZE(ads112c14_vref_source_names));
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "invalid reference-sources value\n");
+
+ measurement->vref_source = ret;
+ }
+
+ if (measurement->vref_source == ADS112C14_VREF_SOURCE_AVDD)
+ *need_avdd_ref = true;
+ if (measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL)
+ *need_ext_ref = true;
+
+ spec->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE);
+ spec->info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE);
+
+ /*
+ * If reference source is resistor rather than voltage supply,
+ * then the measurement is effectively a resistance measurement.
+ */
+ spec->type = (measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL &&
+ data->ext_ref_ohms) ? IIO_RESISTANCE : IIO_VOLTAGE;
+
+ if (spec->type == IIO_RESISTANCE)
+ spec->differential = 0;
+
+ spec->scan_type = (struct iio_scan_type){
+ .format = measurement->bipolar ?
+ IIO_SCAN_FORMAT_SIGNED_INT :
+ IIO_SCAN_FORMAT_UNSIGNED_INT,
+ .realbits = data->chip_info->resolution_bits,
+ .storagebits = 32,
+ .shift = 32 - data->chip_info->resolution_bits,
+ .endianness = IIO_BE,
+ };
+
+ i++;
+ }
+
+ data->num_measurements = i;
+ if (data->num_measurements > ADS112C14_MAX_MEASUREMENT_CHANNELS)
+ return dev_err_probe(dev, -EINVAL,
+ "too many measurement channels defined\n");
+
+ memcpy(channels + i, ads112c14_sys_mon_channels, sizeof(ads112c14_sys_mon_channels));
+
+ for (u32 j = 0; j < ARRAY_SIZE(ads112c14_sys_mon_channels); j++) {
+ struct iio_chan_spec *spec = &channels[i];
+
+ /* Update the template that was already copied with dynamic values. */
+ spec->scan_index = i;
+ spec->scan_type = (struct iio_scan_type){
+ .format = IIO_SCAN_FORMAT_SIGNED_INT,
+ .realbits = data->chip_info->resolution_bits,
+ .storagebits = 32,
+ .shift = 32 - data->chip_info->resolution_bits,
+ .endianness = IIO_BE,
+ };
+
+ i++;
+ }
+
+ channels[i] = IIO_CHAN_SOFT_TIMESTAMP(i);
+ i++;
+
+ indio_dev->channels = channels;
+ indio_dev->num_channels = i;
+
+ return 0;
+}
+
+static void ads112c14_populate_scale_available(int (*scale_avail)[2],
+ u32 full_scale, u32 fsr_bits)
+{
+ for (u32 i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) {
+ u64 gain_x10 = ads112c14_pga_gains_x10[i];
+ s64 scale;
+
+ scale = div64_u64((u64)PICO * 10U * full_scale,
+ gain_x10 * BIT(fsr_bits));
+
+ iio_val_s64_decompose(scale, &scale_avail[i][0],
+ &scale_avail[i][1]);
+ }
+}
+
+static void ads112c14_populate_tables(struct ads112c14_data *data)
+{
+ u32 full_scale, fsr_bits;
+
+ for (u32 i = 0; i < data->num_measurements; i++) {
+ struct ads112c14_measurement *measurement = &data->measurements[i];
+
+ switch (measurement->vref_source) {
+ case ADS112C14_VREF_SOURCE_EXTERNAL:
+ if (data->ext_ref_ohms)
+ full_scale = data->ext_ref_ohms;
+ else
+ full_scale = data->ext_ref_uV / (MICRO / MILLI);
+ break;
+ case ADS112C14_VREF_SOURCE_AVDD:
+ full_scale = data->avdd_uV / (MICRO / MILLI);
+ break;
+ case ADS112C14_VREF_SOURCE_INTERNAL_1_25V:
+ full_scale = ADS112C14_INT_REF0_mV;
+ break;
+ default:
+ full_scale = ADS112C14_INT_REF1_mV;
+ break;
+ }
+
+ fsr_bits = data->chip_info->resolution_bits - measurement->bipolar;
+
+ ads112c14_populate_scale_available(measurement->scale_available,
+ full_scale, fsr_bits);
+ }
+
+ /* For now, assuming all sys_mon channels are using 2.5V reference. */
+ full_scale = ADS112C14_INT_REF1_mV;
+ fsr_bits = data->chip_info->resolution_bits - 1;
+
+ ads112c14_populate_scale_available(data->sys_mon_chan_short_scale_available,
+ full_scale, fsr_bits);
+}
+
+static int ads112c14_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ const struct ads112c14_chip_info *info;
+ struct iio_dev *indio_dev;
+ struct ads112c14_data *data;
+ bool need_avdd_ref, need_ext_ref;
+ u32 refp_uV = 0;
+ u32 refn_uV = 0;
+ u32 reg_val;
+ int ret;
+
+ info = i2c_get_match_data(client);
+ if (!info)
+ return dev_err_probe(dev, -ENODEV, "missing match data\n");
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->chip_info = info;
+
+ ret = devm_mutex_init(dev, &data->lock);
+ if (ret)
+ return ret;
+
+ if (device_property_present(dev, "ti,refp-refn-resistor-ohms")) {
+ ret = device_property_read_u32(dev, "ti,refp-refn-resistor-ohms",
+ &data->ext_ref_ohms);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to read ti,refp-refn-resistor-ohms property\n");
+ }
+
+ ret = ads112c14_parse_channels(indio_dev, &need_avdd_ref, &need_ext_ref);
+ if (ret)
+ return ret;
+
+ ret = devm_regulator_get_enable(dev, "dvdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get dvdd regulator\n");
+
+ if (need_avdd_ref) {
+ ret = devm_regulator_get_enable_read_voltage(dev, "avdd");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to get avdd voltage\n");
+
+ data->avdd_uV = ret;
+ } else {
+ ret = devm_regulator_get_enable(dev, "avdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get avdd regulator\n");
+ }
+
+ if (device_property_present(dev, "refp-supply")) {
+ ret = devm_regulator_get_enable_read_voltage(dev, "refp");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to get refp voltage\n");
+
+ refp_uV = ret;
+
+ struct fwnode_handle *refp_fwnode __free(fwnode_handle) =
+ fwnode_find_reference(dev->fwnode, "refp-supply", 0);
+ if (IS_ERR(refp_fwnode))
+ return dev_err_probe(dev, PTR_ERR(refp_fwnode),
+ "failed to get refp fwnode\n");
+
+ struct fwnode_handle *avdd_fwnode __free(fwnode_handle) =
+ fwnode_find_reference(dev->fwnode, "avdd-supply", 0);
+ if (IS_ERR(avdd_fwnode))
+ return dev_err_probe(dev, PTR_ERR(avdd_fwnode),
+ "failed to get avdd fwnode\n");
+
+ /* REFP buffer should not be enabled when connected to AVDD */
+ data->refp_is_avdd = refp_fwnode == avdd_fwnode;
+ }
+
+ if (device_property_present(dev, "refn-supply")) {
+ ret = devm_regulator_get_enable_read_voltage(dev, "refn");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to get refn voltage\n");
+
+ refn_uV = ret;
+ } else {
+ data->refn_is_gnd = true;
+ }
+
+ data->ext_ref_uV = refp_uV - refn_uV;
+
+ if (data->ext_ref_uV && data->ext_ref_ohms)
+ return dev_err_probe(dev, -EINVAL,
+ "ti,refp-refn-resistor-ohms property should not be present when refp-supply or refn-supply is present\n");
+
+ if (need_ext_ref && !data->ext_ref_uV && !data->ext_ref_ohms)
+ return dev_err_probe(dev, -EINVAL,
+ "external reference measurements require either refp-supply or ti,refp-refn-resistor-ohms property\n");
+
+ /* It takes some time for the internal reference to stabilize. */
+ fsleep(10 * USEC_PER_MSEC);
+
+ data->regmap = devm_regmap_init(dev, &ads112c14_regmap_bus, data,
+ &ads112c14_regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(dev, PTR_ERR(data->regmap),
+ "failed to init regmap\n");
+
+ /*
+ * Write magic reset value (0x16) to ensure known state. The reset may
+ * cause an error because of failing to get the I2C ACK at the end of
+ * the message. The device still gets reset so it is safe to ignore the
+ * return value here. If something else is wrong, later read/write will
+ * likely have the same error.
+ */
+ regmap_write(data->regmap, ADS112C14_REG_CONVERSION_CTRL,
+ FIELD_PREP(ADS112C14_CONVERSION_CTRL_RESET, 0x16));
+
+ fsleep(ADS112C14_DELAY_RESET_US);
+
+ ret = regmap_read(data->regmap, ADS112C14_REG_STATUS_MSB, &reg_val);
+ if (ret)
+ return ret;
+
+ if (FIELD_GET(ADS112C14_STATUS_MSB_RESETN, reg_val))
+ return dev_err_probe(dev, -EIO, "reset failed\n");
+
+ /* Default gain after reset is 1. */
+ data->sys_mon_chan_short_gain_val = 1;
+
+ /*
+ * Clear reset bit to prepare for next probe. And clear AVDD fault since
+ * that happens on every reset.
+ */
+ ret = regmap_write(data->regmap, ADS112C14_REG_STATUS_MSB,
+ ADS112C14_STATUS_MSB_RESETN |
+ ADS112C14_STATUS_MSB_AVDD_UVN);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(data->regmap, ADS112C14_REG_DIGITAL_CFG,
+ ADS112C14_DIGITAL_CFG_I2C_CRC_EN);
+ if (ret)
+ return ret;
+
+ data->i2c_crc_enabled = true;
+
+ ret = regmap_read(data->regmap, ADS112C14_REG_DEVICE_ID, &reg_val);
+ if (ret)
+ return ret;
+
+ if (FIELD_GET(ADS112C14_DEVICE_ID_BITS, reg_val) != info->device_id)
+ dev_info(dev, "device ID mismatch, expected 0x%X, got 0x%lX\n",
+ info->device_id,
+ FIELD_GET(ADS112C14_DEVICE_ID_BITS, reg_val));
+
+ ret = regmap_update_bits(data->regmap, ADS112C14_REG_DEVICE_CFG,
+ ADS112C14_DEVICE_CFG_CONV_MODE,
+ FIELD_PREP(ADS112C14_DEVICE_CFG_CONV_MODE,
+ ADS112C14_DEVICE_CFG_CONV_MODE_SINGLE_SHOT));
+ if (ret)
+ return ret;
+
+ ads112c14_populate_tables(data);
+
+ indio_dev->name = info->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &ads112c14_info;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ iio_pollfunc_store_time,
+ ads112c14_trigger_handler, NULL);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct ads112c14_chip_info ads112c14_chip_info = {
+ .name = "ads112c14",
+ .device_id = 0xE,
+ .resolution_bits = 16,
+};
+
+static const struct ads112c14_chip_info ads122c14_chip_info = {
+ .name = "ads122c14",
+ .device_id = 0xF,
+ .resolution_bits = 24,
+};
+
+static const struct of_device_id ads112c14_of_match[] = {
+ { .compatible = "ti,ads112c14", .data = &ads112c14_chip_info },
+ { .compatible = "ti,ads122c14", .data = &ads122c14_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ads112c14_of_match);
+
+static const struct i2c_device_id ads112c14_id[] = {
+ { .name = "ads112c14", .driver_data = (kernel_ulong_t)&ads112c14_chip_info },
+ { .name = "ads122c14", .driver_data = (kernel_ulong_t)&ads122c14_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ads112c14_id);
+
+static int ads112c14_i2c_add_driver(struct i2c_driver *driver)
+{
+ crc8_populate_msb(ads112c14_crc8_table, ADS112C14_I2C_CRC8_POLYNOMIAL);
+
+ return i2c_add_driver(driver);
+}
+
+static struct i2c_driver ads112c14_driver = {
+ .driver = {
+ .name = "ads112c14",
+ .of_match_table = ads112c14_of_match,
+ },
+ .probe = ads112c14_probe,
+ .id_table = ads112c14_id,
+};
+module_driver(ads112c14_driver, ads112c14_i2c_add_driver, i2c_del_driver);
+
+MODULE_AUTHOR("David Lechner (TI) <dlechner@baylibre.com>");
+MODULE_DESCRIPTION("TI ADS112C14 I2C ADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c
index 8ea1269f74db..49fbc63508ac 100644
--- a/drivers/iio/adc/ti-ads124s08.c
+++ b/drivers/iio/adc/ti-ads124s08.c
@@ -8,7 +8,6 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
@@ -321,7 +320,8 @@ static int ads124s_probe(struct spi_device *spi)
ads124s_priv->reset_gpio = devm_gpiod_get_optional(&spi->dev,
"reset", GPIOD_OUT_LOW);
if (IS_ERR(ads124s_priv->reset_gpio))
- dev_info(&spi->dev, "Reset GPIO not defined\n");
+ return dev_err_probe(&spi->dev, PTR_ERR(ads124s_priv->reset_gpio),
+ "Failed to get reset GPIO\n");
ads124s_priv->chip_info = &ads124s_chip_info_tbl[spi_id->driver_data];
@@ -348,8 +348,8 @@ static int ads124s_probe(struct spi_device *spi)
}
static const struct spi_device_id ads124s_id[] = {
- { "ads124s06", ADS124S06_ID },
- { "ads124s08", ADS124S08_ID },
+ { .name = "ads124s06", .driver_data = ADS124S06_ID },
+ { .name = "ads124s08", .driver_data = ADS124S08_ID },
{ }
};
MODULE_DEVICE_TABLE(spi, ads124s_id);
diff --git a/drivers/iio/adc/ti-ads1298.c b/drivers/iio/adc/ti-ads1298.c
index ae30b47e4514..06c6353aa1b2 100644
--- a/drivers/iio/adc/ti-ads1298.c
+++ b/drivers/iio/adc/ti-ads1298.c
@@ -66,7 +66,7 @@
#define ADS1298_MASK_CONFIG3_VREF_4V BIT(5)
#define ADS1298_REG_LOFF 0x04
-#define ADS1298_REG_CHnSET(n) (0x05 + n)
+#define ADS1298_REG_CHnSET(n) (0x05 + (n))
#define ADS1298_MASK_CH_PD BIT(7)
#define ADS1298_MASK_CH_PGA GENMASK(6, 4)
#define ADS1298_MASK_CH_MUX GENMASK(2, 0)
@@ -210,9 +210,11 @@ static int ads1298_read_one(struct ads1298_private *priv, int chan_index)
return ret;
}
- /* Cannot take longer than 40ms (250Hz) */
- ret = wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(50));
- if (!ret)
+ /*
+ * One conversion takes at most 4ms at the lowest sample rate (250Hz).
+ * Use 50ms to allow for kernel scheduling latency.
+ */
+ if (!wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(50)))
return -ETIMEDOUT;
return 0;
@@ -279,6 +281,7 @@ static const u8 ads1298_pga_settings[] = { 6, 1, 2, 3, 4, 8, 12 };
static int ads1298_get_scale(struct ads1298_private *priv,
int channel, int *val, int *val2)
{
+ unsigned int pga_idx;
int ret;
unsigned int regval;
u8 gain;
@@ -302,7 +305,11 @@ static int ads1298_get_scale(struct ads1298_private *priv,
if (ret)
return ret;
- gain = ads1298_pga_settings[FIELD_GET(ADS1298_MASK_CH_PGA, regval)];
+ pga_idx = FIELD_GET(ADS1298_MASK_CH_PGA, regval);
+ if (pga_idx >= ARRAY_SIZE(ads1298_pga_settings))
+ return -EINVAL;
+
+ gain = ads1298_pga_settings[pga_idx];
*val /= gain; /* Full scale is VREF / gain */
*val2 = ADS1298_BITS_PER_SAMPLE - 1; /* Signed, hence the -1 */
@@ -615,15 +622,6 @@ static int ads1298_init(struct iio_dev *indio_dev)
if (!indio_dev->name)
return -ENOMEM;
- /* Enable internal test signal, double amplitude, double frequency */
- ret = regmap_write(priv->regmap, ADS1298_REG_CONFIG2,
- ADS1298_MASK_CONFIG2_RESERVED |
- ADS1298_MASK_CONFIG2_INT_TEST |
- ADS1298_MASK_CONFIG2_TEST_AMP |
- ADS1298_MASK_CONFIG2_TEST_FREQ_FAST);
- if (ret)
- return ret;
-
val = ADS1298_MASK_CONFIG3_RESERVED; /* Must write 1 always */
if (!priv->reg_vref) {
/* Enable internal reference */
@@ -745,7 +743,7 @@ static int ads1298_probe(struct spi_device *spi)
}
static const struct spi_device_id ads1298_id[] = {
- { "ads1298" },
+ { .name = "ads1298" },
{ }
};
MODULE_DEVICE_TABLE(spi, ads1298_id);
diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c
index a585621b0bc3..1d25f887cadb 100644
--- a/drivers/iio/adc/ti-ads131e08.c
+++ b/drivers/iio/adc/ti-ads131e08.c
@@ -917,9 +917,9 @@ 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] },
+ { .name = "ads131e04", .driver_data = (kernel_ulong_t)&ads131e08_info_tbl[ads131e04] },
+ { .name = "ads131e06", .driver_data = (kernel_ulong_t)&ads131e08_info_tbl[ads131e06] },
+ { .name = "ads131e08", .driver_data = (kernel_ulong_t)&ads131e08_info_tbl[ads131e08] },
{ }
};
MODULE_DEVICE_TABLE(spi, ads131e08_ids);
diff --git a/drivers/iio/adc/ti-ads131m02.c b/drivers/iio/adc/ti-ads131m02.c
index 07d63bf62c5f..2f8f75c8216b 100644
--- a/drivers/iio/adc/ti-ads131m02.c
+++ b/drivers/iio/adc/ti-ads131m02.c
@@ -23,7 +23,6 @@
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/lockdep.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
@@ -944,11 +943,11 @@ static const struct of_device_id ads131m_of_match[] = {
MODULE_DEVICE_TABLE(of, ads131m_of_match);
static const struct spi_device_id ads131m_id[] = {
- { "ads131m02", (kernel_ulong_t)&ads131m02_config },
- { "ads131m03", (kernel_ulong_t)&ads131m03_config },
- { "ads131m04", (kernel_ulong_t)&ads131m04_config },
- { "ads131m06", (kernel_ulong_t)&ads131m06_config },
- { "ads131m08", (kernel_ulong_t)&ads131m08_config },
+ { .name = "ads131m02", .driver_data = (kernel_ulong_t)&ads131m02_config },
+ { .name = "ads131m03", .driver_data = (kernel_ulong_t)&ads131m03_config },
+ { .name = "ads131m04", .driver_data = (kernel_ulong_t)&ads131m04_config },
+ { .name = "ads131m06", .driver_data = (kernel_ulong_t)&ads131m06_config },
+ { .name = "ads131m08", .driver_data = (kernel_ulong_t)&ads131m08_config },
{ }
};
MODULE_DEVICE_TABLE(spi, ads131m_id);
diff --git a/drivers/iio/adc/ti-ads7138.c b/drivers/iio/adc/ti-ads7138.c
index ee5c1b8e3a8e..da82a6947b2b 100644
--- a/drivers/iio/adc/ti-ads7138.c
+++ b/drivers/iio/adc/ti-ads7138.c
@@ -227,6 +227,26 @@ static int ads7138_osr_to_bits(int osr)
return -EINVAL;
}
+static int ads7138_read_statistics(const struct i2c_client *client, u8 reg,
+ u8 *out_values, u8 length)
+{
+ int ret;
+
+ /* Disable statistics update so the value is not updated mid read */
+ ret = ads7138_i2c_clear_bit(client, ADS7138_REG_GENERAL_CFG,
+ ADS7138_GENERAL_CFG_STATS_EN);
+ if (ret)
+ return ret;
+
+ ret = ads7138_i2c_read_block(client, reg, out_values, length);
+ if (ret)
+ return ret;
+
+ /* Enable statistics update after read */
+ return ads7138_i2c_set_bit(client, ADS7138_REG_GENERAL_CFG,
+ ADS7138_GENERAL_CFG_STATS_EN);
+}
+
static int ads7138_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
@@ -236,28 +256,32 @@ static int ads7138_read_raw(struct iio_dev *indio_dev,
u8 values[2];
switch (mask) {
+ /*
+ * Reading the statistics registers reinitializes them. This is
+ * unfortunate but necessary to prevent data races.
+ */
case IIO_CHAN_INFO_RAW:
- ret = ads7138_i2c_read_block(data->client,
- ADS7138_REG_RECENT_LSB_CH(chan->channel),
- values, ARRAY_SIZE(values));
+ ret = ads7138_read_statistics(data->client,
+ ADS7138_REG_RECENT_LSB_CH(chan->channel),
+ values, ARRAY_SIZE(values));
if (ret)
return ret;
*val = get_unaligned_le16(values);
return IIO_VAL_INT;
case IIO_CHAN_INFO_PEAK:
- ret = ads7138_i2c_read_block(data->client,
- ADS7138_REG_MAX_LSB_CH(chan->channel),
- values, ARRAY_SIZE(values));
+ ret = ads7138_read_statistics(data->client,
+ ADS7138_REG_MAX_LSB_CH(chan->channel),
+ values, ARRAY_SIZE(values));
if (ret)
return ret;
*val = get_unaligned_le16(values);
return IIO_VAL_INT;
case IIO_CHAN_INFO_TROUGH:
- ret = ads7138_i2c_read_block(data->client,
- ADS7138_REG_MIN_LSB_CH(chan->channel),
- values, ARRAY_SIZE(values));
+ ret = ads7138_read_statistics(data->client,
+ ADS7138_REG_MIN_LSB_CH(chan->channel),
+ values, ARRAY_SIZE(values));
if (ret)
return ret;
@@ -727,8 +751,8 @@ static const struct of_device_id ads7138_of_match[] = {
MODULE_DEVICE_TABLE(of, ads7138_of_match);
static const struct i2c_device_id ads7138_device_ids[] = {
- { "ads7128", (kernel_ulong_t)&ads7128_data },
- { "ads7138", (kernel_ulong_t)&ads7138_data },
+ { .name = "ads7128", .driver_data = (kernel_ulong_t)&ads7128_data },
+ { .name = "ads7138", .driver_data = (kernel_ulong_t)&ads7138_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, ads7138_device_ids);
diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c
index bbcc4fc22b6e..ff30a52d2850 100644
--- a/drivers/iio/adc/ti-ads7924.c
+++ b/drivers/iio/adc/ti-ads7924.c
@@ -12,6 +12,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
@@ -198,6 +199,8 @@ static int ads7924_get_adc_result(struct ads7924_data *data,
if (chan->channel < 0 || chan->channel >= ADS7924_CHANNELS)
return -EINVAL;
+ guard(mutex)(&data->lock);
+
if (data->conv_invalid) {
int conv_time;
@@ -227,9 +230,7 @@ static int ads7924_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&data->lock);
ret = ads7924_get_adc_result(data, chan, val);
- mutex_unlock(&data->lock);
if (ret < 0)
return ret;
@@ -441,7 +442,7 @@ static int ads7924_probe(struct i2c_client *client)
}
static const struct i2c_device_id ads7924_id[] = {
- { "ads7924" },
+ { .name = "ads7924" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ads7924_id);
diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c
index bbe1ce577789..d27c1f2885fd 100644
--- a/drivers/iio/adc/ti-ads7950.c
+++ b/drivers/iio/adc/ti-ads7950.c
@@ -47,8 +47,6 @@
#define TI_ADS7950_MAX_CHAN 16
#define TI_ADS7950_NUM_GPIOS 4
-#define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16))
-
/* val = value, dec = left shift, bits = number of bits of the mask */
#define TI_ADS7950_EXTRACT(val, dec, bits) \
(((val) >> (dec)) & ((1 << (bits)) - 1))
@@ -105,8 +103,7 @@ struct ti_ads7950_state {
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
*/
- u16 rx_buf[TI_ADS7950_MAX_CHAN + 2 + TI_ADS7950_TIMESTAMP_SIZE]
- __aligned(IIO_DMA_MINALIGN);
+ u16 rx_buf[TI_ADS7950_MAX_CHAN + 2] __aligned(IIO_DMA_MINALIGN);
u16 tx_buf[TI_ADS7950_MAX_CHAN + 2];
u16 single_tx;
u16 single_rx;
@@ -118,21 +115,6 @@ struct ti_ads7950_chip_info {
unsigned int num_channels;
};
-enum ti_ads7950_id {
- TI_ADS7950,
- TI_ADS7951,
- TI_ADS7952,
- TI_ADS7953,
- TI_ADS7954,
- TI_ADS7955,
- TI_ADS7956,
- TI_ADS7957,
- TI_ADS7958,
- TI_ADS7959,
- TI_ADS7960,
- TI_ADS7961,
-};
-
#define TI_ADS7950_V_CHAN(index, bits) \
{ \
.type = IIO_VOLTAGE, \
@@ -225,81 +207,65 @@ static DECLARE_TI_ADS7950_8_CHANNELS(ti_ads7959, 8);
static DECLARE_TI_ADS7950_12_CHANNELS(ti_ads7960, 8);
static DECLARE_TI_ADS7950_16_CHANNELS(ti_ads7961, 8);
-static const struct ti_ads7950_chip_info ti_ads7950_chip_info[] = {
- [TI_ADS7950] = {
- .channels = ti_ads7950_channels,
- .num_channels = ARRAY_SIZE(ti_ads7950_channels),
- },
- [TI_ADS7951] = {
- .channels = ti_ads7951_channels,
- .num_channels = ARRAY_SIZE(ti_ads7951_channels),
- },
- [TI_ADS7952] = {
- .channels = ti_ads7952_channels,
- .num_channels = ARRAY_SIZE(ti_ads7952_channels),
- },
- [TI_ADS7953] = {
- .channels = ti_ads7953_channels,
- .num_channels = ARRAY_SIZE(ti_ads7953_channels),
- },
- [TI_ADS7954] = {
- .channels = ti_ads7954_channels,
- .num_channels = ARRAY_SIZE(ti_ads7954_channels),
- },
- [TI_ADS7955] = {
- .channels = ti_ads7955_channels,
- .num_channels = ARRAY_SIZE(ti_ads7955_channels),
- },
- [TI_ADS7956] = {
- .channels = ti_ads7956_channels,
- .num_channels = ARRAY_SIZE(ti_ads7956_channels),
- },
- [TI_ADS7957] = {
- .channels = ti_ads7957_channels,
- .num_channels = ARRAY_SIZE(ti_ads7957_channels),
- },
- [TI_ADS7958] = {
- .channels = ti_ads7958_channels,
- .num_channels = ARRAY_SIZE(ti_ads7958_channels),
- },
- [TI_ADS7959] = {
- .channels = ti_ads7959_channels,
- .num_channels = ARRAY_SIZE(ti_ads7959_channels),
- },
- [TI_ADS7960] = {
- .channels = ti_ads7960_channels,
- .num_channels = ARRAY_SIZE(ti_ads7960_channels),
- },
- [TI_ADS7961] = {
- .channels = ti_ads7961_channels,
- .num_channels = ARRAY_SIZE(ti_ads7961_channels),
- },
+static const struct ti_ads7950_chip_info ti_ads7950_chip_info = {
+ .channels = ti_ads7950_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7950_channels),
};
-/*
- * ti_ads7950_update_scan_mode() setup the spi transfer buffer for the new
- * scan mask
- */
-static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev,
- const unsigned long *active_scan_mask)
-{
- struct ti_ads7950_state *st = iio_priv(indio_dev);
- int i, cmd, len;
+static const struct ti_ads7950_chip_info ti_ads7951_chip_info = {
+ .channels = ti_ads7951_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7951_channels),
+};
- len = 0;
- for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) {
- cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(i));
- st->tx_buf[len++] = cmd;
- }
+static const struct ti_ads7950_chip_info ti_ads7952_chip_info = {
+ .channels = ti_ads7952_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7952_channels),
+};
- /* Data for the 1st channel is not returned until the 3rd transfer */
- st->tx_buf[len++] = 0;
- st->tx_buf[len++] = 0;
+static const struct ti_ads7950_chip_info ti_ads7953_chip_info = {
+ .channels = ti_ads7953_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7953_channels),
+};
- st->ring_xfer.len = len * 2;
+static const struct ti_ads7950_chip_info ti_ads7954_chip_info = {
+ .channels = ti_ads7954_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7954_channels),
+};
- return 0;
-}
+static const struct ti_ads7950_chip_info ti_ads7955_chip_info = {
+ .channels = ti_ads7955_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7955_channels),
+};
+
+static const struct ti_ads7950_chip_info ti_ads7956_chip_info = {
+ .channels = ti_ads7956_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7956_channels),
+};
+
+static const struct ti_ads7950_chip_info ti_ads7957_chip_info = {
+ .channels = ti_ads7957_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7957_channels),
+};
+
+static const struct ti_ads7950_chip_info ti_ads7958_chip_info = {
+ .channels = ti_ads7958_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7958_channels),
+};
+
+static const struct ti_ads7950_chip_info ti_ads7959_chip_info = {
+ .channels = ti_ads7959_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7959_channels),
+};
+
+static const struct ti_ads7950_chip_info ti_ads7960_chip_info = {
+ .channels = ti_ads7960_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7960_channels),
+};
+
+static const struct ti_ads7950_chip_info ti_ads7961_chip_info = {
+ .channels = ti_ads7961_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7961_channels),
+};
static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
{
@@ -308,16 +274,19 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
struct ti_ads7950_state *st = iio_priv(indio_dev);
int ret;
- mutex_lock(&st->slock);
- ret = spi_sync(st->spi, &st->ring_msg);
- if (ret < 0)
- goto out;
+ do {
+ guard(mutex)(&st->slock);
+
+ ret = spi_sync(st->spi, &st->ring_msg);
+ if (ret)
+ break;
- iio_push_to_buffers_with_timestamp(indio_dev, &st->rx_buf[2],
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts_unaligned(indio_dev, &st->rx_buf[2],
+ sizeof(*st->rx_buf) *
+ TI_ADS7950_MAX_CHAN,
+ iio_get_time_ns(indio_dev));
+ } while (0);
-out:
- mutex_unlock(&st->slock);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
@@ -328,35 +297,21 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
struct ti_ads7950_state *st = iio_priv(indio_dev);
int ret, cmd;
- mutex_lock(&st->slock);
+ guard(mutex)(&st->slock);
+
cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(ch));
st->single_tx = cmd;
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
- goto out;
-
- ret = st->single_rx;
-
-out:
- mutex_unlock(&st->slock);
+ return ret;
- return ret;
+ return st->single_rx;
}
-static int ti_ads7950_get_range(struct ti_ads7950_state *st)
+static unsigned int ti_ads7950_get_range(struct ti_ads7950_state *st)
{
- int vref;
-
- if (st->vref_mv) {
- vref = st->vref_mv;
- } else {
- vref = regulator_get_voltage(st->reg);
- if (vref < 0)
- return vref;
-
- vref /= 1000;
- }
+ unsigned int vref = st->vref_mv;
if (st->cmd_settings_bitmask & TI_ADS7950_CR_RANGE_5V)
vref *= 2;
@@ -385,11 +340,7 @@ static int ti_ads7950_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- ret = ti_ads7950_get_range(st);
- if (ret < 0)
- return ret;
-
- *val = ret;
+ *val = ti_ads7950_get_range(st);
*val2 = (1 << chan->scan_type.realbits) - 1;
return IIO_VAL_FRACTIONAL;
@@ -399,17 +350,50 @@ static int ti_ads7950_read_raw(struct iio_dev *indio_dev,
}
static const struct iio_info ti_ads7950_info = {
- .read_raw = &ti_ads7950_read_raw,
- .update_scan_mode = ti_ads7950_update_scan_mode,
+ .read_raw = &ti_ads7950_read_raw,
+};
+
+static int ti_ads7950_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct ti_ads7950_state *st = iio_priv(indio_dev);
+ u32 len = 0;
+ u32 i;
+ u16 cmd;
+
+ for_each_set_bit(i, indio_dev->active_scan_mask, indio_dev->num_channels) {
+ cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(i));
+ st->tx_buf[len++] = cmd;
+ }
+
+ /* Data for the 1st channel is not returned until the 3rd transfer */
+ st->tx_buf[len++] = 0;
+ st->tx_buf[len++] = 0;
+
+ st->ring_xfer.len = len * 2;
+
+ return spi_optimize_message(st->spi, &st->ring_msg);
+}
+
+static int ti_ads7950_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct ti_ads7950_state *st = iio_priv(indio_dev);
+
+ spi_unoptimize_message(&st->ring_msg);
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ti_ads7950_buffer_setup_ops = {
+ .preenable = ti_ads7950_buffer_preenable,
+ .postdisable = ti_ads7950_buffer_postdisable,
};
static int ti_ads7950_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct ti_ads7950_state *st = gpiochip_get_data(chip);
- int ret;
- mutex_lock(&st->slock);
+ guard(mutex)(&st->slock);
if (value)
st->cmd_settings_bitmask |= BIT(offset);
@@ -417,24 +401,22 @@ static int ti_ads7950_set(struct gpio_chip *chip, unsigned int offset,
st->cmd_settings_bitmask &= ~BIT(offset);
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
- ret = spi_sync(st->spi, &st->scan_single_msg);
-
- mutex_unlock(&st->slock);
- return ret;
+ return spi_sync(st->spi, &st->scan_single_msg);
}
static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset)
{
struct ti_ads7950_state *st = gpiochip_get_data(chip);
+ bool state;
int ret;
- mutex_lock(&st->slock);
+ guard(mutex)(&st->slock);
/* If set as output, return the output */
if (st->gpio_cmd_settings_bitmask & BIT(offset)) {
- ret = st->cmd_settings_bitmask & BIT(offset);
- goto out;
+ state = st->cmd_settings_bitmask & BIT(offset);
+ return state;
}
/* GPIO data bit sets SDO bits 12-15 to GPIO input */
@@ -442,21 +424,18 @@ static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset)
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
- goto out;
+ return ret;
- ret = ((st->single_rx >> 12) & BIT(offset)) ? 1 : 0;
+ state = (st->single_rx >> 12) & BIT(offset);
/* Revert back to original settings */
st->cmd_settings_bitmask &= ~TI_ADS7950_CR_GPIO_DATA;
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
- goto out;
-
-out:
- mutex_unlock(&st->slock);
+ return ret;
- return ret;
+ return state;
}
static int ti_ads7950_get_direction(struct gpio_chip *chip,
@@ -472,9 +451,8 @@ static int _ti_ads7950_set_direction(struct gpio_chip *chip, int offset,
int input)
{
struct ti_ads7950_state *st = gpiochip_get_data(chip);
- int ret = 0;
- mutex_lock(&st->slock);
+ guard(mutex)(&st->slock);
/* Only change direction if needed */
if (input && (st->gpio_cmd_settings_bitmask & BIT(offset)))
@@ -482,15 +460,11 @@ static int _ti_ads7950_set_direction(struct gpio_chip *chip, int offset,
else if (!input && !(st->gpio_cmd_settings_bitmask & BIT(offset)))
st->gpio_cmd_settings_bitmask |= BIT(offset);
else
- goto out;
+ return 0;
st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st);
- ret = spi_sync(st->spi, &st->scan_single_msg);
-out:
- mutex_unlock(&st->slock);
-
- return ret;
+ return spi_sync(st->spi, &st->scan_single_msg);
}
static int ti_ads7950_direction_input(struct gpio_chip *chip,
@@ -513,9 +487,9 @@ static int ti_ads7950_direction_output(struct gpio_chip *chip,
static int ti_ads7950_init_hw(struct ti_ads7950_state *st)
{
- int ret = 0;
+ int ret;
- mutex_lock(&st->slock);
+ guard(mutex)(&st->slock);
/* Settings for Manual/Auto1/Auto2 commands */
/* Default to 5v ref */
@@ -523,17 +497,12 @@ static int ti_ads7950_init_hw(struct ti_ads7950_state *st)
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
- goto out;
+ return ret;
/* Settings for GPIO command */
st->gpio_cmd_settings_bitmask = 0x0;
st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st);
- ret = spi_sync(st->spi, &st->scan_single_msg);
-
-out:
- mutex_unlock(&st->slock);
-
- return ret;
+ return spi_sync(st->spi, &st->scan_single_msg);
}
static int ti_ads7950_probe(struct spi_device *spi)
@@ -546,10 +515,8 @@ static int ti_ads7950_probe(struct spi_device *spi)
spi->bits_per_word = 16;
spi->mode |= SPI_CS_WORD;
ret = spi_setup(spi);
- if (ret < 0) {
- dev_err(&spi->dev, "Error in spi setup\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&spi->dev, ret, "Error in spi setup\n");
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
@@ -557,11 +524,9 @@ static int ti_ads7950_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
- spi_set_drvdata(spi, indio_dev);
-
st->spi = spi;
- info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data];
+ info = spi_get_device_match_data(spi);
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -599,43 +564,38 @@ static int ti_ads7950_probe(struct spi_device *spi)
spi_message_init_with_transfers(&st->scan_single_msg,
st->scan_single_xfer, 3);
+ ret = devm_mutex_init(&spi->dev, &st->slock);
+ if (ret)
+ return ret;
+
/* Use hard coded value for reference voltage in ACPI case */
- if (ACPI_COMPANION(&spi->dev))
+ if (ACPI_COMPANION(&spi->dev)) {
st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT;
+ } else {
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to get regulator \"vref\"\n");
- mutex_init(&st->slock);
-
- st->reg = devm_regulator_get(&spi->dev, "vref");
- if (IS_ERR(st->reg)) {
- ret = dev_err_probe(&spi->dev, PTR_ERR(st->reg),
- "Failed to get regulator \"vref\"\n");
- goto error_destroy_mutex;
- }
-
- ret = regulator_enable(st->reg);
- if (ret) {
- dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n");
- goto error_destroy_mutex;
+ st->vref_mv = ret / 1000;
}
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
- &ti_ads7950_trigger_handler, NULL);
- if (ret) {
- dev_err(&spi->dev, "Failed to setup triggered buffer\n");
- goto error_disable_reg;
- }
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
+ &ti_ads7950_trigger_handler,
+ &ti_ads7950_buffer_setup_ops);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to setup triggered buffer\n");
ret = ti_ads7950_init_hw(st);
- if (ret) {
- dev_err(&spi->dev, "Failed to init adc chip\n");
- goto error_cleanup_ring;
- }
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to init adc chip\n");
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&spi->dev, "Failed to register iio device\n");
- goto error_cleanup_ring;
- }
+ ret = devm_iio_device_register(&spi->dev, indio_dev);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to register iio device\n");
/* Add GPIO chip */
st->chip.label = dev_name(&st->spi->dev);
@@ -650,68 +610,44 @@ static int ti_ads7950_probe(struct spi_device *spi)
st->chip.get = ti_ads7950_get;
st->chip.set = ti_ads7950_set;
- ret = gpiochip_add_data(&st->chip, st);
- if (ret) {
- dev_err(&spi->dev, "Failed to init GPIOs\n");
- goto error_iio_device;
- }
+ ret = devm_gpiochip_add_data(&spi->dev, &st->chip, st);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to init GPIOs\n");
return 0;
-
-error_iio_device:
- iio_device_unregister(indio_dev);
-error_cleanup_ring:
- iio_triggered_buffer_cleanup(indio_dev);
-error_disable_reg:
- regulator_disable(st->reg);
-error_destroy_mutex:
- mutex_destroy(&st->slock);
-
- return ret;
-}
-
-static void ti_ads7950_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ti_ads7950_state *st = iio_priv(indio_dev);
-
- gpiochip_remove(&st->chip);
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- regulator_disable(st->reg);
- mutex_destroy(&st->slock);
}
static const struct spi_device_id ti_ads7950_id[] = {
- { "ads7950", TI_ADS7950 },
- { "ads7951", TI_ADS7951 },
- { "ads7952", TI_ADS7952 },
- { "ads7953", TI_ADS7953 },
- { "ads7954", TI_ADS7954 },
- { "ads7955", TI_ADS7955 },
- { "ads7956", TI_ADS7956 },
- { "ads7957", TI_ADS7957 },
- { "ads7958", TI_ADS7958 },
- { "ads7959", TI_ADS7959 },
- { "ads7960", TI_ADS7960 },
- { "ads7961", TI_ADS7961 },
+ { .name = "ads7950", .driver_data = (kernel_ulong_t)&ti_ads7950_chip_info },
+ { .name = "ads7951", .driver_data = (kernel_ulong_t)&ti_ads7951_chip_info },
+ { .name = "ads7952", .driver_data = (kernel_ulong_t)&ti_ads7952_chip_info },
+ { .name = "ads7953", .driver_data = (kernel_ulong_t)&ti_ads7953_chip_info },
+ { .name = "ads7954", .driver_data = (kernel_ulong_t)&ti_ads7954_chip_info },
+ { .name = "ads7955", .driver_data = (kernel_ulong_t)&ti_ads7955_chip_info },
+ { .name = "ads7956", .driver_data = (kernel_ulong_t)&ti_ads7956_chip_info },
+ { .name = "ads7957", .driver_data = (kernel_ulong_t)&ti_ads7957_chip_info },
+ { .name = "ads7958", .driver_data = (kernel_ulong_t)&ti_ads7958_chip_info },
+ { .name = "ads7959", .driver_data = (kernel_ulong_t)&ti_ads7959_chip_info },
+ { .name = "ads7960", .driver_data = (kernel_ulong_t)&ti_ads7960_chip_info },
+ { .name = "ads7961", .driver_data = (kernel_ulong_t)&ti_ads7961_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ti_ads7950_id);
static const struct of_device_id ads7950_of_table[] = {
- { .compatible = "ti,ads7950", .data = &ti_ads7950_chip_info[TI_ADS7950] },
- { .compatible = "ti,ads7951", .data = &ti_ads7950_chip_info[TI_ADS7951] },
- { .compatible = "ti,ads7952", .data = &ti_ads7950_chip_info[TI_ADS7952] },
- { .compatible = "ti,ads7953", .data = &ti_ads7950_chip_info[TI_ADS7953] },
- { .compatible = "ti,ads7954", .data = &ti_ads7950_chip_info[TI_ADS7954] },
- { .compatible = "ti,ads7955", .data = &ti_ads7950_chip_info[TI_ADS7955] },
- { .compatible = "ti,ads7956", .data = &ti_ads7950_chip_info[TI_ADS7956] },
- { .compatible = "ti,ads7957", .data = &ti_ads7950_chip_info[TI_ADS7957] },
- { .compatible = "ti,ads7958", .data = &ti_ads7950_chip_info[TI_ADS7958] },
- { .compatible = "ti,ads7959", .data = &ti_ads7950_chip_info[TI_ADS7959] },
- { .compatible = "ti,ads7960", .data = &ti_ads7950_chip_info[TI_ADS7960] },
- { .compatible = "ti,ads7961", .data = &ti_ads7950_chip_info[TI_ADS7961] },
+ { .compatible = "ti,ads7950", .data = &ti_ads7950_chip_info },
+ { .compatible = "ti,ads7951", .data = &ti_ads7951_chip_info },
+ { .compatible = "ti,ads7952", .data = &ti_ads7952_chip_info },
+ { .compatible = "ti,ads7953", .data = &ti_ads7953_chip_info },
+ { .compatible = "ti,ads7954", .data = &ti_ads7954_chip_info },
+ { .compatible = "ti,ads7955", .data = &ti_ads7955_chip_info },
+ { .compatible = "ti,ads7956", .data = &ti_ads7956_chip_info },
+ { .compatible = "ti,ads7957", .data = &ti_ads7957_chip_info },
+ { .compatible = "ti,ads7958", .data = &ti_ads7958_chip_info },
+ { .compatible = "ti,ads7959", .data = &ti_ads7959_chip_info },
+ { .compatible = "ti,ads7960", .data = &ti_ads7960_chip_info },
+ { .compatible = "ti,ads7961", .data = &ti_ads7961_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ads7950_of_table);
@@ -722,7 +658,6 @@ static struct spi_driver ti_ads7950_driver = {
.of_match_table = ads7950_of_table,
},
.probe = ti_ads7950_probe,
- .remove = ti_ads7950_remove,
.id_table = ti_ads7950_id,
};
module_spi_driver(ti_ads7950_driver);
diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c
index b0bf46cae0b6..8ad070b5ec4c 100644
--- a/drivers/iio/adc/ti-ads8688.c
+++ b/drivers/iio/adc/ti-ads8688.c
@@ -6,18 +6,15 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
-#include <linux/iio/sysfs.h>
#define ADS8688_CMD_REG(x) (x << 8)
#define ADS8688_CMD_REG_NOOP 0x00
@@ -66,6 +63,7 @@ struct ads8688_state {
const struct ads8688_chip_info *chip_info;
struct spi_device *spi;
unsigned int vref_mv;
+ int scale_avail[3][2];
enum ads8688_range range[8];
union {
__be32 d32;
@@ -114,37 +112,9 @@ static const struct ads8688_ranges ads8688_range_def[5] = {
}
};
-static ssize_t ads8688_show_scales(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct ads8688_state *st = iio_priv(dev_to_iio_dev(dev));
-
- return sprintf(buf, "0.%09u 0.%09u 0.%09u\n",
- ads8688_range_def[0].scale * st->vref_mv,
- ads8688_range_def[1].scale * st->vref_mv,
- ads8688_range_def[2].scale * st->vref_mv);
-}
-
-static ssize_t ads8688_show_offsets(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d %d\n", ads8688_range_def[0].offset,
- ads8688_range_def[3].offset);
-}
-
-static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO,
- ads8688_show_scales, NULL, 0);
-static IIO_DEVICE_ATTR(in_voltage_offset_available, S_IRUGO,
- ads8688_show_offsets, NULL, 0);
-
-static struct attribute *ads8688_attributes[] = {
- &iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
- &iio_dev_attr_in_voltage_offset_available.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ads8688_attribute_group = {
- .attrs = ads8688_attributes,
+static const int ads8688_offset_avail[] = {
+ -(1 << (ADS8688_REALBITS - 1)),
+ 0
};
#define ADS8688_CHAN(index) \
@@ -155,6 +125,9 @@ static const struct attribute_group ads8688_attribute_group = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
| BIT(IIO_CHAN_INFO_SCALE) \
| BIT(IIO_CHAN_INFO_OFFSET), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = index, \
.scan_type = { \
.sign = 'u', \
@@ -369,11 +342,34 @@ static int ads8688_write_raw_get_fmt(struct iio_dev *indio_dev,
return -EINVAL;
}
+static int ads8688_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct ads8688_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (const int *)st->scale_avail;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ *length = ARRAY_SIZE(st->scale_avail) * 2;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_OFFSET:
+ *vals = ads8688_offset_avail;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(ads8688_offset_avail);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct iio_info ads8688_info = {
.read_raw = &ads8688_read_raw,
+ .read_avail = &ads8688_read_avail,
.write_raw = &ads8688_write_raw,
.write_raw_get_fmt = &ads8688_write_raw_get_fmt,
- .attrs = &ads8688_attribute_group,
};
static irqreturn_t ads8688_trigger_handler(int irq, void *p)
@@ -426,6 +422,11 @@ static int ads8688_probe(struct spi_device *spi)
st->vref_mv = ret == -ENODEV ? ADS8688_VREF_MV : ret / 1000;
+ for (unsigned int i = 0; i < ARRAY_SIZE(st->scale_avail); i++) {
+ st->scale_avail[i][0] = 0;
+ st->scale_avail[i][1] = ads8688_range_def[i].scale * st->vref_mv;
+ }
+
st->chip_info = &ads8688_chip_info_tbl[spi_get_device_id(spi)->driver_data];
spi->mode = SPI_MODE_1;
@@ -452,8 +453,8 @@ static int ads8688_probe(struct spi_device *spi)
}
static const struct spi_device_id ads8688_id[] = {
- { "ads8684", ID_ADS8684 },
- { "ads8688", ID_ADS8688 },
+ { .name = "ads8684", .driver_data = ID_ADS8684 },
+ { .name = "ads8688", .driver_data = ID_ADS8688 },
{ }
};
MODULE_DEVICE_TABLE(spi, ads8688_id);
diff --git a/drivers/iio/adc/ti-lmp92064.c b/drivers/iio/adc/ti-lmp92064.c
index 7e57006a8a12..d248bbea0d31 100644
--- a/drivers/iio/adc/ti-lmp92064.c
+++ b/drivers/iio/adc/ti-lmp92064.c
@@ -357,7 +357,7 @@ static int lmp92064_adc_probe(struct spi_device *spi)
}
static const struct spi_device_id lmp92064_id_table[] = {
- { "lmp92064" },
+ { .name = "lmp92064" },
{ }
};
MODULE_DEVICE_TABLE(spi, lmp92064_id_table);
diff --git a/drivers/iio/adc/ti-tlc4541.c b/drivers/iio/adc/ti-tlc4541.c
index f67945c62c99..ea776f80de72 100644
--- a/drivers/iio/adc/ti-tlc4541.c
+++ b/drivers/iio/adc/ti-tlc4541.c
@@ -24,7 +24,6 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
@@ -241,8 +240,8 @@ static const struct of_device_id tlc4541_dt_ids[] = {
MODULE_DEVICE_TABLE(of, tlc4541_dt_ids);
static const struct spi_device_id tlc4541_id[] = {
- { "tlc3541", TLC3541 },
- { "tlc4541", TLC4541 },
+ { .name = "tlc3541", .driver_data = TLC3541 },
+ { .name = "tlc4541", .driver_data = TLC4541 },
{ }
};
MODULE_DEVICE_TABLE(spi, tlc4541_id);
diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c
index aba4b10a17ac..125f6d7e2d84 100644
--- a/drivers/iio/adc/ti-tsc2046.c
+++ b/drivers/iio/adc/ti-tsc2046.c
@@ -121,11 +121,6 @@ struct tsc2046_adc_group_layout {
unsigned int skip;
};
-struct tsc2046_adc_dcfg {
- const struct iio_chan_spec *channels;
- unsigned int num_channels;
-};
-
struct tsc2046_adc_ch_cfg {
unsigned int settling_time_us;
unsigned int oversampling_ratio;
@@ -141,7 +136,6 @@ enum tsc2046_state {
struct tsc2046_adc_priv {
struct spi_device *spi;
- const struct tsc2046_adc_dcfg *dcfg;
bool internal_vref;
struct iio_trigger *trig;
@@ -214,11 +208,6 @@ const struct iio_chan_spec name ## _channels[] = { \
static DECLARE_TI_TSC2046_8_CHANNELS(tsc2046_adc, 12);
-static const struct tsc2046_adc_dcfg tsc2046_adc_dcfg_tsc2046e = {
- .channels = tsc2046_adc_channels,
- .num_channels = ARRAY_SIZE(tsc2046_adc_channels),
-};
-
/*
* Convert time to a number of samples which can be transferred within this
* time.
@@ -739,7 +728,6 @@ static void tsc2046_adc_parse_fwnode(struct tsc2046_adc_priv *priv)
static int tsc2046_adc_probe(struct spi_device *spi)
{
- const struct tsc2046_adc_dcfg *dcfg;
struct device *dev = &spi->dev;
struct tsc2046_adc_priv *priv;
struct iio_dev *indio_dev;
@@ -752,10 +740,6 @@ static int tsc2046_adc_probe(struct spi_device *spi)
return -EINVAL;
}
- dcfg = spi_get_device_match_data(spi);
- if (!dcfg)
- return -EINVAL;
-
spi->mode &= ~SPI_MODE_X_MASK;
spi->mode |= SPI_MODE_0;
ret = spi_setup(spi);
@@ -767,14 +751,13 @@ static int tsc2046_adc_probe(struct spi_device *spi)
return -ENOMEM;
priv = iio_priv(indio_dev);
- priv->dcfg = dcfg;
priv->spi = spi;
indio_dev->name = TI_TSC2046_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = dcfg->channels;
- indio_dev->num_channels = dcfg->num_channels;
+ indio_dev->channels = tsc2046_adc_channels;
+ indio_dev->num_channels = ARRAY_SIZE(tsc2046_adc_channels);
indio_dev->info = &tsc2046_adc_info;
ret = devm_regulator_get_enable_read_voltage(dev, "vref");
@@ -829,13 +812,13 @@ static int tsc2046_adc_probe(struct spi_device *spi)
}
static const struct of_device_id ads7950_of_table[] = {
- { .compatible = "ti,tsc2046e-adc", .data = &tsc2046_adc_dcfg_tsc2046e },
+ { .compatible = "ti,tsc2046e-adc" },
{ }
};
MODULE_DEVICE_TABLE(of, ads7950_of_table);
static const struct spi_device_id tsc2046_adc_spi_ids[] = {
- { "tsc2046e-adc", (unsigned long)&tsc2046_adc_dcfg_tsc2046e },
+ { .name = "tsc2046e-adc" },
{ }
};
MODULE_DEVICE_TABLE(spi, tsc2046_adc_spi_ids);
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index a1a28584de93..1516dd332f90 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -113,10 +113,10 @@ static void tiadc_step_config(struct iio_dev *indio_dev)
* There are 16 configurable steps and 8 analog input
* lines available which are shared between Touchscreen and ADC.
*
- * Steps forwards i.e. from 0 towards 16 are used by ADC
- * depending on number of input lines needed.
+ * Steps forward, i.e. from 0 towards 16, are used by ADC
+ * depending on the number of input lines needed.
* Channel would represent which analog input
- * needs to be given to ADC to digitalize data.
+ * needs to be given to ADC to digitize data.
*/
for (i = 0; i < adc_dev->channels; i++) {
int chan;
diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c
index fe3b31ec976e..0ee7e16b5e24 100644
--- a/drivers/iio/adc/twl4030-madc.c
+++ b/drivers/iio/adc/twl4030-madc.c
@@ -19,7 +19,6 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -252,7 +251,7 @@ static const struct s16_fract twl4030_divider_ratios[16] = {
{5, 11}, /* CHANNEL 15 */
};
-/* Conversion table from -3 to 55 degrees Celcius */
+/* Conversion table from -3 to 55 degrees Celsius */
static int twl4030_therm_tbl[] = {
30800, 29500, 28300, 27100,
26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700,
diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c
index 3ac774ebf678..31b1c01baa27 100644
--- a/drivers/iio/adc/twl6030-gpadc.c
+++ b/drivers/iio/adc/twl6030-gpadc.c
@@ -16,7 +16,6 @@
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -416,7 +415,7 @@ static u8 twl6032_channel_to_reg(int channel)
{
/*
* for any prior chosen channel, when the conversion is ready
- * the result is avalable in GPCH0_LSB, GPCH0_MSB.
+ * the result is available in GPCH0_LSB, GPCH0_MSB.
*/
return TWL6032_GPADC_GPCH0_LSB;
diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
new file mode 100644
index 000000000000..1b55d343982e
--- /dev/null
+++ b/drivers/iio/adc/versal-sysmon-core.c
@@ -0,0 +1,1052 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Versal SysMon core driver
+ *
+ * Copyright (C) 2019 - 2022, Xilinx, Inc.
+ * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/limits.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/overflow.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/units.h>
+
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+
+#include "versal-sysmon.h"
+
+/*
+ * Oversampling ratio values exposed to userspace via IIO.
+ * Actual number of samples averaged: 1=none, 2=2x, 4=4x, 8=8x, 16=16x.
+ */
+static const int sysmon_oversampling_avail[] = { 1, 2, 4, 8, 16 };
+
+/* TEMP hysteresis mode bit in SYSMON_TEMP_EV_CFG */
+#define SYSMON_TEMP_HYST_MASK BIT(1)
+
+/* Compute alarm register offset from a channel address */
+#define SYSMON_ALARM_OFFSET(addr) \
+ (SYSMON_ALARM_REG + ((addr) / SYSMON_ALARM_BITS_PER_REG) * SYSMON_REG_STRIDE)
+
+#define SYSMON_CHAN_TEMP(_chan, _address, _name) \
+{ \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .address = _address, \
+ .channel = _chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .datasheet_name = _name, \
+}
+
+enum sysmon_alarm_bit {
+ SYSMON_BIT_ALARM0 = 0,
+ SYSMON_BIT_ALARM1 = 1,
+ SYSMON_BIT_ALARM2 = 2,
+ SYSMON_BIT_ALARM3 = 3,
+ SYSMON_BIT_ALARM4 = 4,
+ SYSMON_BIT_TEMP = 9,
+};
+
+/* Temperature event specification: rising threshold + hysteresis only */
+static const struct iio_event_spec sysmon_temp_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+};
+
+/* Supply event specifications */
+static const struct iio_event_spec sysmon_supply_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+/*
+ * Static temperature channels (always present).
+ *
+ * These are hardware-computed aggregate registers across all active
+ * temperature satellites:
+ * temp: current max temperature across all active satellites
+ * min: current min temperature across all active satellites
+ * max_max: highest peak recorded since last hardware reset
+ * min_min: lowest trough recorded since last hardware reset
+ */
+static const struct iio_chan_spec temp_channels[] = {
+ SYSMON_CHAN_TEMP(0, SYSMON_TEMP_MAX, "temp"),
+ SYSMON_CHAN_TEMP(1, SYSMON_TEMP_MIN, "min"),
+ SYSMON_CHAN_TEMP(2, SYSMON_TEMP_MAX_MAX, "max_max"),
+ SYSMON_CHAN_TEMP(3, SYSMON_TEMP_MIN_MIN, "min_min"),
+};
+
+static void sysmon_q8p7_to_millicelsius(s16 raw_data, int *val)
+{
+ *val = (raw_data * MILLIDEGREE_PER_DEGREE) >> SYSMON_FRACTIONAL_SHIFT;
+}
+
+static void sysmon_millicelsius_to_q8p7(u32 *raw_data, int val)
+{
+ *raw_data = (val << SYSMON_FRACTIONAL_SHIFT) / MILLIDEGREE_PER_DEGREE;
+}
+
+static void sysmon_supply_rawtoprocessed(int raw_data, int *val)
+{
+ int mantissa, format, exponent;
+
+ mantissa = FIELD_GET(SYSMON_MANTISSA_MASK, raw_data);
+ exponent = SYSMON_SUPPLY_MANTISSA_BITS - FIELD_GET(SYSMON_MODE_MASK, raw_data);
+ format = FIELD_GET(SYSMON_FMT_MASK, raw_data);
+ /*
+ * When format bit is set the mantissa is two's complement
+ * (per hardware spec); sign-extend to int for correct arithmetic.
+ */
+ if (format)
+ mantissa = sign_extend32(mantissa, 15);
+
+ *val = (mantissa * (int)MILLI) >> exponent;
+}
+
+static void sysmon_supply_processedtoraw(int val, u32 reg_val, u32 *raw_data)
+{
+ int exponent = FIELD_GET(SYSMON_MODE_MASK, reg_val);
+ int format = FIELD_GET(SYSMON_FMT_MASK, reg_val);
+ int scale, tmp;
+
+ scale = BIT(SYSMON_SUPPLY_MANTISSA_BITS - exponent);
+ tmp = (val * scale) / (int)MILLI;
+
+ if (format)
+ tmp = clamp(tmp, S16_MIN, S16_MAX);
+ else
+ tmp = clamp(tmp, 0, U16_MAX);
+
+ *raw_data = (u16)tmp;
+}
+
+static int sysmon_supply_thresh_offset(unsigned long address, enum iio_event_direction dir)
+{
+ if (dir == IIO_EV_DIR_RISING)
+ return (address * SYSMON_REG_STRIDE) + SYSMON_SUPPLY_TH_UP;
+ if (dir == IIO_EV_DIR_FALLING)
+ return (address * SYSMON_REG_STRIDE) + SYSMON_SUPPLY_TH_LOW;
+
+ return -EINVAL;
+}
+
+static int sysmon_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned int regval;
+ int ret;
+
+ guard(mutex)(&sysmon->lock);
+
+ if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO) {
+ *val = (chan->type == IIO_TEMP) ? sysmon->temp_oversampling :
+ sysmon->supply_oversampling;
+ return IIO_VAL_INT;
+ }
+
+ switch (chan->type) {
+ case IIO_TEMP:
+ if (mask == IIO_CHAN_INFO_SCALE) {
+ /* Q8.7 to millicelsius: raw * 1000 / 128 */
+ *val = MILLIDEGREE_PER_DEGREE;
+ *val2 = BIT(SYSMON_FRACTIONAL_SHIFT);
+ return IIO_VAL_FRACTIONAL;
+ }
+ if (mask != IIO_CHAN_INFO_RAW)
+ return -EINVAL;
+
+ ret = regmap_read(sysmon->regmap, chan->address, &regval);
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(regval, 15);
+ return IIO_VAL_INT;
+
+ case IIO_VOLTAGE:
+ if (mask != IIO_CHAN_INFO_PROCESSED)
+ return -EINVAL;
+
+ ret = regmap_read(sysmon->regmap,
+ chan->address * SYSMON_REG_STRIDE +
+ SYSMON_SUPPLY_BASE, &regval);
+ if (ret)
+ return ret;
+
+ sysmon_supply_rawtoprocessed(regval, val);
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static u32 sysmon_get_event_mask(const struct iio_chan_spec *chan)
+{
+ if (chan->type == IIO_TEMP)
+ return BIT(SYSMON_BIT_TEMP);
+
+ return BIT(chan->address / SYSMON_ALARM_BITS_PER_REG);
+}
+
+static int sysmon_read_alarm_config(struct sysmon *sysmon,
+ unsigned long address)
+{
+ u32 shift = address % SYSMON_ALARM_BITS_PER_REG;
+ u32 offset = SYSMON_ALARM_OFFSET(address);
+
+ return regmap_test_bits(sysmon->regmap, offset, BIT(shift));
+}
+
+static int sysmon_write_alarm_config(struct sysmon *sysmon,
+ unsigned long address, bool enable)
+{
+ u32 shift = address % SYSMON_ALARM_BITS_PER_REG;
+ u32 offset = SYSMON_ALARM_OFFSET(address);
+
+ return regmap_assign_bits(sysmon->regmap, offset, BIT(shift), enable);
+}
+
+static int sysmon_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ u32 mask = sysmon_get_event_mask(chan);
+ unsigned int imr;
+ int config_value;
+ int ret;
+
+ ret = regmap_read(sysmon->regmap, SYSMON_IMR, &imr);
+ if (ret)
+ return ret;
+
+ /* IMR bits are 1=masked, invert to get 1=enabled */
+ imr = ~imr;
+
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ config_value = sysmon_read_alarm_config(sysmon, chan->address);
+ if (config_value < 0)
+ return config_value;
+ return config_value && (imr & mask);
+
+ case IIO_TEMP:
+ /*
+ * Return the administrative state, not the hardware IMR.
+ * The IRQ handler temporarily masks the interrupt during
+ * the polling window; reading IMR would show it as disabled.
+ * temp_mask bit is set when administratively disabled.
+ */
+ return !(sysmon->temp_mask & mask);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sysmon_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ bool state)
+{
+ u32 offset = SYSMON_ALARM_OFFSET(chan->address);
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ u32 mask = sysmon_get_event_mask(chan);
+ unsigned int alarm_config;
+ int ret;
+
+ guard(mutex)(&sysmon->lock);
+
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ ret = sysmon_write_alarm_config(sysmon, chan->address, state);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(sysmon->regmap, offset, &alarm_config);
+ if (ret)
+ return ret;
+
+ if (alarm_config)
+ return regmap_write(sysmon->regmap, SYSMON_IER, mask);
+
+ return regmap_write(sysmon->regmap, SYSMON_IDR, mask);
+
+ case IIO_TEMP:
+ if (state) {
+ ret = regmap_write(sysmon->regmap, SYSMON_IER, mask);
+ if (ret)
+ return ret;
+
+ scoped_guard(spinlock_irq, &sysmon->irq_lock)
+ sysmon->temp_mask &= ~mask;
+ } else {
+ ret = regmap_write(sysmon->regmap, SYSMON_IDR, mask);
+ if (ret)
+ return ret;
+
+ scoped_guard(spinlock_irq, &sysmon->irq_lock)
+ sysmon->temp_mask |= mask;
+ }
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * Recompute the lower threshold register from upper threshold and
+ * cached hysteresis. Called when either upper threshold or hysteresis
+ * is written.
+ */
+static int sysmon_update_temp_lower(struct sysmon *sysmon)
+{
+ unsigned int upper_reg;
+ int upper_mc, lower_mc;
+ u32 raw_val;
+ int ret;
+
+ ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg);
+ if (ret)
+ return ret;
+
+ sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc);
+ lower_mc = clamp(upper_mc - sysmon->temp_hysteresis, -256000, 255992);
+ sysmon_millicelsius_to_q8p7(&raw_val, lower_mc);
+
+ return regmap_write(sysmon->regmap, SYSMON_TEMP_TH_LOW, raw_val);
+}
+
+static int sysmon_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned int reg_val;
+ int offset;
+ int ret;
+
+ guard(mutex)(&sysmon->lock);
+
+ switch (chan->type) {
+ case IIO_TEMP:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &reg_val);
+ if (ret)
+ return ret;
+
+ sysmon_q8p7_to_millicelsius(reg_val, val);
+
+ return IIO_VAL_INT;
+
+ case IIO_EV_INFO_HYSTERESIS:
+ *val = sysmon->temp_hysteresis;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+
+ case IIO_VOLTAGE:
+ offset = sysmon_supply_thresh_offset(chan->address, dir);
+ if (offset < 0)
+ return offset;
+
+ ret = regmap_read(sysmon->regmap, offset, &reg_val);
+ if (ret)
+ return ret;
+
+ sysmon_supply_rawtoprocessed(reg_val, val);
+
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sysmon_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned int reg_val;
+ u32 raw_val;
+ int offset;
+ int ret;
+
+ guard(mutex)(&sysmon->lock);
+
+ switch (chan->type) {
+ case IIO_TEMP:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ /* Q8.7 signed range: -256000 to +255992 mC */
+ if (val < -256000 || val > 255992)
+ return -EINVAL;
+
+ sysmon_millicelsius_to_q8p7(&raw_val, val);
+
+ ret = regmap_write(sysmon->regmap, SYSMON_TEMP_TH_UP, raw_val);
+ if (ret)
+ return ret;
+
+ /* Recompute lower = upper - hysteresis */
+ return sysmon_update_temp_lower(sysmon);
+
+ case IIO_EV_INFO_HYSTERESIS:
+ if (val < 0)
+ return -EINVAL;
+
+ sysmon->temp_hysteresis = val;
+
+ return sysmon_update_temp_lower(sysmon);
+
+ default:
+ return -EINVAL;
+ }
+
+ case IIO_VOLTAGE:
+ offset = sysmon_supply_thresh_offset(chan->address, dir);
+ if (offset < 0)
+ return offset;
+
+ ret = regmap_read(sysmon->regmap, offset, &reg_val);
+ if (ret)
+ return ret;
+
+ /* Clamp to prevent overflow in processedtoraw conversion */
+ if (val < -32768 || val > 32767)
+ return -EINVAL;
+
+ sysmon_supply_processedtoraw(val, reg_val, &raw_val);
+
+ /*
+ * The hardware threshold register returns FMT and MODE
+ * bits in the upper 16 bits on read, but only the lower
+ * 16-bit mantissa is used on write.
+ */
+ return regmap_write(sysmon->regmap, offset, raw_val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sysmon_set_avg_enable(struct sysmon *sysmon,
+ u32 base, u32 count, u32 val)
+{
+ struct regmap *map = sysmon->regmap;
+ int ret;
+
+ for (unsigned int i = 0; i < count; i++) {
+ ret = regmap_write(map, base + i * SYSMON_REG_STRIDE, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sysmon_osr_write_temp(struct sysmon *sysmon, unsigned int val)
+{
+ /*
+ * HW register encoding is sample_count / 2:
+ * 0=none, 1=2x, 2=4x, 4=8x, 8=16x (not log2-based).
+ */
+ unsigned int hw_val = val >> 1;
+ unsigned int readback;
+ int ret;
+
+ ret = regmap_update_bits(sysmon->regmap, SYSMON_CONFIG,
+ SYSMON_CONFIG_TEMP_SAT_OSR,
+ FIELD_PREP(SYSMON_CONFIG_TEMP_SAT_OSR, hw_val));
+ if (ret)
+ return ret;
+
+ /*
+ * Readback fence: the SysMon CONFIG register resides in the
+ * PMC domain behind the NoC. A posted write may not reach the
+ * hardware before the next MMIO access. Reading the register
+ * back forces the interconnect to complete the write, preventing
+ * a bus hang on the subsequent access.
+ */
+ regmap_read(sysmon->regmap, SYSMON_CONFIG, &readback);
+
+ return sysmon_set_avg_enable(sysmon, SYSMON_TEMP_EN_AVG_BASE,
+ SYSMON_TEMP_EN_AVG_COUNT,
+ hw_val ? ~0 : 0);
+}
+
+static int sysmon_osr_write_supply(struct sysmon *sysmon, unsigned int val)
+{
+ /* HW encoding: sample_count / 2 (see sysmon_osr_write_temp) */
+ unsigned int hw_val = val >> 1;
+ unsigned int readback;
+ int ret;
+
+ ret = regmap_update_bits(sysmon->regmap, SYSMON_CONFIG,
+ SYSMON_CONFIG_SUPPLY_OSR,
+ FIELD_PREP(SYSMON_CONFIG_SUPPLY_OSR, hw_val));
+ if (ret)
+ return ret;
+
+ /* Readback fence -- see sysmon_osr_write_temp for details */
+ regmap_read(sysmon->regmap, SYSMON_CONFIG, &readback);
+
+ return sysmon_set_avg_enable(sysmon, SYSMON_SUPPLY_EN_AVG_BASE,
+ SYSMON_SUPPLY_EN_AVG_COUNT,
+ hw_val ? ~0 : 0);
+}
+
+static int sysmon_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned int i;
+ int ret;
+
+ if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(sysmon_oversampling_avail); i++) {
+ if (val == sysmon_oversampling_avail[i])
+ break;
+ }
+ if (i == ARRAY_SIZE(sysmon_oversampling_avail))
+ return -EINVAL;
+
+ guard(mutex)(&sysmon->lock);
+
+ if (chan->type == IIO_TEMP) {
+ ret = sysmon_osr_write_temp(sysmon, val);
+ if (ret)
+ return ret;
+ sysmon->temp_oversampling = val;
+ } else {
+ ret = sysmon_osr_write_supply(sysmon, val);
+ if (ret)
+ return ret;
+ sysmon->supply_oversampling = val;
+ }
+
+ return 0;
+}
+
+static int sysmon_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO)
+ return IIO_VAL_INT;
+
+ return -EINVAL;
+}
+
+static int sysmon_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type,
+ int *length, long mask)
+{
+ if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
+ return -EINVAL;
+
+ *vals = sysmon_oversampling_avail;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(sysmon_oversampling_avail);
+
+ return IIO_AVAIL_LIST;
+}
+
+static int sysmon_read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ char *label)
+{
+ if (chan->datasheet_name)
+ return sysfs_emit(label, "%s\n", chan->datasheet_name);
+
+ return -EINVAL;
+}
+
+static const struct iio_info sysmon_iio_info = {
+ .read_raw = sysmon_read_raw,
+ .write_raw = sysmon_write_raw,
+ .write_raw_get_fmt = sysmon_write_raw_get_fmt,
+ .read_avail = sysmon_read_avail,
+ .read_label = sysmon_read_label,
+ .read_event_config = sysmon_read_event_config,
+ .write_event_config = sysmon_write_event_config,
+ .read_event_value = sysmon_read_event_value,
+ .write_event_value = sysmon_write_event_value,
+};
+
+static void sysmon_push_event(struct iio_dev *indio_dev, u32 address)
+{
+ const struct iio_chan_spec *chan;
+ enum iio_event_direction dir;
+
+ for (unsigned int i = 0; i < indio_dev->num_channels; i++) {
+ if (indio_dev->channels[i].address != address)
+ continue;
+
+ chan = &indio_dev->channels[i];
+ /* Temp uses hysteresis mode (rising only), voltage uses window */
+ dir = (chan->type == IIO_TEMP) ? IIO_EV_DIR_RISING :
+ IIO_EV_DIR_EITHER;
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(chan->type,
+ chan->channel,
+ IIO_EV_TYPE_THRESH,
+ dir),
+ iio_get_time_ns(indio_dev));
+ }
+}
+
+static int sysmon_handle_event(struct iio_dev *indio_dev, u32 event)
+{
+ u32 alarm_flag_offset = SYSMON_ALARM_FLAG + event * SYSMON_REG_STRIDE;
+ u32 alarm_reg_offset = SYSMON_ALARM_REG + event * SYSMON_REG_STRIDE;
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned long alarm_flag_reg;
+ unsigned int reg_val;
+ u32 address, bit;
+ int ret;
+
+ switch (event) {
+ case SYSMON_BIT_TEMP:
+ sysmon_push_event(indio_dev, SYSMON_TEMP_MAX);
+
+ ret = regmap_write(sysmon->regmap, SYSMON_IDR, BIT(SYSMON_BIT_TEMP));
+ if (ret)
+ return ret;
+
+ sysmon->masked_temp |= BIT(SYSMON_BIT_TEMP);
+ return 0;
+
+ case SYSMON_BIT_ALARM0:
+ case SYSMON_BIT_ALARM1:
+ case SYSMON_BIT_ALARM2:
+ case SYSMON_BIT_ALARM3:
+ case SYSMON_BIT_ALARM4:
+ ret = regmap_read(sysmon->regmap, alarm_flag_offset, &reg_val);
+ if (ret)
+ return ret;
+
+ alarm_flag_reg = reg_val;
+
+ for_each_set_bit(bit, &alarm_flag_reg, SYSMON_ALARM_BITS_PER_REG) {
+ address = bit + SYSMON_ALARM_BITS_PER_REG * event;
+ sysmon_push_event(indio_dev, address);
+ ret = regmap_clear_bits(sysmon->regmap, alarm_reg_offset, BIT(bit));
+ if (ret)
+ return ret;
+ }
+
+ return regmap_write(sysmon->regmap, alarm_flag_offset, alarm_flag_reg);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static void sysmon_handle_events(struct iio_dev *indio_dev,
+ unsigned long events)
+{
+ unsigned int bit;
+
+ for_each_set_bit(bit, &events, SYSMON_NO_OF_EVENTS)
+ sysmon_handle_event(indio_dev, bit);
+}
+
+static void sysmon_unmask_temp(struct sysmon *sysmon, unsigned int isr)
+{
+ unsigned int status;
+ u32 ier;
+
+ status = isr & SYSMON_TEMP_INTR_MASK;
+
+ ier = ~status & sysmon->masked_temp;
+ sysmon->masked_temp &= status;
+
+ /* Only unmask if not administratively disabled by userspace */
+ ier &= ~sysmon->temp_mask;
+
+ regmap_write(sysmon->regmap, SYSMON_IER, ier);
+}
+
+/*
+ * Versal threshold interrupts are level-sensitive. Active threshold
+ * interrupts are masked in the handler and polled via delayed work
+ * until the condition clears, then unmasked.
+ */
+static void sysmon_unmask_worker(struct work_struct *work)
+{
+ struct sysmon *sysmon =
+ container_of(work, struct sysmon, sysmon_unmask_work.work);
+ unsigned int isr;
+
+ /*
+ * If the ISR read fails, skip processing to avoid acting
+ * on undefined data.
+ */
+ scoped_guard(spinlock_irq, &sysmon->irq_lock) {
+ if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr))
+ break;
+ regmap_write(sysmon->regmap, SYSMON_ISR, isr);
+ sysmon_unmask_temp(sysmon, isr);
+ }
+
+ if (sysmon->masked_temp)
+ schedule_delayed_work(&sysmon->sysmon_unmask_work,
+ msecs_to_jiffies(SYSMON_UNMASK_WORK_DELAY_MS));
+ else
+ regmap_write(sysmon->regmap, SYSMON_STATUS_RESET, 1);
+}
+
+static irqreturn_t sysmon_iio_irq(int irq, void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned int isr, imr;
+
+ guard(spinlock)(&sysmon->irq_lock);
+
+ if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr) ||
+ regmap_read(sysmon->regmap, SYSMON_IMR, &imr))
+ return IRQ_NONE;
+
+ isr &= ~imr;
+ if (!isr)
+ return IRQ_NONE;
+
+ regmap_write(sysmon->regmap, SYSMON_ISR, isr);
+
+ sysmon_handle_events(indio_dev, isr);
+ schedule_delayed_work(&sysmon->sysmon_unmask_work,
+ msecs_to_jiffies(SYSMON_UNMASK_WORK_DELAY_MS));
+
+ return IRQ_HANDLED;
+}
+
+static void sysmon_disable_interrupts(void *data)
+{
+ struct sysmon *sysmon = data;
+
+ regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK);
+
+ scoped_guard(spinlock_irq, &sysmon->irq_lock)
+ sysmon->masked_temp = 0;
+
+ cancel_delayed_work_sync(&sysmon->sysmon_unmask_work);
+}
+
+static int sysmon_init_interrupt(struct sysmon *sysmon,
+ struct device *dev,
+ struct iio_dev *indio_dev,
+ int irq)
+{
+ unsigned int imr;
+ int ret;
+
+ /* Events not supported without IRQ (e.g. I2C path) */
+ if (!irq)
+ return 0;
+
+ INIT_DELAYED_WORK(&sysmon->sysmon_unmask_work, sysmon_unmask_worker);
+
+ ret = regmap_read(sysmon->regmap, SYSMON_IMR, &imr);
+ if (ret)
+ return ret;
+ sysmon->temp_mask = imr & SYSMON_TEMP_INTR_MASK;
+
+ ret = devm_request_irq(dev, irq, sysmon_iio_irq, 0, "sysmon-irq", indio_dev);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, sysmon_disable_interrupts, sysmon);
+}
+
+/*
+ * Initialize the cached hysteresis for a temperature channel from the
+ * current hardware threshold registers: hysteresis = upper - lower.
+ */
+static int sysmon_init_hysteresis(struct sysmon *sysmon, int *hysteresis)
+{
+ unsigned int upper_reg, lower_reg;
+ int upper_mc, lower_mc;
+ int ret;
+
+ ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_LOW, &lower_reg);
+ if (ret)
+ return ret;
+
+ sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc);
+ sysmon_q8p7_to_millicelsius(lower_reg, &lower_mc);
+ *hysteresis = upper_mc - lower_mc;
+
+ return 0;
+}
+
+/**
+ * sysmon_parse_fw() - Parse firmware nodes and configure IIO channels.
+ * @indio_dev: IIO device instance
+ * @dev: Parent device
+ * @irq: IRQ number (positive enables event channels, 0 disables)
+ *
+ * Reads voltage-channels and temperature-channels container nodes from
+ * firmware and builds the IIO channel array. Static temperature channels
+ * and event channels are prepended, followed by supply and satellite
+ * channels from DT.
+ *
+ * Event channels and per-channel event specs are only added when the
+ * device has an IRQ. I2C devices have no interrupt line, and the I2C
+ * regmap cannot be called from atomic context, so events are not
+ * supported on that path.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev, int irq)
+{
+ unsigned int num_chan, num_static, num_supply, num_temp;
+ unsigned int idx, temp_chan_idx, volt_chan_idx;
+ struct iio_chan_spec *sysmon_channels;
+ const char *label;
+ u32 reg;
+ int ret;
+
+ struct fwnode_handle *supply_node __free(fwnode_handle) =
+ device_get_named_child_node(dev, "voltage-channels");
+ num_supply = fwnode_get_child_node_count(supply_node);
+
+ struct fwnode_handle *temp_node __free(fwnode_handle) =
+ device_get_named_child_node(dev, "temperature-channels");
+ num_temp = fwnode_get_child_node_count(temp_node);
+
+ num_static = ARRAY_SIZE(temp_channels);
+ num_chan = size_add(num_temp, size_add(num_static, num_supply));
+ sysmon_channels = devm_kcalloc(dev, num_chan, sizeof(*sysmon_channels), GFP_KERNEL);
+ if (!sysmon_channels)
+ return -ENOMEM;
+
+ memcpy(sysmon_channels, temp_channels, sizeof(temp_channels));
+
+ /* Attach event spec to channel 0 when IRQ is available */
+ if (irq > 0) {
+ sysmon_channels[0].event_spec = sysmon_temp_events;
+ sysmon_channels[0].num_event_specs = ARRAY_SIZE(sysmon_temp_events);
+ }
+
+ idx = num_static;
+
+ /* Supply channels from DT */
+ fwnode_for_each_child_node_scoped(supply_node, child) {
+ ret = fwnode_property_read_u32(child, "reg", &reg);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "missing reg for supply channel\n");
+
+ if (reg > SYSMON_SUPPLY_IDX_MAX)
+ return dev_err_probe(dev, -EINVAL,
+ "supply reg %u exceeds max %u\n",
+ reg, SYSMON_SUPPLY_IDX_MAX);
+
+ ret = fwnode_property_read_string(child, "label", &label);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "missing label for supply channel\n");
+
+ sysmon_channels[idx++] = (struct iio_chan_spec) {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .address = reg,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_type =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .event_spec = irq > 0 ?
+ sysmon_supply_events : NULL,
+ .num_event_specs = irq > 0 ?
+ ARRAY_SIZE(sysmon_supply_events) : 0,
+ .datasheet_name = label,
+ };
+ }
+
+ /* Temperature satellite channels from DT */
+ fwnode_for_each_child_node_scoped(temp_node, child) {
+ ret = fwnode_property_read_u32(child, "reg", &reg);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "missing reg for temp channel\n");
+
+ if (reg < 1 || reg > SYSMON_TEMP_SAT_MAX)
+ return dev_err_probe(dev, -EINVAL,
+ "temp reg %u out of range [1..%u]\n",
+ reg, SYSMON_TEMP_SAT_MAX);
+
+ ret = fwnode_property_read_string(child, "label", &label);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "missing label for temp channel\n");
+
+ sysmon_channels[idx++] = (struct iio_chan_spec) {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .address = SYSMON_TEMP_SAT_BASE +
+ (reg - 1) * SYSMON_REG_STRIDE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type =
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .datasheet_name = label,
+ };
+ }
+
+ indio_dev->num_channels = idx;
+ indio_dev->info = &sysmon_iio_info;
+
+ /*
+ * Assign per-type sequential channel numbers.
+ * IIO sysfs uses type prefix (in_tempN, in_voltageN)
+ * so numbers only need to be unique within each type.
+ */
+ temp_chan_idx = 0;
+ volt_chan_idx = 0;
+ for (unsigned int idx = 0; idx < indio_dev->num_channels; idx++) {
+ if (sysmon_channels[idx].type == IIO_TEMP)
+ sysmon_channels[idx].channel = temp_chan_idx++;
+ else
+ sysmon_channels[idx].channel = volt_chan_idx++;
+ }
+
+ indio_dev->channels = sysmon_channels;
+
+ return 0;
+}
+
+/**
+ * devm_versal_sysmon_core_probe() - Initialize Versal SysMon core
+ * @dev: Parent device
+ * @regmap: Register map for hardware access
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap)
+{
+ struct iio_dev *indio_dev;
+ struct sysmon *sysmon;
+ int irq;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*sysmon));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ sysmon = iio_priv(indio_dev);
+ sysmon->regmap = regmap;
+ sysmon->temp_oversampling = 1;
+ sysmon->supply_oversampling = 1;
+
+ ret = devm_mutex_init(dev, &sysmon->lock);
+ if (ret)
+ return ret;
+ spin_lock_init(&sysmon->irq_lock);
+
+ /* Disable all interrupts and clear pending status */
+ ret = regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK);
+ if (ret)
+ return ret;
+ ret = regmap_write(sysmon->regmap, SYSMON_ISR, SYSMON_INTR_ALL_MASK);
+ if (ret)
+ return ret;
+
+ irq = fwnode_irq_get(dev_fwnode(dev), 0);
+ if (irq == -EPROBE_DEFER)
+ return dev_err_probe(dev, irq, "failed to get IRQ\n");
+
+ indio_dev->name = "versal-sysmon";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = sysmon_parse_fw(indio_dev, dev, irq);
+ if (ret)
+ return ret;
+
+ if (irq > 0) {
+ /* Set hysteresis mode for temperature threshold */
+ ret = regmap_set_bits(sysmon->regmap, SYSMON_TEMP_EV_CFG,
+ SYSMON_TEMP_HYST_MASK);
+ if (ret)
+ return ret;
+
+ /* Initialize cached hysteresis from hardware registers */
+ ret = sysmon_init_hysteresis(sysmon, &sysmon->temp_hysteresis);
+ if (ret)
+ return ret;
+
+ ret = sysmon_init_interrupt(sysmon, dev, indio_dev, irq);
+ if (ret)
+ return ret;
+ }
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_NS_GPL(devm_versal_sysmon_core_probe, "VERSAL_SYSMON");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AMD Versal SysMon Core Driver");
+MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>");
diff --git a/drivers/iio/adc/versal-sysmon-i2c.c b/drivers/iio/adc/versal-sysmon-i2c.c
new file mode 100644
index 000000000000..e9a7629159ab
--- /dev/null
+++ b/drivers/iio/adc/versal-sysmon-i2c.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Versal SysMon I2C driver
+ *
+ * Copyright (C) 2023 - 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/bits.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#include "versal-sysmon.h"
+
+#define SYSMON_I2C_INSTR_READ BIT(2)
+#define SYSMON_I2C_INSTR_WRITE BIT(3)
+
+/*
+ * I2C command frame layout (8 bytes):
+ * [0..3] data payload (little-endian u32)
+ * [4..5] register offset >> 2 (little-endian u16)
+ * [6] instruction (read/write)
+ * [7] reserved
+ */
+#define SYSMON_I2C_DATA_OFS 0
+#define SYSMON_I2C_REG_OFS 4
+#define SYSMON_I2C_INSTR_OFS 6
+
+static int sysmon_i2c_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct i2c_client *client = context;
+ u8 write_buf[8] = { };
+ u8 read_buf[4];
+ int ret;
+
+ put_unaligned_le16(reg >> 2, &write_buf[SYSMON_I2C_REG_OFS]);
+ write_buf[SYSMON_I2C_INSTR_OFS] = SYSMON_I2C_INSTR_READ;
+
+ ret = i2c_master_send(client, write_buf, sizeof(write_buf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(write_buf))
+ return -EIO;
+
+ ret = i2c_master_recv(client, read_buf, sizeof(read_buf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(read_buf))
+ return -EIO;
+
+ *val = get_unaligned_le32(read_buf);
+
+ return 0;
+}
+
+static int sysmon_i2c_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct i2c_client *client = context;
+ u8 write_buf[8] = { };
+ int ret;
+
+ put_unaligned_le32(val, &write_buf[SYSMON_I2C_DATA_OFS]);
+ put_unaligned_le16(reg >> 2, &write_buf[SYSMON_I2C_REG_OFS]);
+ write_buf[SYSMON_I2C_INSTR_OFS] = SYSMON_I2C_INSTR_WRITE;
+
+ ret = i2c_master_send(client, write_buf, sizeof(write_buf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(write_buf))
+ return -EIO;
+
+ return 0;
+}
+
+/*
+ * Almost all registers are volatile (live ADC readings, interrupt
+ * status). The rest are not accessed often enough to benefit from
+ * caching.
+ */
+static const struct regmap_config sysmon_i2c_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = SYSMON_REG_STRIDE,
+ .max_register = SYSMON_MAX_REG,
+ .reg_read = sysmon_i2c_reg_read,
+ .reg_write = sysmon_i2c_reg_write,
+};
+
+static int sysmon_i2c_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init(dev, NULL, client, &sysmon_i2c_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* I2C has no IRQ connection; events are not supported */
+ return devm_versal_sysmon_core_probe(dev, regmap);
+}
+
+static const struct of_device_id sysmon_i2c_of_match_table[] = {
+ { .compatible = "xlnx,versal-sysmon" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sysmon_i2c_of_match_table);
+
+static const struct i2c_device_id sysmon_i2c_id_table[] = {
+ { .name = "versal-sysmon" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sysmon_i2c_id_table);
+
+static struct i2c_driver sysmon_i2c_driver = {
+ .probe = sysmon_i2c_probe,
+ .driver = {
+ .name = "versal-sysmon-i2c",
+ .of_match_table = sysmon_i2c_of_match_table,
+ },
+ .id_table = sysmon_i2c_id_table,
+};
+module_i2c_driver(sysmon_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AMD Versal SysMon I2C Driver");
+MODULE_IMPORT_NS("VERSAL_SYSMON");
+MODULE_AUTHOR("Conall O'Griofa <conall.ogriofa@amd.com>");
+MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>");
diff --git a/drivers/iio/adc/versal-sysmon.c b/drivers/iio/adc/versal-sysmon.c
new file mode 100644
index 000000000000..529d0486c9f9
--- /dev/null
+++ b/drivers/iio/adc/versal-sysmon.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Versal SysMon MMIO platform driver
+ *
+ * Copyright (C) 2019 - 2022, Xilinx, Inc.
+ * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include "versal-sysmon.h"
+
+struct sysmon_mmio {
+ void __iomem *base;
+};
+
+static int sysmon_mmio_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct sysmon_mmio *mmio = context;
+
+ *val = readl(mmio->base + reg);
+ return 0;
+}
+
+static int sysmon_mmio_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct sysmon_mmio *mmio = context;
+
+ /* NPI must be unlocked before any register write except to NPI_LOCK */
+ if (reg != SYSMON_NPI_LOCK)
+ writel(SYSMON_NPI_UNLOCK_CODE, mmio->base + SYSMON_NPI_LOCK);
+ writel(val, mmio->base + reg);
+
+ return 0;
+}
+
+static const struct regmap_config sysmon_mmio_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = SYSMON_REG_STRIDE,
+ .max_register = SYSMON_MAX_REG,
+ .reg_read = sysmon_mmio_reg_read,
+ .reg_write = sysmon_mmio_reg_write,
+ .fast_io = true,
+};
+
+static int sysmon_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sysmon_mmio *mmio;
+ struct regmap *regmap;
+
+ mmio = devm_kzalloc(dev, sizeof(*mmio), GFP_KERNEL);
+ if (!mmio)
+ return -ENOMEM;
+
+ mmio->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(mmio->base))
+ return PTR_ERR(mmio->base);
+
+ regmap = devm_regmap_init(dev, NULL, mmio, &sysmon_mmio_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return devm_versal_sysmon_core_probe(dev, regmap);
+}
+
+static const struct of_device_id sysmon_of_match_table[] = {
+ { .compatible = "xlnx,versal-sysmon" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sysmon_of_match_table);
+
+static struct platform_driver sysmon_platform_driver = {
+ .probe = sysmon_platform_probe,
+ .driver = {
+ .name = "versal-sysmon",
+ .of_match_table = sysmon_of_match_table,
+ },
+};
+module_platform_driver(sysmon_platform_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AMD Versal SysMon Platform Driver");
+MODULE_IMPORT_NS("VERSAL_SYSMON");
+MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>");
diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h
new file mode 100644
index 000000000000..bb9a75bf71c0
--- /dev/null
+++ b/drivers/iio/adc/versal-sysmon.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AMD Versal SysMon driver
+ *
+ * Copyright (C) 2019 - 2022, Xilinx, Inc.
+ * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
+ */
+
+#ifndef _VERSAL_SYSMON_H_
+#define _VERSAL_SYSMON_H_
+
+#include <linux/bits.h>
+#include <linux/mutex.h>
+#include <linux/spinlock_types.h>
+#include <linux/workqueue.h>
+
+struct device;
+struct regmap;
+
+/* Register offsets (sorted by address) */
+#define SYSMON_NPI_LOCK 0x000C
+#define SYSMON_ISR 0x0044
+#define SYSMON_IMR 0x0048
+#define SYSMON_IER 0x004C
+#define SYSMON_IDR 0x0050
+#define SYSMON_CONFIG 0x0100
+#define SYSMON_TEMP_MAX 0x1030
+#define SYSMON_TEMP_MIN 0x1034
+#define SYSMON_SUPPLY_BASE 0x1040
+#define SYSMON_ALARM_FLAG 0x1018
+#define SYSMON_ALARM_REG 0x1940
+#define SYSMON_SUPPLY_EN_AVG_BASE 0x1958
+#define SYSMON_TEMP_TH_LOW 0x1970
+#define SYSMON_TEMP_TH_UP 0x1974
+#define SYSMON_SUPPLY_TH_LOW 0x1980
+#define SYSMON_SUPPLY_TH_UP 0x1C80
+#define SYSMON_TEMP_EV_CFG 0x1F84
+#define SYSMON_TEMP_MIN_MIN 0x1F8C
+#define SYSMON_TEMP_MAX_MAX 0x1F90
+#define SYSMON_STATUS_RESET 0x1F94
+#define SYSMON_TEMP_SAT_BASE 0x1FAC
+#define SYSMON_TEMP_EN_AVG_BASE 0x24B4
+#define SYSMON_MAX_REG 0x24C0
+
+/* NPI unlock value written to SYSMON_NPI_LOCK */
+#define SYSMON_NPI_UNLOCK_CODE 0xF9E8D7C6
+
+/* Register stride: 4 bytes per 32-bit register */
+#define SYSMON_REG_STRIDE 4
+
+#define SYSMON_SUPPLY_IDX_MAX 159
+#define SYSMON_TEMP_SAT_MAX 64
+#define SYSMON_NO_OF_EVENTS 32
+#define SYSMON_INTR_ALL_MASK GENMASK(31, 0)
+
+/* ISR/IMR temperature alarm mask (bit 9) */
+#define SYSMON_TEMP_INTR_MASK BIT(9)
+
+/* SYSMON_CONFIG: supply oversampling ratio */
+#define SYSMON_CONFIG_SUPPLY_OSR GENMASK(17, 14)
+
+/* SYSMON_CONFIG: temperature satellite oversampling ratio */
+#define SYSMON_CONFIG_TEMP_SAT_OSR GENMASK(27, 24)
+
+/* Per-channel averaging enable register counts */
+#define SYSMON_SUPPLY_EN_AVG_COUNT 5
+#define SYSMON_TEMP_EN_AVG_COUNT 2
+
+/* Supply voltage conversion register fields */
+#define SYSMON_MANTISSA_MASK GENMASK(15, 0)
+#define SYSMON_FMT_MASK BIT(16)
+#define SYSMON_MODE_MASK GENMASK(18, 17)
+
+/* Q8.7 fractional shift */
+#define SYSMON_FRACTIONAL_SHIFT 7U
+#define SYSMON_SUPPLY_MANTISSA_BITS 16
+
+/* Bits per alarm register */
+#define SYSMON_ALARM_BITS_PER_REG 32
+
+#define SYSMON_UNMASK_WORK_DELAY_MS 500
+
+/**
+ * struct sysmon - Driver data for Versal SysMon
+ * @regmap: register map for hardware access
+ * @lock: protects read-modify-write sequences on threshold registers
+ * and cached state that spans multiple regmap calls
+ * @irq_lock: protects interrupt mask register updates (MMIO path only)
+ * @masked_temp: currently masked temperature alarm bits
+ * @temp_mask: temperature interrupt configuration mask
+ * @temp_hysteresis: cached DEVICE_TEMP hysteresis in millicelsius
+ * @sysmon_unmask_work: re-enables events after alarm condition clears
+ * @temp_oversampling: current temp oversampling ratio
+ * @supply_oversampling: current supply oversampling ratio
+ */
+struct sysmon {
+ struct regmap *regmap;
+ /*
+ * Protects read-modify-write sequences on threshold registers
+ * and cached state (oversampling ratios, hysteresis values)
+ * that spans multiple regmap calls.
+ */
+ struct mutex lock;
+ /*
+ * Protects interrupt mask register updates. Only used on the
+ * MMIO path (fast_io regmap); I2C has no IRQ and never reaches
+ * the event code that takes this lock.
+ */
+ spinlock_t irq_lock;
+ unsigned int masked_temp;
+ unsigned int temp_mask;
+ int temp_hysteresis;
+ struct delayed_work sysmon_unmask_work;
+ unsigned int temp_oversampling;
+ unsigned int supply_oversampling;
+};
+
+int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap);
+
+#endif /* _VERSAL_SYSMON_H_ */
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index d7182ed0d2a7..bcbeb482e714 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -5,7 +5,6 @@
* Copyright 2013 Freescale Semiconductor, Inc.
*/
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/property.h>
diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c
index 9bb0b83c8f67..6efe1c618ef7 100644
--- a/drivers/iio/adc/viperboard_adc.c
+++ b/drivers/iio/adc/viperboard_adc.c
@@ -70,8 +70,10 @@ static int vprbrd_iio_read_raw(struct iio_dev *iio_dev,
VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, admsg,
sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS);
if (ret != sizeof(struct vprbrd_adc_msg)) {
- dev_err(&iio_dev->dev, "usb send error on adc read\n");
+ mutex_unlock(&vb->lock);
error = -EREMOTEIO;
+ dev_err(&iio_dev->dev, "usb send error on adc read\n");
+ goto error;
}
ret = usb_control_msg(vb->usb_dev,
diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c
index 124470c92529..158e6133abf5 100644
--- a/drivers/iio/adc/xilinx-ams.c
+++ b/drivers/iio/adc/xilinx-ams.c
@@ -18,7 +18,6 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/overflow.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -102,6 +101,7 @@
#define AMS_PS_SEQ_MASK GENMASK(21, 0)
#define AMS_PL_SEQ_MASK GENMASK_ULL(59, 22)
+#define AMS_ALARM_NONE 0x000 /* not a real offset */
#define AMS_ALARM_TEMP 0x140
#define AMS_ALARM_SUPPLY1 0x144
#define AMS_ALARM_SUPPLY2 0x148
@@ -720,22 +720,20 @@ static int ams_read_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case IIO_CHAN_INFO_RAW:
- mutex_lock(&ams->lock);
+ case IIO_CHAN_INFO_RAW: {
+ guard(mutex)(&ams->lock);
if (chan->scan_index >= AMS_CTRL_SEQ_BASE) {
ret = ams_read_vcc_reg(ams, chan->address, val);
if (ret)
- goto unlock_mutex;
+ return ret;
ams_enable_channel_sequence(indio_dev);
} else if (chan->scan_index >= AMS_PS_SEQ_MAX)
*val = readl(ams->pl_base + chan->address);
else
*val = readl(ams->ps_base + chan->address);
- ret = IIO_VAL_INT;
-unlock_mutex:
- mutex_unlock(&ams->lock);
- return ret;
+ return IIO_VAL_INT;
+ }
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
@@ -765,9 +763,49 @@ unlock_mutex:
}
}
+struct ams_alarm_map {
+ enum ams_ps_pl_seq scan_index;
+ unsigned int base_offset;
+};
+
+/*
+ * Array index matches enum ams_alarm_bit.
+ * Entries with base_offset == AMS_ALARM_NONE are unused/invalid
+ * (e.g. RESERVED) and must be skipped.
+ */
+static const struct ams_alarm_map alarm_map[] = {
+ [AMS_ALARM_BIT_TEMP] = { AMS_SEQ_TEMP, AMS_ALARM_TEMP },
+ [AMS_ALARM_BIT_SUPPLY1] = { AMS_SEQ_SUPPLY1, AMS_ALARM_SUPPLY1 },
+ [AMS_ALARM_BIT_SUPPLY2] = { AMS_SEQ_SUPPLY2, AMS_ALARM_SUPPLY2 },
+ [AMS_ALARM_BIT_SUPPLY3] = { AMS_SEQ_SUPPLY3, AMS_ALARM_SUPPLY3 },
+ [AMS_ALARM_BIT_SUPPLY4] = { AMS_SEQ_SUPPLY4, AMS_ALARM_SUPPLY4 },
+ [AMS_ALARM_BIT_SUPPLY5] = { AMS_SEQ_SUPPLY5, AMS_ALARM_SUPPLY5 },
+ [AMS_ALARM_BIT_SUPPLY6] = { AMS_SEQ_SUPPLY6, AMS_ALARM_SUPPLY6 },
+ [AMS_ALARM_BIT_RESERVED] = { 0, AMS_ALARM_NONE },
+ [AMS_ALARM_BIT_SUPPLY7] = { AMS_SEQ_SUPPLY7, AMS_ALARM_SUPPLY7 },
+ [AMS_ALARM_BIT_SUPPLY8] = { AMS_SEQ_SUPPLY8, AMS_ALARM_SUPPLY8 },
+ [AMS_ALARM_BIT_SUPPLY9] = { AMS_SEQ_SUPPLY9, AMS_ALARM_SUPPLY9 },
+ [AMS_ALARM_BIT_SUPPLY10] = { AMS_SEQ_SUPPLY10, AMS_ALARM_SUPPLY10 },
+ [AMS_ALARM_BIT_VCCAMS] = { AMS_SEQ_VCCAMS, AMS_ALARM_VCCAMS },
+ [AMS_ALARM_BIT_TEMP_REMOTE] = { AMS_SEQ_TEMP_REMOTE, AMS_ALARM_TEMP_REMOTE },
+};
+
+static int ams_scan_index_to_event(int scan_index)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(alarm_map); i++) {
+ if (alarm_map[i].base_offset == AMS_ALARM_NONE)
+ continue;
+
+ if (alarm_map[i].scan_index == scan_index)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
static int ams_get_alarm_offset(int scan_index, enum iio_event_direction dir)
{
- int offset;
+ int offset, event;
if (scan_index >= AMS_PS_SEQ_MAX)
scan_index -= AMS_PS_SEQ_MAX;
@@ -781,36 +819,11 @@ static int ams_get_alarm_offset(int scan_index, enum iio_event_direction dir)
offset = 0;
}
- switch (scan_index) {
- case AMS_SEQ_TEMP:
- return AMS_ALARM_TEMP + offset;
- case AMS_SEQ_SUPPLY1:
- return AMS_ALARM_SUPPLY1 + offset;
- case AMS_SEQ_SUPPLY2:
- return AMS_ALARM_SUPPLY2 + offset;
- case AMS_SEQ_SUPPLY3:
- return AMS_ALARM_SUPPLY3 + offset;
- case AMS_SEQ_SUPPLY4:
- return AMS_ALARM_SUPPLY4 + offset;
- case AMS_SEQ_SUPPLY5:
- return AMS_ALARM_SUPPLY5 + offset;
- case AMS_SEQ_SUPPLY6:
- return AMS_ALARM_SUPPLY6 + offset;
- case AMS_SEQ_SUPPLY7:
- return AMS_ALARM_SUPPLY7 + offset;
- case AMS_SEQ_SUPPLY8:
- return AMS_ALARM_SUPPLY8 + offset;
- case AMS_SEQ_SUPPLY9:
- return AMS_ALARM_SUPPLY9 + offset;
- case AMS_SEQ_SUPPLY10:
- return AMS_ALARM_SUPPLY10 + offset;
- case AMS_SEQ_VCCAMS:
- return AMS_ALARM_VCCAMS + offset;
- case AMS_SEQ_TEMP_REMOTE:
- return AMS_ALARM_TEMP_REMOTE + offset;
- default:
+ event = ams_scan_index_to_event(scan_index);
+ if (event < 0 || alarm_map[event].base_offset == AMS_ALARM_NONE)
return 0;
- }
+
+ return alarm_map[event].base_offset + offset;
}
static const struct iio_chan_spec *ams_event_to_channel(struct iio_dev *dev,
@@ -823,96 +836,38 @@ static const struct iio_chan_spec *ams_event_to_channel(struct iio_dev *dev,
scan_index = AMS_PS_SEQ_MAX;
}
- switch (event) {
- case AMS_ALARM_BIT_TEMP:
- scan_index += AMS_SEQ_TEMP;
- break;
- case AMS_ALARM_BIT_SUPPLY1:
- scan_index += AMS_SEQ_SUPPLY1;
- break;
- case AMS_ALARM_BIT_SUPPLY2:
- scan_index += AMS_SEQ_SUPPLY2;
- break;
- case AMS_ALARM_BIT_SUPPLY3:
- scan_index += AMS_SEQ_SUPPLY3;
- break;
- case AMS_ALARM_BIT_SUPPLY4:
- scan_index += AMS_SEQ_SUPPLY4;
- break;
- case AMS_ALARM_BIT_SUPPLY5:
- scan_index += AMS_SEQ_SUPPLY5;
- break;
- case AMS_ALARM_BIT_SUPPLY6:
- scan_index += AMS_SEQ_SUPPLY6;
- break;
- case AMS_ALARM_BIT_SUPPLY7:
- scan_index += AMS_SEQ_SUPPLY7;
- break;
- case AMS_ALARM_BIT_SUPPLY8:
- scan_index += AMS_SEQ_SUPPLY8;
- break;
- case AMS_ALARM_BIT_SUPPLY9:
- scan_index += AMS_SEQ_SUPPLY9;
- break;
- case AMS_ALARM_BIT_SUPPLY10:
- scan_index += AMS_SEQ_SUPPLY10;
- break;
- case AMS_ALARM_BIT_VCCAMS:
- scan_index += AMS_SEQ_VCCAMS;
- break;
- case AMS_ALARM_BIT_TEMP_REMOTE:
- scan_index += AMS_SEQ_TEMP_REMOTE;
- break;
- default:
- break;
- }
+ if (event >= ARRAY_SIZE(alarm_map))
+ return NULL;
+
+ if (alarm_map[event].base_offset == AMS_ALARM_NONE)
+ return NULL;
+
+ scan_index += alarm_map[event].scan_index;
for (i = 0; i < dev->num_channels; i++)
if (dev->channels[i].scan_index == scan_index)
break;
+ if (i == dev->num_channels)
+ return NULL;
+
return &dev->channels[i];
}
static int ams_get_alarm_mask(int scan_index)
{
- int bit = 0;
+ int bit = 0, event;
if (scan_index >= AMS_PS_SEQ_MAX) {
bit = AMS_PL_ALARM_START;
scan_index -= AMS_PS_SEQ_MAX;
}
- switch (scan_index) {
- case AMS_SEQ_TEMP:
- return BIT(AMS_ALARM_BIT_TEMP + bit);
- case AMS_SEQ_SUPPLY1:
- return BIT(AMS_ALARM_BIT_SUPPLY1 + bit);
- case AMS_SEQ_SUPPLY2:
- return BIT(AMS_ALARM_BIT_SUPPLY2 + bit);
- case AMS_SEQ_SUPPLY3:
- return BIT(AMS_ALARM_BIT_SUPPLY3 + bit);
- case AMS_SEQ_SUPPLY4:
- return BIT(AMS_ALARM_BIT_SUPPLY4 + bit);
- case AMS_SEQ_SUPPLY5:
- return BIT(AMS_ALARM_BIT_SUPPLY5 + bit);
- case AMS_SEQ_SUPPLY6:
- return BIT(AMS_ALARM_BIT_SUPPLY6 + bit);
- case AMS_SEQ_SUPPLY7:
- return BIT(AMS_ALARM_BIT_SUPPLY7 + bit);
- case AMS_SEQ_SUPPLY8:
- return BIT(AMS_ALARM_BIT_SUPPLY8 + bit);
- case AMS_SEQ_SUPPLY9:
- return BIT(AMS_ALARM_BIT_SUPPLY9 + bit);
- case AMS_SEQ_SUPPLY10:
- return BIT(AMS_ALARM_BIT_SUPPLY10 + bit);
- case AMS_SEQ_VCCAMS:
- return BIT(AMS_ALARM_BIT_VCCAMS + bit);
- case AMS_SEQ_TEMP_REMOTE:
- return BIT(AMS_ALARM_BIT_TEMP_REMOTE + bit);
- default:
+ event = ams_scan_index_to_event(scan_index);
+ if (event < 0)
return 0;
- }
+
+ return BIT(event + bit);
}
static int ams_read_event_config(struct iio_dev *indio_dev,
@@ -936,7 +891,7 @@ static int ams_write_event_config(struct iio_dev *indio_dev,
alarm = ams_get_alarm_mask(chan->scan_index);
- mutex_lock(&ams->lock);
+ guard(mutex)(&ams->lock);
if (state)
ams->alarm_mask |= alarm;
@@ -945,8 +900,6 @@ static int ams_write_event_config(struct iio_dev *indio_dev,
ams_update_alarm(ams, ams->alarm_mask);
- mutex_unlock(&ams->lock);
-
return 0;
}
@@ -959,15 +912,13 @@ static int ams_read_event_value(struct iio_dev *indio_dev,
struct ams *ams = iio_priv(indio_dev);
unsigned int offset = ams_get_alarm_offset(chan->scan_index, dir);
- mutex_lock(&ams->lock);
+ guard(mutex)(&ams->lock);
if (chan->scan_index >= AMS_PS_SEQ_MAX)
*val = readl(ams->pl_base + offset);
else
*val = readl(ams->ps_base + offset);
- mutex_unlock(&ams->lock);
-
return IIO_VAL_INT;
}
@@ -980,7 +931,7 @@ static int ams_write_event_value(struct iio_dev *indio_dev,
struct ams *ams = iio_priv(indio_dev);
unsigned int offset;
- mutex_lock(&ams->lock);
+ guard(mutex)(&ams->lock);
/* Set temperature channel threshold to direct threshold */
if (chan->type == IIO_TEMP) {
@@ -1002,8 +953,6 @@ static int ams_write_event_value(struct iio_dev *indio_dev,
else
writel(val, ams->ps_base + offset);
- mutex_unlock(&ams->lock);
-
return 0;
}
@@ -1012,6 +961,8 @@ static void ams_handle_event(struct iio_dev *indio_dev, u32 event)
const struct iio_chan_spec *chan;
chan = ams_event_to_channel(indio_dev, event);
+ if (!chan)
+ return;
if (chan->type == IIO_TEMP) {
/*
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c
index e257c1b94a5f..cab66bb8cc1c 100644
--- a/drivers/iio/adc/xilinx-xadc-core.c
+++ b/drivers/iio/adc/xilinx-xadc-core.c
@@ -17,7 +17,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/platform_device.h>
@@ -817,6 +816,7 @@ static int xadc_postdisable(struct iio_dev *indio_dev)
{
struct xadc *xadc = iio_priv(indio_dev);
unsigned long scan_mask;
+ int seq_mode;
int ret;
int i;
@@ -824,6 +824,12 @@ static int xadc_postdisable(struct iio_dev *indio_dev)
for (i = 0; i < indio_dev->num_channels; i++)
scan_mask |= BIT(indio_dev->channels[i].scan_index);
+ /*
+ * Use the correct sequencer mode for the idle state: simultaneous
+ * mode for dual external mux configurations, continuous otherwise.
+ */
+ seq_mode = xadc_get_seq_mode(xadc, scan_mask);
+
/* Enable all channels and calibration */
ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(0), scan_mask & 0xffff);
if (ret)
@@ -834,11 +840,11 @@ static int xadc_postdisable(struct iio_dev *indio_dev)
return ret;
ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK,
- XADC_CONF1_SEQ_CONTINUOUS);
+ seq_mode);
if (ret)
return ret;
- return xadc_power_adc_b(xadc, XADC_CONF1_SEQ_CONTINUOUS);
+ return xadc_power_adc_b(xadc, seq_mode);
}
static int xadc_preenable(struct iio_dev *indio_dev)
diff --git a/drivers/iio/addac/ad74115.c b/drivers/iio/addac/ad74115.c
index f8b04d86b01f..9b9d7a12ce87 100644
--- a/drivers/iio/addac/ad74115.c
+++ b/drivers/iio/addac/ad74115.c
@@ -1835,7 +1835,10 @@ static int ad74115_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
st->spi = spi;
- mutex_init(&st->lock);
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
init_completion(&st->adc_data_completion);
indio_dev->name = AD74115_NAME;
@@ -1901,7 +1904,7 @@ static int __init ad74115_register_driver(struct spi_driver *spi)
}
static const struct spi_device_id ad74115_spi_id[] = {
- { "ad74115h" },
+ { .name = "ad74115h" },
{ }
};
diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c
index a20b4d48c5f7..2e5a58e48a89 100644
--- a/drivers/iio/addac/ad74413r.c
+++ b/drivers/iio/addac/ad74413r.c
@@ -18,7 +18,6 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/interrupt.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -839,12 +838,9 @@ static int _ad74413r_get_single_adc_result(struct ad74413r_state *st,
if (ret)
return ret;
- ret = wait_for_completion_timeout(&st->adc_data_completion,
- msecs_to_jiffies(1000));
- if (!ret) {
- ret = -ETIMEDOUT;
- return ret;
- }
+ if (!wait_for_completion_timeout(&st->adc_data_completion,
+ msecs_to_jiffies(1000)))
+ return -ETIMEDOUT;
ret = regmap_read(st->regmap, AD74413R_REG_ADC_RESULT_X(channel),
&uval);
@@ -1461,7 +1457,7 @@ static int ad74413r_probe(struct spi_device *spi)
ret = devm_request_irq(st->dev, spi->irq, ad74413r_adc_data_interrupt,
0, st->chip_info->name, indio_dev);
if (ret)
- return dev_err_probe(st->dev, ret, "Failed to request irq\n");
+ return ret;
ret = devm_iio_triggered_buffer_setup(st->dev, indio_dev,
&iio_pollfunc_store_time,
diff --git a/drivers/iio/addac/stx104.c b/drivers/iio/addac/stx104.c
index 7bdf2cb94176..6207eb2fac74 100644
--- a/drivers/iio/addac/stx104.c
+++ b/drivers/iio/addac/stx104.c
@@ -349,9 +349,9 @@ static const struct iio_chan_spec stx104_channels_diff[] = {
STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1)
};
-static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,
- unsigned int offset, unsigned int *const reg,
- unsigned int *const mask)
+static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, enum gpio_regmap_operation op,
+ const unsigned int base, unsigned int offset,
+ unsigned int *const reg, unsigned int *const mask)
{
/* Output lines are located at same register bit offsets as input lines */
if (offset >= 4)
diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
index ecaf59278c6f..3a6a09ffa526 100644
--- a/drivers/iio/afe/iio-rescale.c
+++ b/drivers/iio/afe/iio-rescale.c
@@ -10,7 +10,6 @@
#include <linux/err.h>
#include <linux/gcd.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -609,3 +608,4 @@ module_platform_driver(rescale_driver);
MODULE_DESCRIPTION("IIO rescale driver");
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/amplifiers/Kconfig b/drivers/iio/amplifiers/Kconfig
index a8a604863eed..9e24421b5e97 100644
--- a/drivers/iio/amplifiers/Kconfig
+++ b/drivers/iio/amplifiers/Kconfig
@@ -18,7 +18,15 @@ config AD8366
AD8366 Dual-Digital Variable Gain Amplifier (VGA)
ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
ADL5240 Digitally controlled variable gain amplifier (VGA)
+ ADRF5702: 0.125 dB LSB, 8-Bit, Silicon Digital Attenuator
+ ADRF5703: 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
+ ADRF5720: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator
+ ADRF5730: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator
+ ADRF5731: 2 dB LSB, 4-Bit, Silicon Digital Attenuator
+ HMC271A: 1dB LSB 5-Bit Digital Attenuator SMT
HMC792A 0.25 dB LSB GaAs MMIC 6-Bit Digital Attenuator
+ HMC1018A: 1.0 dB LSB GaAs MMIC 5-BIT Digital Attenuator
+ HMC1019A: 0.5 dB LSB GaAs MMIC 5-BIT Digital Attenuator
HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
To compile this driver as a module, choose M here: the
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
index d06ac786501c..e12f8604f59f 100644
--- a/drivers/iio/amplifiers/ad8366.c
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -5,46 +5,51 @@
* AD8366 Dual-Digital Variable Gain Amplifier (VGA)
* ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
* ADL5240 Digitally controlled variable gain amplifier (VGA)
+ * ADRF5702: 0.125 dB LSB, 8-Bit, Silicon Digital Attenuator, 50 MHz to 20 GHz
+ * ADRF5703: 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator, 9 kHz to 20 GHz
+ * ADRF5720: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator, 9 kHz to 40 GHz
+ * ADRF5730: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator, 100 MHz to 40 GHz
+ * ADRF5731: 2 dB LSB, 4-Bit, Silicon Digital Attenuator, 100 MHz to 40 GHz
+ * HMC271A: 1dB LSB 5-Bit Digital Attenuator SMT, 0.7 - 3.7 GHz
* HMC792A 0.25 dB LSB GaAs MMIC 6-Bit Digital Attenuator
+ * HMC1018A: 1.0 dB LSB GaAs MMIC 5-BIT DIGITAL ATTENUATOR, 0.1 - 30 GHz
+ * HMC1019A: 0.5 dB LSB GaAs MMIC 5-BIT DIGITAL ATTENUATOR, 0.1 - 30 GHz
* HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
*
- * Copyright 2012-2019 Analog Devices Inc.
+ * Copyright 2012-2026 Analog Devices Inc.
*/
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/spi/spi.h>
-#include <linux/regulator/consumer.h>
-#include <linux/gpio/consumer.h>
+#include <linux/bitrev.h>
+#include <linux/bits.h>
+#include <linux/dev_printk.h>
#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/math.h>
+#include <linux/minmax.h>
#include <linux/module.h>
-#include <linux/bitrev.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-
-enum ad8366_type {
- ID_AD8366,
- ID_ADA4961,
- ID_ADL5240,
- ID_HMC792,
- ID_HMC1119,
-};
struct ad8366_info {
+ const char *name;
int gain_min;
int gain_max;
+ int gain_step;
+ size_t num_channels;
+ size_t (*pack_code)(const unsigned char *code, size_t num_channels,
+ unsigned char *data);
};
struct ad8366_state {
struct spi_device *spi;
- struct regulator *reg;
struct mutex lock; /* protect sensor state */
- struct gpio_desc *reset_gpio;
unsigned char ch[2];
- enum ad8366_type type;
const struct ad8366_info *info;
/*
* DMA (thus cache coherency maintenance) may require the
@@ -53,60 +58,148 @@ struct ad8366_state {
unsigned char data[2] __aligned(IIO_DMA_MINALIGN);
};
-static const struct ad8366_info ad8366_infos[] = {
- [ID_AD8366] = {
- .gain_min = 4500,
- .gain_max = 20500,
- },
- [ID_ADA4961] = {
- .gain_min = -6000,
- .gain_max = 15000,
- },
- [ID_ADL5240] = {
- .gain_min = -11500,
- .gain_max = 20000,
- },
- [ID_HMC792] = {
- .gain_min = -15750,
- .gain_max = 0,
- },
- [ID_HMC1119] = {
- .gain_min = -31750,
- .gain_max = 0,
- },
-};
+static size_t ad8366_pack_code(const unsigned char *code, size_t num_channels,
+ unsigned char *data)
+{
+ u8 ch_a = bitrev8(code[0]) >> 2;
+ u8 ch_b = bitrev8(code[1]) >> 2;
+
+ put_unaligned_be16((ch_b << 6) | ch_a, &data[0]);
+ return sizeof(__be16);
+}
-static int ad8366_write(struct iio_dev *indio_dev,
- unsigned char ch_a, unsigned char ch_b)
+static size_t adrf5731_pack_code(const unsigned char *code, size_t num_channels,
+ unsigned char *data)
{
- struct ad8366_state *st = iio_priv(indio_dev);
- int ret;
+ data[0] = code[0] << 2;
+ return 1;
+}
- switch (st->type) {
- case ID_AD8366:
- ch_a = bitrev8(ch_a & 0x3F);
- ch_b = bitrev8(ch_b & 0x3F);
+static size_t hmc271_pack_code(const unsigned char *code, size_t num_channels,
+ unsigned char *data)
+{
+ data[0] = bitrev8(code[0]) >> 3;
+ return 1;
+}
- st->data[0] = ch_b >> 4;
- st->data[1] = (ch_b << 4) | (ch_a >> 2);
- break;
- case ID_ADA4961:
- st->data[0] = ch_a & 0x1F;
- break;
- case ID_ADL5240:
- st->data[0] = (ch_a & 0x3F);
- break;
- case ID_HMC792:
- case ID_HMC1119:
- st->data[0] = ch_a;
- break;
- }
+static const struct ad8366_info ad8366_chip_info = {
+ .name = "ad8366",
+ .gain_min = 4500,
+ .gain_max = 20500,
+ .gain_step = 253,
+ .num_channels = 2,
+ .pack_code = ad8366_pack_code,
+};
- ret = spi_write(st->spi, st->data, indio_dev->num_channels);
- if (ret < 0)
- dev_err(&indio_dev->dev, "write failed (%d)", ret);
+static const struct ad8366_info ada4961_chip_info = {
+ .name = "ada4961",
+ .gain_min = -6000,
+ .gain_max = 15000,
+ .gain_step = -1000,
+ .num_channels = 1,
+};
- return ret;
+static const struct ad8366_info adl5240_chip_info = {
+ .name = "adl5240",
+ .gain_min = -11500,
+ .gain_max = 20000,
+ .gain_step = 500,
+ .num_channels = 1,
+};
+
+static const struct ad8366_info adrf5702_chip_info = {
+ .name = "adrf5702",
+ .gain_min = -31875,
+ .gain_max = 0,
+ .gain_step = -125,
+ .num_channels = 1,
+};
+
+static const struct ad8366_info adrf5703_chip_info = {
+ .name = "adrf5703",
+ .gain_min = -31750,
+ .gain_max = 0,
+ .gain_step = -250,
+ .num_channels = 1,
+};
+
+static const struct ad8366_info adrf5720_chip_info = {
+ .name = "adrf5720",
+ .gain_min = -31500,
+ .gain_max = 0,
+ .gain_step = -500,
+ .num_channels = 1,
+};
+
+static const struct ad8366_info adrf5730_chip_info = {
+ .name = "adrf5730",
+ .gain_min = -31500,
+ .gain_max = 0,
+ .gain_step = -500,
+ .num_channels = 1,
+};
+
+static const struct ad8366_info adrf5731_chip_info = {
+ .name = "adrf5731",
+ .gain_min = -30000,
+ .gain_max = 0,
+ .gain_step = -2000,
+ .num_channels = 1,
+ .pack_code = adrf5731_pack_code,
+};
+
+static const struct ad8366_info hmc271_chip_info = {
+ .name = "hmc271a",
+ .gain_min = -31000,
+ .gain_max = 0,
+ .gain_step = 1000,
+ .num_channels = 1,
+ .pack_code = hmc271_pack_code,
+};
+
+static const struct ad8366_info hmc792_chip_info = {
+ .name = "hmc792a",
+ .gain_min = -15750,
+ .gain_max = 0,
+ .gain_step = 250,
+ .num_channels = 1,
+};
+
+static const struct ad8366_info hmc1018_chip_info = {
+ .name = "hmc1018a",
+ .gain_min = -31000,
+ .gain_max = 0,
+ .gain_step = 1000,
+ .num_channels = 1,
+};
+
+static const struct ad8366_info hmc1019_chip_info = {
+ .name = "hmc1019a",
+ .gain_min = -15500,
+ .gain_max = 0,
+ .gain_step = 500,
+ .num_channels = 1,
+};
+
+static const struct ad8366_info hmc1119_chip_info = {
+ .name = "hmc1119",
+ .gain_min = -31750,
+ .gain_max = 0,
+ .gain_step = -250,
+ .num_channels = 1,
+};
+
+static int ad8366_write_code(struct ad8366_state *st)
+{
+ const struct ad8366_info *inf = st->info;
+ size_t len = 1;
+
+ if (inf->pack_code)
+ len = inf->pack_code(st->ch, inf->num_channels, st->data);
+ else
+ st->data[0] = st->ch[0];
+
+ return spi_write(st->spi, st->data, len);
}
static int ad8366_read_raw(struct iio_dev *indio_dev,
@@ -116,6 +209,7 @@ static int ad8366_read_raw(struct iio_dev *indio_dev,
long m)
{
struct ad8366_state *st = iio_priv(indio_dev);
+ const struct ad8366_info *inf = st->info;
int ret;
int code, gain = 0;
@@ -123,25 +217,8 @@ static int ad8366_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_HARDWAREGAIN:
code = st->ch[chan->channel];
-
- switch (st->type) {
- case ID_AD8366:
- gain = code * 253 + 4500;
- break;
- case ID_ADA4961:
- gain = 15000 - code * 1000;
- break;
- case ID_ADL5240:
- gain = 20000 - 31500 + code * 500;
- break;
- case ID_HMC792:
- gain = -1 * code * 500;
- break;
- case ID_HMC1119:
- gain = -1 * code * 250;
- break;
- }
-
+ gain = inf->gain_step > 0 ? inf->gain_min : inf->gain_max;
+ gain += inf->gain_step * code;
/* Values in dB */
*val = gain / 1000;
*val2 = (gain % 1000) * 1000;
@@ -176,29 +253,14 @@ static int ad8366_write_raw(struct iio_dev *indio_dev,
if (gain > inf->gain_max || gain < inf->gain_min)
return -EINVAL;
- switch (st->type) {
- case ID_AD8366:
- code = (gain - 4500) / 253;
- break;
- case ID_ADA4961:
- code = (15000 - gain) / 1000;
- break;
- case ID_ADL5240:
- code = ((gain - 500 - 20000) / 500) & 0x3F;
- break;
- case ID_HMC792:
- code = (abs(gain) / 500) & 0x3F;
- break;
- case ID_HMC1119:
- code = (abs(gain) / 250) & 0x7F;
- break;
- }
+ gain -= inf->gain_step > 0 ? inf->gain_min : inf->gain_max;
+ code = DIV_ROUND_CLOSEST(gain, inf->gain_step);
mutex_lock(&st->lock);
switch (mask) {
case IIO_CHAN_INFO_HARDWAREGAIN:
st->ch[chan->channel] = code;
- ret = ad8366_write(indio_dev, st->ch[0], st->ch[1]);
+ ret = ad8366_write_code(st);
break;
default:
ret = -EINVAL;
@@ -239,107 +301,97 @@ static const struct iio_chan_spec ad8366_channels[] = {
AD8366_CHAN(1),
};
-static const struct iio_chan_spec ada4961_channels[] = {
- AD8366_CHAN(0),
-};
-
static int ad8366_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
+ struct gpio_desc *enable_gpio;
+ struct reset_control *rstc;
struct iio_dev *indio_dev;
struct ad8366_state *st;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = devm_regulator_get(&spi->dev, "vcc");
- if (!IS_ERR(st->reg)) {
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
- }
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ ret = devm_regulator_get_enable(dev, "vcc");
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulator\n");
- spi_set_drvdata(spi, indio_dev);
- mutex_init(&st->lock);
st->spi = spi;
- st->type = spi_get_device_id(spi)->driver_data;
+ st->info = spi_get_device_match_data(spi);
- switch (st->type) {
- case ID_AD8366:
- indio_dev->channels = ad8366_channels;
- indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
- break;
- case ID_ADA4961:
- case ID_ADL5240:
- case ID_HMC792:
- case ID_HMC1119:
- st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_HIGH);
- if (IS_ERR(st->reset_gpio)) {
- ret = PTR_ERR(st->reset_gpio);
- goto error_disable_reg;
- }
- indio_dev->channels = ada4961_channels;
- indio_dev->num_channels = ARRAY_SIZE(ada4961_channels);
- break;
- default:
- dev_err(&spi->dev, "Invalid device ID\n");
- ret = -EINVAL;
- goto error_disable_reg;
- }
+ enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(enable_gpio))
+ return dev_err_probe(dev, PTR_ERR(enable_gpio),
+ "Failed to get enable GPIO\n");
+
+ rstc = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL);
+ if (IS_ERR(rstc))
+ return dev_err_probe(dev, PTR_ERR(rstc),
+ "Failed to get reset controller\n");
- st->info = &ad8366_infos[st->type];
- indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->name = st->info->name;
indio_dev->info = &ad8366_info;
indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ad8366_channels;
+ indio_dev->num_channels = st->info->num_channels;
- ret = ad8366_write(indio_dev, 0, 0);
+ ret = ad8366_write_code(st);
if (ret < 0)
- goto error_disable_reg;
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_disable_reg;
-
- return 0;
+ return dev_err_probe(dev, ret, "failed to write initial gain\n");
-error_disable_reg:
- if (!IS_ERR(st->reg))
- regulator_disable(st->reg);
-
- return ret;
-}
-
-static void ad8366_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad8366_state *st = iio_priv(indio_dev);
- struct regulator *reg = st->reg;
-
- iio_device_unregister(indio_dev);
-
- if (!IS_ERR(reg))
- regulator_disable(reg);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id ad8366_id[] = {
- {"ad8366", ID_AD8366},
- {"ada4961", ID_ADA4961},
- {"adl5240", ID_ADL5240},
- {"hmc792a", ID_HMC792},
- {"hmc1119", ID_HMC1119},
+ { .name = "ad8366", .driver_data = (kernel_ulong_t)&ad8366_chip_info },
+ { .name = "ada4961", .driver_data = (kernel_ulong_t)&ada4961_chip_info },
+ { .name = "adl5240", .driver_data = (kernel_ulong_t)&adl5240_chip_info },
+ { .name = "adrf5702", .driver_data = (kernel_ulong_t)&adrf5702_chip_info },
+ { .name = "adrf5703", .driver_data = (kernel_ulong_t)&adrf5703_chip_info },
+ { .name = "adrf5720", .driver_data = (kernel_ulong_t)&adrf5720_chip_info },
+ { .name = "adrf5730", .driver_data = (kernel_ulong_t)&adrf5730_chip_info },
+ { .name = "adrf5731", .driver_data = (kernel_ulong_t)&adrf5731_chip_info },
+ { .name = "hmc271a", .driver_data = (kernel_ulong_t)&hmc271_chip_info },
+ { .name = "hmc792a", .driver_data = (kernel_ulong_t)&hmc792_chip_info },
+ { .name = "hmc1018a", .driver_data = (kernel_ulong_t)&hmc1018_chip_info },
+ { .name = "hmc1019a", .driver_data = (kernel_ulong_t)&hmc1019_chip_info },
+ { .name = "hmc1119", .driver_data = (kernel_ulong_t)&hmc1119_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad8366_id);
+static const struct of_device_id ad8366_of_match[] = {
+ { .compatible = "adi,ad8366", .data = &ad8366_chip_info },
+ { .compatible = "adi,ada4961", .data = &ada4961_chip_info },
+ { .compatible = "adi,adl5240", .data = &adl5240_chip_info },
+ { .compatible = "adi,adrf5702", .data = &adrf5702_chip_info },
+ { .compatible = "adi,adrf5703", .data = &adrf5703_chip_info },
+ { .compatible = "adi,adrf5720", .data = &adrf5720_chip_info },
+ { .compatible = "adi,adrf5730", .data = &adrf5730_chip_info },
+ { .compatible = "adi,adrf5731", .data = &adrf5731_chip_info },
+ { .compatible = "adi,hmc271a", .data = &hmc271_chip_info },
+ { .compatible = "adi,hmc792a", .data = &hmc792_chip_info },
+ { .compatible = "adi,hmc1018a", .data = &hmc1018_chip_info },
+ { .compatible = "adi,hmc1019a", .data = &hmc1019_chip_info },
+ { .compatible = "adi,hmc1119", .data = &hmc1119_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad8366_of_match);
+
static struct spi_driver ad8366_driver = {
.driver = {
- .name = KBUILD_MODNAME,
+ .name = KBUILD_MODNAME,
+ .of_match_table = ad8366_of_match,
},
.probe = ad8366_probe,
- .remove = ad8366_remove,
.id_table = ad8366_id,
};
diff --git a/drivers/iio/amplifiers/ada4250.c b/drivers/iio/amplifiers/ada4250.c
index 40f396ea9069..9702de3a5074 100644
--- a/drivers/iio/amplifiers/ada4250.c
+++ b/drivers/iio/amplifiers/ada4250.c
@@ -109,7 +109,7 @@ static int ada4250_set_offset_uv(struct iio_dev *indio_dev,
/*
* Compute Range and Voltage per LSB for the Sensor Offset Calibration
- * Example of computation for Range 1 and Range 2 (Curren Bias Set = AVDD):
+ * Example of computation for Range 1 and Range 2 (Current Bias Set = AVDD):
* Range 1 Range 2
* Gain | Max Vos(mV) | LSB(mV) | Max Vos(mV) | LSB(mV) |
* 2 | X1*127 | X1=0.126(AVDD-1) | X1*3*127 | X1*3 |
@@ -358,7 +358,7 @@ static int ada4250_probe(struct spi_device *spi)
}
static const struct spi_device_id ada4250_id[] = {
- { "ada4250", 0 },
+ { .name = "ada4250" },
{ }
};
MODULE_DEVICE_TABLE(spi, ada4250_id);
diff --git a/drivers/iio/amplifiers/adl8113.c b/drivers/iio/amplifiers/adl8113.c
index b8a431b6616b..1f1cfca980b4 100644
--- a/drivers/iio/amplifiers/adl8113.c
+++ b/drivers/iio/amplifiers/adl8113.c
@@ -12,7 +12,6 @@
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/iio.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c
index 4dbf894c7e3b..85bfc8dcc5fb 100644
--- a/drivers/iio/amplifiers/hmc425a.c
+++ b/drivers/iio/amplifiers/hmc425a.c
@@ -14,7 +14,6 @@
#include <linux/iio/sysfs.h>
#include <linux/kernel.h>
#include <linux/math.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
diff --git a/drivers/iio/buffer/industrialio-buffer-cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c
index 0c266c216525..b58263bcf3cb 100644
--- a/drivers/iio/buffer/industrialio-buffer-cb.c
+++ b/drivers/iio/buffer/industrialio-buffer-cb.c
@@ -154,3 +154,4 @@ EXPORT_SYMBOL_GPL(iio_channel_cb_get_iio_dev);
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("Industrial I/O callback buffer");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
index 98acce909854..1bd82d3db5ea 100644
--- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c
+++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
@@ -56,6 +56,23 @@ static void iio_dmaengine_buffer_block_done(void *data,
iio_dma_buffer_block_done(block);
}
+/*
+ * Cyclic transfers run until abort. Cap active cyclic blocks to one until there
+ * is a use case for more.
+ */
+static bool iio_dmaengine_buffer_has_active_cyclic(struct dmaengine_buffer *dmaengine_buffer)
+{
+ struct iio_dma_buffer_block *block;
+
+ guard(spinlock_irqsave)(&dmaengine_buffer->queue.list_lock);
+ list_for_each_entry(block, &dmaengine_buffer->active, head) {
+ if (block->cyclic)
+ return true;
+ }
+
+ return false;
+}
+
static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue,
struct iio_dma_buffer_block *block)
{
@@ -79,13 +96,20 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue,
else
dma_dir = DMA_MEM_TO_DEV;
+ if (block->cyclic && iio_dmaengine_buffer_has_active_cyclic(dmaengine_buffer)) {
+ dev_err(queue->dev, "cyclic DMA transfer already active\n");
+ return -EBUSY;
+ }
+
if (block->sg_table) {
+ unsigned long flags;
+
sgl = block->sg_table->sgl;
nents = sg_nents_for_len(sgl, block->bytes_used);
if (nents < 0)
return nents;
- vecs = kmalloc_array(nents, sizeof(*vecs), GFP_ATOMIC);
+ vecs = kmalloc_objs(*vecs, nents, GFP_ATOMIC);
if (!vecs)
return -ENOMEM;
@@ -99,9 +123,19 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue,
sgl = sg_next(sgl);
}
+ if (block->cyclic)
+ flags = DMA_PREP_REPEAT;
+ else
+ flags = DMA_PREP_INTERRUPT;
+
+ /*
+ * A new transfer may need to end an already active cyclic transfer
+ * before it can run, so always set the EOT flag.
+ */
+ flags |= DMA_PREP_LOAD_EOT;
desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan,
vecs, nents, dma_dir,
- DMA_PREP_INTERRUPT);
+ flags);
kfree(vecs);
} else {
max_size = min(block->size, dmaengine_buffer->max_size);
@@ -122,8 +156,10 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue,
if (!desc)
return -ENOMEM;
- desc->callback_result = iio_dmaengine_buffer_block_done;
- desc->callback_param = block;
+ if (!block->cyclic) {
+ desc->callback_result = iio_dmaengine_buffer_block_done;
+ desc->callback_param = block;
+ }
cookie = dmaengine_submit(desc);
if (dma_submit_error(cookie))
diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c
index cb771ef8eeb3..d035aa33b357 100644
--- a/drivers/iio/buffer/industrialio-hw-consumer.c
+++ b/drivers/iio/buffer/industrialio-hw-consumer.c
@@ -28,7 +28,6 @@ struct hw_consumer_buffer {
struct list_head head;
struct iio_dev *indio_dev;
struct iio_buffer buffer;
- long scan_mask[];
};
static struct hw_consumer_buffer *iio_buffer_to_hw_consumer_buffer(
@@ -41,6 +40,8 @@ static void iio_hw_buf_release(struct iio_buffer *buffer)
{
struct hw_consumer_buffer *hw_buf =
iio_buffer_to_hw_consumer_buffer(buffer);
+
+ bitmap_free(buffer->scan_mask);
kfree(hw_buf);
}
@@ -52,7 +53,6 @@ static const struct iio_buffer_access_funcs iio_hw_buf_access = {
static struct hw_consumer_buffer *iio_hw_consumer_get_buffer(
struct iio_hw_consumer *hwc, struct iio_dev *indio_dev)
{
- unsigned int mask_longs = BITS_TO_LONGS(iio_get_masklength(indio_dev));
struct hw_consumer_buffer *buf;
list_for_each_entry(buf, &hwc->buffers, head) {
@@ -60,13 +60,18 @@ static struct hw_consumer_buffer *iio_hw_consumer_get_buffer(
return buf;
}
- buf = kzalloc_flex(*buf, scan_mask, mask_longs);
+ buf = kzalloc_obj(*buf);
if (!buf)
return NULL;
buf->buffer.access = &iio_hw_buf_access;
buf->indio_dev = indio_dev;
- buf->buffer.scan_mask = buf->scan_mask;
+ buf->buffer.scan_mask = bitmap_zalloc(iio_get_masklength(indio_dev),
+ GFP_KERNEL);
+ if (!buf->buffer.scan_mask) {
+ kfree(buf);
+ return NULL;
+ }
iio_buffer_init(&buf->buffer);
list_add_tail(&buf->head, &hwc->buffers);
@@ -82,7 +87,7 @@ static struct hw_consumer_buffer *iio_hw_consumer_get_buffer(
*/
struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev)
{
- struct hw_consumer_buffer *buf;
+ struct hw_consumer_buffer *buf, *tmp;
struct iio_hw_consumer *hwc;
struct iio_channel *chan;
int ret;
@@ -113,7 +118,7 @@ struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev)
return hwc;
err_put_buffers:
- list_for_each_entry(buf, &hwc->buffers, head)
+ list_for_each_entry_safe(buf, tmp, &hwc->buffers, head)
iio_buffer_put(&buf->buffer);
iio_channel_release_all(hwc->channels);
err_free_hwc:
@@ -211,3 +216,4 @@ EXPORT_SYMBOL_GPL(iio_hw_consumer_disable);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Hardware consumer buffer the IIO framework");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c
index a6ff9085b8a2..b67ea6468226 100644
--- a/drivers/iio/buffer/kfifo_buf.c
+++ b/drivers/iio/buffer/kfifo_buf.c
@@ -224,35 +224,9 @@ void iio_kfifo_free(struct iio_buffer *r)
}
EXPORT_SYMBOL(iio_kfifo_free);
-static void devm_iio_kfifo_release(struct device *dev, void *res)
+static void devm_iio_kfifo_release(void *buffer)
{
- iio_kfifo_free(*(struct iio_buffer **)res);
-}
-
-/**
- * devm_iio_kfifo_allocate - Resource-managed iio_kfifo_allocate()
- * @dev: Device to allocate kfifo buffer for
- *
- * RETURNS:
- * Pointer to allocated iio_buffer on success, NULL on failure.
- */
-static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
-{
- struct iio_buffer **ptr, *r;
-
- ptr = devres_alloc(devm_iio_kfifo_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return NULL;
-
- r = iio_kfifo_allocate();
- if (r) {
- *ptr = r;
- devres_add(dev, ptr);
- } else {
- devres_free(ptr);
- }
-
- return r;
+ iio_kfifo_free(buffer);
}
/**
@@ -262,10 +236,12 @@ static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
* @setup_ops: The setup_ops required to configure the HW part of the buffer (optional)
* @buffer_attrs: Extra sysfs buffer attributes for this IIO buffer
*
- * This function allocates a kfifo buffer via devm_iio_kfifo_allocate() and
+ * This function allocates a kfifo buffer via iio_kfifo_allocate() and
* attaches it to the IIO device via iio_device_attach_buffer().
* This is meant to be a bit of a short-hand/helper function as there are a few
* drivers that seem to do this.
+ *
+ * Return: 0 on success, negative error code on failure.
*/
int devm_iio_kfifo_buffer_setup_ext(struct device *dev,
struct iio_dev *indio_dev,
@@ -273,11 +249,16 @@ int devm_iio_kfifo_buffer_setup_ext(struct device *dev,
const struct iio_dev_attr **buffer_attrs)
{
struct iio_buffer *buffer;
+ int ret;
- buffer = devm_iio_kfifo_allocate(dev);
+ buffer = iio_kfifo_allocate();
if (!buffer)
return -ENOMEM;
+ ret = devm_add_action_or_reset(dev, devm_iio_kfifo_release, buffer);
+ if (ret)
+ return ret;
+
indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
indio_dev->setup_ops = setup_ops;
diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c
index 427d32e398b3..2f35c6d2f9ce 100644
--- a/drivers/iio/cdc/ad7150.c
+++ b/drivers/iio/cdc/ad7150.c
@@ -13,7 +13,6 @@
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -306,7 +305,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,
dir);
if (ret)
goto error_ret;
- /* reenable any irq's we disabled whilst changing mode */
+ /* re-enable any IRQs we disabled whilst changing mode */
enable_irq(chip->interrupts[0]);
enable_irq(chip->interrupts[1]);
}
@@ -628,9 +627,9 @@ static int ad7150_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad7150_id[] = {
- { "ad7150", AD7150 },
- { "ad7151", AD7151 },
- { "ad7156", AD7150 },
+ { .name = "ad7150", .driver_data = AD7150 },
+ { .name = "ad7151", .driver_data = AD7151 },
+ { .name = "ad7156", .driver_data = AD7150 },
{ }
};
diff --git a/drivers/iio/cdc/ad7746.c b/drivers/iio/cdc/ad7746.c
index 8a306d55c72a..cf68b882bc49 100644
--- a/drivers/iio/cdc/ad7746.c
+++ b/drivers/iio/cdc/ad7746.c
@@ -606,7 +606,7 @@ static int ad7746_read_channel(struct iio_dev *indio_dev,
return ret;
/*
- * Offset applied internally becaue the _offset userspace interface is
+ * Offset applied internally because the _offset userspace interface is
* needed for the CAP DACs which apply a controllable offset.
*/
*val = get_unaligned_be24(data) - 0x800000;
@@ -789,9 +789,9 @@ static int ad7746_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad7746_id[] = {
- { "ad7745", 7745 },
- { "ad7746", 7746 },
- { "ad7747", 7747 },
+ { .name = "ad7745", .driver_data = 7745 },
+ { .name = "ad7746", .driver_data = 7746 },
+ { .name = "ad7747", .driver_data = 7747 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad7746_id);
diff --git a/drivers/iio/chemical/ags02ma.c b/drivers/iio/chemical/ags02ma.c
index 151178d4e8f4..8b97ea4a9515 100644
--- a/drivers/iio/chemical/ags02ma.c
+++ b/drivers/iio/chemical/ags02ma.c
@@ -139,7 +139,7 @@ static int ags02ma_probe(struct i2c_client *client)
}
static const struct i2c_device_id ags02ma_id_table[] = {
- { "ags02ma" },
+ { .name = "ags02ma" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ags02ma_id_table);
diff --git a/drivers/iio/chemical/ams-iaq-core.c b/drivers/iio/chemical/ams-iaq-core.c
index 10156d794092..7af515110b89 100644
--- a/drivers/iio/chemical/ams-iaq-core.c
+++ b/drivers/iio/chemical/ams-iaq-core.c
@@ -7,7 +7,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/i2c.h>
@@ -163,7 +162,7 @@ static int ams_iaqcore_probe(struct i2c_client *client)
}
static const struct i2c_device_id ams_iaqcore_id[] = {
- { "ams-iaq-core" },
+ { .name = "ams-iaq-core" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ams_iaqcore_id);
diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c
index 59f3a4fa9e9f..298b2fe48a19 100644
--- a/drivers/iio/chemical/atlas-ezo-sensor.c
+++ b/drivers/iio/chemical/atlas-ezo-sensor.c
@@ -8,7 +8,6 @@
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/property.h>
@@ -186,9 +185,9 @@ static const struct iio_info atlas_info = {
};
static const struct i2c_device_id atlas_ezo_id[] = {
- { "atlas-co2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_CO2_EZO] },
- { "atlas-o2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_O2_EZO] },
- { "atlas-hum-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_HUM_EZO] },
+ { .name = "atlas-co2-ezo", .driver_data = (kernel_ulong_t)&atlas_ezo_devices[ATLAS_CO2_EZO] },
+ { .name = "atlas-o2-ezo", .driver_data = (kernel_ulong_t)&atlas_ezo_devices[ATLAS_O2_EZO] },
+ { .name = "atlas-hum-ezo", .driver_data = (kernel_ulong_t)&atlas_ezo_devices[ATLAS_HUM_EZO] },
{ }
};
MODULE_DEVICE_TABLE(i2c, atlas_ezo_id);
diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c
index 8bbba85af699..1d4a9919df1a 100644
--- a/drivers/iio/chemical/atlas-sensor.c
+++ b/drivers/iio/chemical/atlas-sensor.c
@@ -13,9 +13,7 @@
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/irq.h>
-#include <linux/irq_work.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
@@ -88,7 +86,6 @@ struct atlas_data {
struct iio_trigger *trig;
const struct atlas_device *chip;
struct regmap *regmap;
- struct irq_work work;
unsigned int interrupt_enabled;
/* 96-bit data + 32-bit pad + 64-bit timestamp */
__be32 buffer[6] __aligned(8);
@@ -413,7 +410,11 @@ static int atlas_buffer_postenable(struct iio_dev *indio_dev)
if (ret)
return ret;
- return atlas_set_interrupt(data, true);
+ ret = atlas_set_interrupt(data, true);
+ if (ret)
+ pm_runtime_put_autosuspend(&data->client->dev);
+
+ return ret;
}
static int atlas_buffer_predisable(struct iio_dev *indio_dev)
@@ -437,13 +438,6 @@ static const struct iio_buffer_setup_ops atlas_buffer_setup_ops = {
.predisable = atlas_buffer_predisable,
};
-static void atlas_work_handler(struct irq_work *work)
-{
- struct atlas_data *data = container_of(work, struct atlas_data, work);
-
- iio_trigger_poll(data->trig);
-}
-
static irqreturn_t atlas_trigger_handler(int irq, void *private)
{
struct iio_poll_func *pf = private;
@@ -470,7 +464,7 @@ static irqreturn_t atlas_interrupt_handler(int irq, void *private)
struct iio_dev *indio_dev = private;
struct atlas_data *data = iio_priv(indio_dev);
- irq_work_queue(&data->work);
+ iio_trigger_poll_nested(data->trig);
return IRQ_HANDLED;
}
@@ -586,11 +580,11 @@ static const struct iio_info atlas_info = {
};
static const struct i2c_device_id atlas_id[] = {
- { "atlas-ph-sm", (kernel_ulong_t)&atlas_devices[ATLAS_PH_SM] },
- { "atlas-ec-sm", (kernel_ulong_t)&atlas_devices[ATLAS_EC_SM] },
- { "atlas-orp-sm", (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] },
- { "atlas-do-sm", (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] },
- { "atlas-rtd-sm", (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] },
+ { .name = "atlas-ph-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_PH_SM] },
+ { .name = "atlas-ec-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_EC_SM] },
+ { .name = "atlas-orp-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] },
+ { .name = "atlas-do-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] },
+ { .name = "atlas-rtd-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] },
{ }
};
MODULE_DEVICE_TABLE(i2c, atlas_id);
@@ -666,8 +660,6 @@ static int atlas_probe(struct i2c_client *client)
goto unregister_trigger;
}
- init_irq_work(&data->work, atlas_work_handler);
-
if (client->irq > 0) {
/* interrupt pin toggles on new conversion */
ret = devm_request_threaded_irq(&client->dev, client->irq,
diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c
index 24e0b59e2fdf..ac9a737481dc 100644
--- a/drivers/iio/chemical/bme680_core.c
+++ b/drivers/iio/chemical/bme680_core.c
@@ -128,7 +128,7 @@ struct bme680_data {
u16 heater_temp;
struct {
- s32 chan[4];
+ s32 chan[BME680_NUM_CHANNELS];
aligned_s64 ts;
} scan;
@@ -807,7 +807,7 @@ static int bme680_read_gas(struct bme680_data *data, int *comp_gas_res)
adc_gas_res = FIELD_GET(BME680_ADC_GAS_RES, gas_regs_val);
/*
- * occurs if either the gas heating duration was insuffient
+ * This may occur if either the gas heating duration was insufficient
* to reach the target heater temperature or the target
* heater temperature was too high for the heater sink to
* reach.
diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c
index 5560ea708b36..c34d67bcb2a3 100644
--- a/drivers/iio/chemical/bme680_i2c.c
+++ b/drivers/iio/chemical/bme680_i2c.c
@@ -24,10 +24,9 @@ static int bme680_i2c_probe(struct i2c_client *client)
const char *name = NULL;
regmap = devm_regmap_init_i2c(client, &bme680_regmap_config);
- if (IS_ERR(regmap)) {
- dev_err(&client->dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap));
- return PTR_ERR(regmap);
- }
+ if (IS_ERR(regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(regmap),
+ "Failed to register i2c regmap\n");
if (id)
name = id->name;
@@ -36,7 +35,7 @@ static int bme680_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bme680_i2c_id[] = {
- { "bme680" },
+ { .name = "bme680" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bme680_i2c_id);
diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c
index aa97645ba539..2175b9564fa1 100644
--- a/drivers/iio/chemical/bme680_spi.c
+++ b/drivers/iio/chemical/bme680_spi.c
@@ -4,7 +4,6 @@
*
* Copyright (C) 2018 Himanshu Jha <himanshujha199640@gmail.com>
*/
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -122,16 +121,15 @@ static int bme680_spi_probe(struct spi_device *spi)
regmap = devm_regmap_init(&spi->dev, &bme680_regmap_bus,
bus_context, &bme680_regmap_config);
- if (IS_ERR(regmap)) {
- dev_err(&spi->dev, "Failed to register spi regmap %ld\n", PTR_ERR(regmap));
- return PTR_ERR(regmap);
- }
+ if (IS_ERR(regmap))
+ return dev_err_probe(&spi->dev, PTR_ERR(regmap),
+ "Failed to register spi regmap\n");
return bme680_core_probe(&spi->dev, regmap, id->name);
}
static const struct spi_device_id bme680_spi_id[] = {
- {"bme680", 0},
+ { .name = "bme680" },
{ }
};
MODULE_DEVICE_TABLE(spi, bme680_spi_id);
diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c
index 998c9239c4c7..d126ee12ffe5 100644
--- a/drivers/iio/chemical/ccs811.c
+++ b/drivers/iio/chemical/ccs811.c
@@ -484,10 +484,8 @@ static int ccs811_probe(struct i2c_client *client)
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"ccs811_irq", indio_dev);
- if (ret) {
- dev_err(&client->dev, "irq request error %d\n", -ret);
+ if (ret)
goto err_poweroff;
- }
data->drdy_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
@@ -552,8 +550,8 @@ static void ccs811_remove(struct i2c_client *client)
}
static const struct i2c_device_id ccs811_id[] = {
- { "ccs811" },
- { }
+ { .name = "ccs811" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, ccs811_id);
diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c
index bbc96c4c6283..7c1ffda38b99 100644
--- a/drivers/iio/chemical/ens160_core.c
+++ b/drivers/iio/chemical/ens160_core.c
@@ -320,7 +320,7 @@ static int ens160_setup_trigger(struct iio_dev *indio_dev, int irq)
IRQF_NO_THREAD, indio_dev->name,
indio_dev->trig);
if (ret)
- return dev_err_probe(dev, ret, "failed to request irq\n");
+ return ret;
return 0;
}
diff --git a/drivers/iio/chemical/ens160_i2c.c b/drivers/iio/chemical/ens160_i2c.c
index aa0dfe639245..ab0e8dcce011 100644
--- a/drivers/iio/chemical/ens160_i2c.c
+++ b/drivers/iio/chemical/ens160_i2c.c
@@ -34,7 +34,7 @@ static int ens160_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id ens160_i2c_id[] = {
- { "ens160" },
+ { .name = "ens160" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ens160_i2c_id);
diff --git a/drivers/iio/chemical/ens160_spi.c b/drivers/iio/chemical/ens160_spi.c
index a674c0e1bf4b..7c11d19291c9 100644
--- a/drivers/iio/chemical/ens160_spi.c
+++ b/drivers/iio/chemical/ens160_spi.c
@@ -39,7 +39,7 @@ static const struct of_device_id ens160_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, ens160_spi_of_match);
static const struct spi_device_id ens160_spi_id[] = {
- { "ens160" },
+ { .name = "ens160" },
{ }
};
MODULE_DEVICE_TABLE(spi, ens160_spi_id);
diff --git a/drivers/iio/chemical/mhz19b.c b/drivers/iio/chemical/mhz19b.c
index 3c64154918b1..a793620e95b7 100644
--- a/drivers/iio/chemical/mhz19b.c
+++ b/drivers/iio/chemical/mhz19b.c
@@ -17,7 +17,6 @@
#include <linux/jiffies.h>
#include <linux/kstrtox.h>
#include <linux/minmax.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/serdev.h>
@@ -52,6 +51,8 @@ struct mhz19b_state {
struct completion buf_ready;
u8 buf_idx;
+ bool buf_overflow;
+
/*
* Serdev receive buffer.
* When data is received from the MH-Z19B,
@@ -106,6 +107,10 @@ static int mhz19b_serdev_cmd(struct iio_dev *indio_dev, int cmd, u16 arg)
cmd_buf[8] = mhz19b_get_checksum(cmd_buf);
/* Write buf to uart ctrl synchronously */
+ st->buf_idx = 0;
+ st->buf_overflow = false;
+ reinit_completion(&st->buf_ready);
+
ret = serdev_device_write(serdev, cmd_buf, MHZ19B_CMD_SIZE, 0);
if (ret < 0)
return ret;
@@ -121,6 +126,9 @@ static int mhz19b_serdev_cmd(struct iio_dev *indio_dev, int cmd, u16 arg)
if (!ret)
return -ETIMEDOUT;
+ if (st->buf_overflow)
+ return -EMSGSIZE;
+
if (st->buf[8] != mhz19b_get_checksum(st->buf)) {
dev_err(dev, "checksum err");
return -EINVAL;
@@ -240,6 +248,14 @@ static size_t mhz19b_receive_buf(struct serdev_device *serdev,
{
struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
struct mhz19b_state *st = iio_priv(indio_dev);
+ size_t remaining = MHZ19B_CMD_SIZE - st->buf_idx;
+
+ if (len > remaining) {
+ st->buf_idx = 0;
+ st->buf_overflow = true;
+ complete(&st->buf_ready);
+ return len;
+ }
memcpy(st->buf + st->buf_idx, data, len);
st->buf_idx += len;
diff --git a/drivers/iio/chemical/pms7003.c b/drivers/iio/chemical/pms7003.c
index 656d4a12c58f..c50edb24af89 100644
--- a/drivers/iio/chemical/pms7003.c
+++ b/drivers/iio/chemical/pms7003.c
@@ -14,7 +14,6 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/serdev.h>
diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c
index a665fcb78806..770571c21521 100644
--- a/drivers/iio/chemical/scd30_core.c
+++ b/drivers/iio/chemical/scd30_core.c
@@ -2,8 +2,10 @@
/*
* Sensirion SCD30 carbon dioxide sensor core driver
*
- * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com>
*/
+
+#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/completion.h>
@@ -43,6 +45,11 @@
#define SCD30_TEMP_OFFSET_MAX 655360
#define SCD30_EXTRA_TIMEOUT_PER_S 250
+/* Floating point arithmetic macros */
+#define SCD30_FLOAT_MANTISSA_MSK GENMASK(22, 0)
+#define SCD30_FLOAT_EXP_MSK GENMASK(30, 23)
+#define SCD30_FLOAT_SIGN_MSK BIT(31)
+
enum {
SCD30_CONC,
SCD30_TEMP,
@@ -89,10 +96,14 @@ static int scd30_reset(struct scd30_state *state)
/* simplified float to fixed point conversion with a scaling factor of 0.01 */
static int scd30_float_to_fp(int float32)
{
- int fraction, shift,
- mantissa = float32 & GENMASK(22, 0),
- sign = (float32 & BIT(31)) ? -1 : 1,
- exp = (float32 & ~BIT(31)) >> 23;
+ int fraction, shift, sign;
+ int mantissa = FIELD_GET(SCD30_FLOAT_MANTISSA_MSK, float32);
+ int exp = FIELD_GET(SCD30_FLOAT_EXP_MSK, float32);
+
+ if (float32 & SCD30_FLOAT_SIGN_MSK)
+ sign = -1;
+ else
+ sign = 1;
/* special case 0 */
if (!exp && !mantissa)
@@ -256,7 +267,7 @@ static int scd30_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const
guard(mutex)(&state->lock);
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
- if (val)
+ if (val || !val2)
return -EINVAL;
val = 1000000000 / val2;
@@ -368,11 +379,13 @@ static ssize_t calibration_auto_enable_show(struct device *dev, struct device_at
int ret;
u16 val;
- mutex_lock(&state->lock);
+ guard(mutex)(&state->lock);
+
ret = scd30_command_read(state, CMD_ASC, &val);
- mutex_unlock(&state->lock);
+ if (ret)
+ return ret;
- return ret ?: sysfs_emit(buf, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t calibration_auto_enable_store(struct device *dev, struct device_attribute *attr,
@@ -387,11 +400,13 @@ static ssize_t calibration_auto_enable_store(struct device *dev, struct device_a
if (ret)
return ret;
- mutex_lock(&state->lock);
+ guard(mutex)(&state->lock);
+
ret = scd30_command_write(state, CMD_ASC, val);
- mutex_unlock(&state->lock);
+ if (ret)
+ return ret;
- return ret ?: len;
+ return len;
}
static ssize_t calibration_forced_value_show(struct device *dev, struct device_attribute *attr,
@@ -402,11 +417,13 @@ static ssize_t calibration_forced_value_show(struct device *dev, struct device_a
int ret;
u16 val;
- mutex_lock(&state->lock);
+ guard(mutex)(&state->lock);
+
ret = scd30_command_read(state, CMD_FRC, &val);
- mutex_unlock(&state->lock);
+ if (ret)
+ return ret;
- return ret ?: sysfs_emit(buf, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t calibration_forced_value_store(struct device *dev, struct device_attribute *attr,
@@ -424,11 +441,13 @@ static ssize_t calibration_forced_value_store(struct device *dev, struct device_
if (val < SCD30_FRC_MIN_PPM || val > SCD30_FRC_MAX_PPM)
return -EINVAL;
- mutex_lock(&state->lock);
+ guard(mutex)(&state->lock);
+
ret = scd30_command_write(state, CMD_FRC, val);
- mutex_unlock(&state->lock);
+ if (ret)
+ return ret;
- return ret ?: len;
+ return len;
}
static IIO_DEVICE_ATTR_RO(sampling_frequency_available, 0);
@@ -579,24 +598,34 @@ out:
return IRQ_HANDLED;
}
+static int scd30_trigger_handler_helper(struct iio_dev *indio_dev, int *scan_data,
+ size_t scan_data_size)
+{
+ struct scd30_state *state = iio_priv(indio_dev);
+ int ret;
+
+ guard(mutex)(&state->lock);
+
+ if (!iio_trigger_using_own(indio_dev))
+ ret = scd30_read_poll(state);
+ else
+ ret = scd30_read_meas(state);
+ memcpy(scan_data, state->meas, scan_data_size);
+
+ return ret;
+}
+
static irqreturn_t scd30_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct scd30_state *state = iio_priv(indio_dev);
struct {
int data[SCD30_MEAS_COUNT];
aligned_s64 ts;
} scan = { };
int ret;
- mutex_lock(&state->lock);
- if (!iio_trigger_using_own(indio_dev))
- ret = scd30_read_poll(state);
- else
- ret = scd30_read_meas(state);
- memcpy(scan.data, state->meas, sizeof(state->meas));
- mutex_unlock(&state->lock);
+ ret = scd30_trigger_handler_helper(indio_dev, scan.data, sizeof(scan.data));
if (ret)
goto out;
@@ -657,7 +686,7 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev)
IRQF_NO_AUTOEN,
indio_dev->name, indio_dev);
if (ret)
- return dev_err_probe(dev, ret, "failed to request irq\n");
+ return ret;
return 0;
}
@@ -682,7 +711,11 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
state->pressure_comp = SCD30_PRESSURE_COMP_DEFAULT;
state->meas_interval = SCD30_MEAS_INTERVAL_DEFAULT;
state->command = command;
- mutex_init(&state->lock);
+
+ ret = devm_mutex_init(dev, &state->lock);
+ if (ret)
+ return ret;
+
init_completion(&state->meas_ready);
dev_set_drvdata(dev, indio_dev);
@@ -741,6 +774,6 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
}
EXPORT_SYMBOL_NS(scd30_probe, "IIO_SCD30");
-MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor core driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/chemical/scd30_i2c.c b/drivers/iio/chemical/scd30_i2c.c
index 436df9c61a71..bcef1e473e34 100644
--- a/drivers/iio/chemical/scd30_i2c.c
+++ b/drivers/iio/chemical/scd30_i2c.c
@@ -2,7 +2,7 @@
/*
* Sensirion SCD30 carbon dioxide sensor i2c driver
*
- * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com>
*
* I2C slave address: 0x61
*/
@@ -10,7 +10,6 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/unaligned.h>
@@ -20,7 +19,7 @@
#define SCD30_I2C_MAX_BUF_SIZE 18
#define SCD30_I2C_CRC8_POLYNOMIAL 0x31
-static u16 scd30_i2c_cmd_lookup_tbl[] = {
+static const u16 scd30_i2c_cmd_lookup_tbl[] = {
[CMD_START_MEAS] = 0x0010,
[CMD_STOP_MEAS] = 0x0104,
[CMD_MEAS_INTERVAL] = 0x4600,
@@ -71,6 +70,9 @@ static int scd30_i2c_command(struct scd30_state *state, enum scd30_cmd cmd, u16
int i, ret;
char crc;
+ if (!response && size != 0)
+ return -EINVAL;
+
put_unaligned_be16(scd30_i2c_cmd_lookup_tbl[cmd], buf);
i = 2;
@@ -134,7 +136,7 @@ static struct i2c_driver scd30_i2c_driver = {
};
module_i2c_driver(scd30_i2c_driver);
-MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor i2c driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("IIO_SCD30");
diff --git a/drivers/iio/chemical/scd30_serial.c b/drivers/iio/chemical/scd30_serial.c
index e8b453aae859..31b0fc957b08 100644
--- a/drivers/iio/chemical/scd30_serial.c
+++ b/drivers/iio/chemical/scd30_serial.c
@@ -2,14 +2,13 @@
/*
* Sensirion SCD30 carbon dioxide sensor serial driver
*
- * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com>
*/
#include <linux/crc16.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/iio/iio.h>
#include <linux/jiffies.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/serdev.h>
@@ -258,7 +257,7 @@ static struct serdev_device_driver scd30_serdev_driver = {
};
module_serdev_device_driver(scd30_serdev_driver);
-MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor serial driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("IIO_SCD30");
diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c
index 21730d62b5c8..379c1c4af8d8 100644
--- a/drivers/iio/chemical/sgp30.c
+++ b/drivers/iio/chemical/sgp30.c
@@ -20,7 +20,6 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
@@ -498,6 +497,7 @@ static const struct of_device_id sgp_dt_ids[] = {
{ .compatible = "sensirion,sgpc3", .data = &sgp_devices[SGPC3] },
{ }
};
+MODULE_DEVICE_TABLE(of, sgp_dt_ids);
static int sgp_probe(struct i2c_client *client)
{
@@ -548,6 +548,9 @@ static int sgp_probe(struct i2c_client *client)
data->iaq_thread = kthread_run(sgp_iaq_threadfn, data,
"%s-iaq", data->client->name);
+ if (IS_ERR(data->iaq_thread))
+ return dev_err_probe(dev, PTR_ERR(data->iaq_thread),
+ "failed to start IAQ thread\n");
return 0;
}
@@ -562,13 +565,11 @@ static void sgp_remove(struct i2c_client *client)
}
static const struct i2c_device_id sgp_id[] = {
- { "sgp30", (kernel_ulong_t)&sgp_devices[SGP30] },
- { "sgpc3", (kernel_ulong_t)&sgp_devices[SGPC3] },
+ { .name = "sgp30", .driver_data = (kernel_ulong_t)&sgp_devices[SGP30] },
+ { .name = "sgpc3", .driver_data = (kernel_ulong_t)&sgp_devices[SGPC3] },
{ }
};
-
MODULE_DEVICE_TABLE(i2c, sgp_id);
-MODULE_DEVICE_TABLE(of, sgp_dt_ids);
static struct i2c_driver sgp_driver = {
.driver = {
diff --git a/drivers/iio/chemical/sgp40.c b/drivers/iio/chemical/sgp40.c
index 07d8ab830211..b2b5e32a9eb2 100644
--- a/drivers/iio/chemical/sgp40.c
+++ b/drivers/iio/chemical/sgp40.c
@@ -355,7 +355,7 @@ static int sgp40_probe(struct i2c_client *client)
}
static const struct i2c_device_id sgp40_id[] = {
- { "sgp40" },
+ { .name = "sgp40" },
{ }
};
diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c
index a934bf0298dd..8e15baa31423 100644
--- a/drivers/iio/chemical/sps30.c
+++ b/drivers/iio/chemical/sps30.c
@@ -5,6 +5,7 @@
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*/
+#include <linux/cleanup.h>
#include <linux/crc8.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -69,6 +70,8 @@ static int sps30_do_meas(struct sps30_state *state, s32 *data, int size)
{
int i, ret;
+ guard(mutex)(&state->lock);
+
if (state->state == RESET) {
ret = state->ops->start_meas(state);
if (ret)
@@ -111,9 +114,7 @@ static irqreturn_t sps30_trigger_handler(int irq, void *p)
aligned_s64 ts;
} scan;
- mutex_lock(&state->lock);
ret = sps30_do_meas(state, scan.data, ARRAY_SIZE(scan.data));
- mutex_unlock(&state->lock);
if (ret)
goto err;
@@ -136,7 +137,6 @@ static int sps30_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_MASSCONCENTRATION:
- mutex_lock(&state->lock);
/* read up to the number of bytes actually needed */
switch (chan->channel2) {
case IIO_MOD_PM1:
@@ -152,7 +152,6 @@ static int sps30_read_raw(struct iio_dev *indio_dev,
ret = sps30_do_meas(state, data, 4);
break;
}
- mutex_unlock(&state->lock);
if (ret)
return ret;
@@ -197,9 +196,9 @@ static ssize_t start_cleaning_store(struct device *dev,
if (kstrtoint(buf, 0, &val) || val != 1)
return -EINVAL;
- mutex_lock(&state->lock);
+ guard(mutex)(&state->lock);
+
ret = state->ops->clean_fan(state);
- mutex_unlock(&state->lock);
if (ret)
return ret;
@@ -215,9 +214,9 @@ static ssize_t cleaning_period_show(struct device *dev,
__be32 val;
int ret;
- mutex_lock(&state->lock);
+ guard(mutex)(&state->lock);
+
ret = state->ops->read_cleaning_period(state, &val);
- mutex_unlock(&state->lock);
if (ret)
return ret;
@@ -238,12 +237,11 @@ static ssize_t cleaning_period_store(struct device *dev, struct device_attribute
(val > SPS30_AUTO_CLEANING_PERIOD_MAX))
return -EINVAL;
- mutex_lock(&state->lock);
+ guard(mutex)(&state->lock);
+
ret = state->ops->write_cleaning_period(state, cpu_to_be32(val));
- if (ret) {
- mutex_unlock(&state->lock);
+ if (ret)
return ret;
- }
msleep(20);
@@ -256,8 +254,6 @@ static ssize_t cleaning_period_store(struct device *dev, struct device_attribute
dev_warn(dev,
"period changed but reads will return the old value\n");
- mutex_unlock(&state->lock);
-
return len;
}
diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c
index c92f04990c34..2d3a876cc06e 100644
--- a/drivers/iio/chemical/sps30_i2c.c
+++ b/drivers/iio/chemical/sps30_i2c.c
@@ -2,7 +2,7 @@
/*
* Sensirion SPS30 particulate matter sensor i2c driver
*
- * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com>
*
* I2C slave address: 0x69
*/
@@ -12,7 +12,6 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -232,7 +231,7 @@ static int sps30_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id sps30_i2c_id[] = {
- { "sps30" },
+ { .name = "sps30" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sps30_i2c_id);
@@ -253,7 +252,7 @@ static struct i2c_driver sps30_i2c_driver = {
};
module_i2c_driver(sps30_i2c_driver);
-MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor i2c driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("IIO_SPS30");
diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c
index a5e6bc08d5fd..0cdba8703e93 100644
--- a/drivers/iio/chemical/sps30_serial.c
+++ b/drivers/iio/chemical/sps30_serial.c
@@ -2,14 +2,13 @@
/*
* Sensirion SPS30 particulate matter sensor serial driver
*
- * Copyright (c) 2021 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ * Copyright (c) 2021 Tomasz Duszynski <tduszyns@gmail.com>
*/
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/iio/iio.h>
#include <linux/minmax.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/serdev.h>
#include <linux/types.h>
@@ -426,7 +425,7 @@ static struct serdev_device_driver sps30_serial_driver = {
};
module_serdev_device_driver(sps30_serial_driver);
-MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor serial driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("IIO_SPS30");
diff --git a/drivers/iio/chemical/sunrise_co2.c b/drivers/iio/chemical/sunrise_co2.c
index 158be9d798d2..dae8a7025e05 100644
--- a/drivers/iio/chemical/sunrise_co2.c
+++ b/drivers/iio/chemical/sunrise_co2.c
@@ -13,7 +13,6 @@
#include <linux/bitops.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c
index 5b358bcd311b..2e10a6b17047 100644
--- a/drivers/iio/chemical/vz89x.c
+++ b/drivers/iio/chemical/vz89x.c
@@ -10,7 +10,6 @@
#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -385,8 +384,8 @@ static int vz89x_probe(struct i2c_client *client)
}
static const struct i2c_device_id vz89x_id[] = {
- { "vz89x", (kernel_ulong_t)&vz89x_chips[VZ89X] },
- { "vz89te", (kernel_ulong_t)&vz89x_chips[VZ89TE] },
+ { .name = "vz89x", .driver_data = (kernel_ulong_t)&vz89x_chips[VZ89X] },
+ { .name = "vz89te", .driver_data = (kernel_ulong_t)&vz89x_chips[VZ89TE] },
{ }
};
MODULE_DEVICE_TABLE(i2c, vz89x_id);
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c b/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c
index 6e38d115b6fe..6762685e6876 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c
@@ -279,13 +279,7 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
channel++;
}
- /* Timestamp */
- channel->scan_index = index;
- channel->type = IIO_TIMESTAMP;
- channel->channel = -1;
- channel->scan_type.sign = 's';
- channel->scan_type.realbits = 64;
- channel->scan_type.storagebits = 64;
+ *channel = IIO_CHAN_SOFT_TIMESTAMP(index);
indio_dev->channels = st->channels;
indio_dev->num_channels = index + 1;
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c
index 2d3d148b4206..8f5bf40a0596 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c
@@ -20,7 +20,6 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_device.h>
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
index 82cef4a12442..b971f8b646be 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
@@ -16,7 +16,6 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
@@ -106,7 +105,7 @@ static int cros_ec_sensors_read(struct iio_dev *indio_dev,
switch (st->core.type) {
case MOTIONSENSE_TYPE_ACCEL:
/*
- * EC returns data in g, iio exepects m/s^2.
+ * EC returns data in g, IIO expects m/s^2.
* Do not use IIO_G_TO_M_S_2 to avoid precision loss.
*/
*val = div_s64(val64 * 980665, 10);
@@ -279,13 +278,7 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
}
}
- /* Timestamp */
- channel->type = IIO_TIMESTAMP;
- channel->channel = -1;
- channel->scan_index = CROS_EC_SENSOR_MAX_AXIS;
- channel->scan_type.sign = 's';
- channel->scan_type.realbits = 64;
- channel->scan_type.storagebits = 64;
+ *channel = IIO_CHAN_SOFT_TIMESTAMP(CROS_EC_SENSOR_MAX_AXIS);
indio_dev->channels = state->channels;
indio_dev->num_channels = CROS_EC_SENSORS_MAX_CHANNELS;
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
index a61428bfdce3..9e7c26e37880 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
@@ -72,8 +72,7 @@ static const struct {
{HID_USAGE_SENSOR_HUMAN_ATTENTION, 0, 1, 0},
};
-static void simple_div(int dividend, int divisor, int *whole,
- int *micro_frac)
+static void simple_div(int dividend, int divisor, int *whole, int *micro_frac)
{
int rem;
int exp = 0;
@@ -111,7 +110,7 @@ for 10^-2.
Negative numbers are 2's complement
*/
static void convert_from_vtf_format(u32 value, int size, int exp,
- int *val1, int *val2)
+ int *val1, int *val2)
{
int sign = 1;
@@ -176,7 +175,7 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
EXPORT_SYMBOL_NS(hid_sensor_read_poll_value, "IIO_HID_ATTRIBUTES");
int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
- int *val1, int *val2)
+ int *val1, int *val2)
{
s32 value;
int ret;
@@ -203,7 +202,7 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
EXPORT_SYMBOL_NS(hid_sensor_read_samp_freq_value, "IIO_HID");
int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
- int val1, int val2)
+ int val1, int val2)
{
s32 value;
int ret;
@@ -238,15 +237,15 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
EXPORT_SYMBOL_NS(hid_sensor_write_samp_freq_value, "IIO_HID");
int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
- int *val1, int *val2)
+ int *val1, int *val2)
{
s32 value;
int ret;
ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity.report_id,
- st->sensitivity.index, sizeof(value),
- &value);
+ st->sensitivity.index,
+ sizeof(value), &value);
if (ret < 0 || value < 0) {
*val1 = *val2 = 0;
return -EINVAL;
@@ -268,8 +267,8 @@ int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1,
ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity_rel.report_id,
- st->sensitivity_rel.index, sizeof(value),
- &value);
+ st->sensitivity_rel.index,
+ sizeof(value), &value);
if (ret < 0 || value < 0) {
*val1 = *val2 = 0;
return -EINVAL;
@@ -282,9 +281,8 @@ int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1,
}
EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_rel_value, "IIO_HID");
-
int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
- int val1, int val2)
+ int val1, int val2)
{
s32 value;
int ret;
@@ -293,8 +291,8 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
return -EINVAL;
value = convert_to_vtf_format(st->sensitivity.size,
- st->sensitivity.unit_expo,
- val1, val2);
+ st->sensitivity.unit_expo,
+ val1, val2);
ret = sensor_hub_set_feature(st->hsdev, st->sensitivity.report_id,
st->sensitivity.index, sizeof(value),
&value);
@@ -303,8 +301,8 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity.report_id,
- st->sensitivity.index, sizeof(value),
- &value);
+ st->sensitivity.index,
+ sizeof(value), &value);
if (ret < 0 || value < 0)
return -EINVAL;
@@ -324,8 +322,8 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st,
return -EINVAL;
value = convert_to_vtf_format(st->sensitivity_rel.size,
- st->sensitivity_rel.unit_expo,
- val1, val2);
+ st->sensitivity_rel.unit_expo,
+ val1, val2);
ret = sensor_hub_set_feature(st->hsdev, st->sensitivity_rel.report_id,
st->sensitivity_rel.index, sizeof(value),
&value);
@@ -334,8 +332,8 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st,
ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity_rel.report_id,
- st->sensitivity_rel.index, sizeof(value),
- &value);
+ st->sensitivity_rel.index,
+ sizeof(value), &value);
if (ret < 0 || value < 0)
return -EINVAL;
@@ -346,7 +344,7 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st,
EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_rel_value, "IIO_HID");
/*
- * This fuction applies the unit exponent to the scale.
+ * This function applies the unit exponent to the scale.
* For example:
* 9.806650000 ->exp:2-> val0[980]val1[665000000]
* 9.000806000 ->exp:2-> val0[900]val1[80600000]
@@ -356,8 +354,8 @@ EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_rel_value, "IIO_HID");
* 1.001745329 ->exp:4-> val0[10017]val1[453290000]
* 9.806650000 ->exp:-2-> val0[0]val1[98066500]
*/
-static void adjust_exponent_nano(int *val0, int *val1, int scale0,
- int scale1, int exp)
+static void adjust_exponent_nano(int *val0, int *val1,
+ int scale0, int scale1, int exp)
{
int divisor;
int i;
@@ -404,8 +402,8 @@ static void adjust_exponent_nano(int *val0, int *val1, int scale0,
}
int hid_sensor_format_scale(u32 usage_id,
- struct hid_sensor_hub_attribute_info *attr_info,
- int *val0, int *val1)
+ struct hid_sensor_hub_attribute_info *attr_info,
+ int *val0, int *val1)
{
int i;
int exp;
@@ -415,12 +413,11 @@ int hid_sensor_format_scale(u32 usage_id,
for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) {
if (unit_conversion[i].usage_id == usage_id &&
- unit_conversion[i].unit == attr_info->units) {
- exp = hid_sensor_convert_exponent(
- attr_info->unit_expo);
+ unit_conversion[i].unit == attr_info->units) {
+ exp = hid_sensor_convert_exponent(attr_info->unit_expo);
adjust_exponent_nano(val0, val1,
- unit_conversion[i].scale_val0,
- unit_conversion[i].scale_val1, exp);
+ unit_conversion[i].scale_val0,
+ unit_conversion[i].scale_val1, exp);
break;
}
}
@@ -438,8 +435,8 @@ EXPORT_SYMBOL_NS(hid_sensor_convert_timestamp, "IIO_HID");
static
int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- struct hid_sensor_common *st)
+ u32 usage_id,
+ struct hid_sensor_common *st)
{
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
@@ -473,9 +470,10 @@ int hid_sensor_get_report_latency(struct hid_sensor_common *st)
int ret;
int value;
- ret = sensor_hub_get_feature(st->hsdev, st->report_latency.report_id,
- st->report_latency.index, sizeof(value),
- &value);
+ ret = sensor_hub_get_feature(st->hsdev,
+ st->report_latency.report_id,
+ st->report_latency.index,
+ sizeof(value), &value);
if (ret < 0)
return ret;
@@ -498,10 +496,10 @@ bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st)
EXPORT_SYMBOL_NS(hid_sensor_batch_mode_supported, "IIO_HID_ATTRIBUTES");
int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- struct hid_sensor_common *st,
- const u32 *sensitivity_addresses,
- u32 sensitivity_addresses_len)
+ u32 usage_id,
+ struct hid_sensor_common *st,
+ const u32 *sensitivity_addresses,
+ u32 sensitivity_addresses_len)
{
struct hid_sensor_hub_attribute_info timestamp;
@@ -527,7 +525,7 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS,
- &st->sensitivity);
+ &st->sensitivity);
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
@@ -578,8 +576,9 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
timestamp.index, timestamp.report_id);
ret = sensor_hub_get_feature(hsdev,
- st->power_state.report_id,
- st->power_state.index, sizeof(value), &value);
+ st->power_state.report_id,
+ st->power_state.index,
+ sizeof(value), &value);
if (ret < 0)
return ret;
if (value < 0)
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 5540e2d28f4a..60808e2430ca 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -14,6 +14,7 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/sysfs.h>
+#include <linux/iio/kfifo_buf.h>
#include "hid-sensor-trigger.h"
static ssize_t _hid_sensor_set_report_latency(struct device *dev,
@@ -202,12 +203,21 @@ static void hid_sensor_set_power_work(struct work_struct *work)
_hid_sensor_power_state(attrb, true);
}
-static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
- bool state)
+static int buffer_postenable(struct iio_dev *indio_dev)
{
- return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state);
+ return hid_sensor_power_state(iio_device_get_drvdata(indio_dev), 1);
}
+static int buffer_predisable(struct iio_dev *indio_dev)
+{
+ return hid_sensor_power_state(iio_device_get_drvdata(indio_dev), 0);
+}
+
+static const struct iio_buffer_setup_ops hid_sensor_buffer_ops = {
+ .postenable = buffer_postenable,
+ .predisable = buffer_predisable,
+};
+
void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
struct hid_sensor_common *attrb)
{
@@ -219,16 +229,11 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
cancel_work_sync(&attrb->work);
iio_trigger_unregister(attrb->trigger);
iio_trigger_free(attrb->trigger);
- iio_triggered_buffer_cleanup(indio_dev);
}
EXPORT_SYMBOL_NS(hid_sensor_remove_trigger, "IIO_HID");
-static const struct iio_trigger_ops hid_sensor_trigger_ops = {
- .set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
-};
-
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
- struct hid_sensor_common *attrb)
+ struct hid_sensor_common *attrb)
{
const struct iio_dev_attr **fifo_attrs;
int ret;
@@ -239,25 +244,34 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
else
fifo_attrs = NULL;
- ret = iio_triggered_buffer_setup_ext(indio_dev,
- &iio_pollfunc_store_time, NULL,
- IIO_BUFFER_DIRECTION_IN,
- NULL, fifo_attrs);
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_HARDWARE_TRIGGERED;
+
+ ret = devm_iio_kfifo_buffer_setup_ext(&indio_dev->dev, indio_dev,
+ &hid_sensor_buffer_ops,
+ fifo_attrs);
if (ret) {
- dev_err(&indio_dev->dev, "Triggered Buffer Setup Failed\n");
+ dev_err(&indio_dev->dev, "Kfifo Buffer Setup Failed\n");
return ret;
}
+ /*
+ * The current user space in distro "iio-sensor-proxy" is not working in
+ * trigerless mode and it expects
+ * /sys/bus/iio/devices/iio:device0/trigger/current_trigger.
+ * The change replacing iio_triggered_buffer_setup_ext() with
+ * devm_iio_kfifo_buffer_setup_ext() will not create attribute without
+ * registering a trigger with INDIO_HARDWARE_TRIGGERED.
+ * So the below code fragment is still required.
+ */
+
trig = iio_trigger_alloc(indio_dev->dev.parent,
"%s-dev%d", name, iio_device_id(indio_dev));
- if (trig == NULL) {
+ if (!trig) {
dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
- ret = -ENOMEM;
- goto error_triggered_buffer_cleanup;
+ return -ENOMEM;
}
iio_trigger_set_drvdata(trig, attrb);
- trig->ops = &hid_sensor_trigger_ops;
ret = iio_trigger_register(trig);
if (ret) {
@@ -284,8 +298,6 @@ error_unreg_trigger:
iio_trigger_unregister(trig);
error_free_trig:
iio_trigger_free(trig);
-error_triggered_buffer_cleanup:
- iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
EXPORT_SYMBOL_NS(hid_sensor_setup_trigger, "IIO_HID");
@@ -302,7 +314,9 @@ static int __maybe_unused hid_sensor_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+
schedule_work(&attrb->work);
+
return 0;
}
@@ -310,6 +324,7 @@ static int __maybe_unused hid_sensor_runtime_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+
return _hid_sensor_power_state(attrb, true);
}
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
index f94fca4f1edf..589de858e369 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -15,7 +15,7 @@ struct iio_dev;
extern const struct dev_pm_ops hid_sensor_pm_ops;
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
- struct hid_sensor_common *attrb);
+ struct hid_sensor_common *attrb);
void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
struct hid_sensor_common *attrb);
int hid_sensor_power_state(struct hid_sensor_common *st, bool state);
diff --git a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c
index 97526ba87b93..88a82d1370c5 100644
--- a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c
+++ b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c
@@ -10,18 +10,19 @@
#include <linux/iio/common/inv_sensors_timestamp.h>
-/* compute jitter, min and max following jitter in per mille */
-#define INV_SENSORS_TIMESTAMP_JITTER(_val, _jitter) \
- (div_s64((_val) * (_jitter), 1000))
+/* compute min and max following jitter in per mille */
#define INV_SENSORS_TIMESTAMP_MIN(_val, _jitter) \
(((_val) * (1000 - (_jitter))) / 1000)
#define INV_SENSORS_TIMESTAMP_MAX(_val, _jitter) \
(((_val) * (1000 + (_jitter))) / 1000)
+/* minimum timestamp delta between 2 interrupts for measuring period (20ms) */
+#define INV_SENSORS_MIN_IT_DELTA (20 * NSEC_PER_MSEC)
+
/* Add a new value inside an accumulator and update the estimate value */
-static void inv_update_acc(struct inv_sensors_timestamp_acc *acc, uint32_t val)
+static void inv_update_acc(struct inv_sensors_timestamp_acc *acc, u32 val)
{
- uint64_t sum = 0;
+ u64 sum = 0;
size_t i;
acc->values[acc->idx++] = val;
@@ -58,9 +59,9 @@ void inv_sensors_timestamp_init(struct inv_sensors_timestamp *ts,
EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_init, "IIO_INV_SENSORS_TIMESTAMP");
int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts,
- uint32_t period, bool fifo)
+ u32 period, bool fifo)
{
- uint32_t mult;
+ u32 mult;
/* when FIFO is on, prevent odr change if one is already pending */
if (fifo && ts->new_mult != 0)
@@ -78,9 +79,9 @@ int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts,
}
EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_update_odr, "IIO_INV_SENSORS_TIMESTAMP");
-static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period)
+static bool inv_validate_period(struct inv_sensors_timestamp *ts, u32 period)
{
- uint32_t period_min, period_max;
+ u32 period_min, period_max;
/* check that period is acceptable */
period_min = ts->min_period * ts->mult;
@@ -92,9 +93,9 @@ static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t perio
}
static bool inv_update_chip_period(struct inv_sensors_timestamp *ts,
- uint32_t period)
+ u32 period)
{
- uint32_t new_chip_period;
+ u32 new_chip_period;
if (!inv_validate_period(ts, period))
return false;
@@ -102,78 +103,84 @@ static bool inv_update_chip_period(struct inv_sensors_timestamp *ts,
/* update chip internal period estimation */
new_chip_period = period / ts->mult;
inv_update_acc(&ts->chip_period, new_chip_period);
- ts->period = ts->mult * ts->chip_period.val;
return true;
}
-static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts)
+static u32 inv_align_timestamp_it(struct inv_sensors_timestamp *ts,
+ unsigned int sample_nb)
{
- const int64_t period_min = (int64_t)ts->min_period * ts->mult;
- const int64_t period_max = (int64_t)ts->max_period * ts->mult;
- int64_t add_max, sub_max;
- int64_t delta, jitter;
- int64_t adjust;
-
- /* delta time between last sample and last interrupt */
- delta = ts->it.lo - ts->timestamp;
-
- /* adjust timestamp while respecting jitter */
- add_max = period_max - (int64_t)ts->period;
- sub_max = period_min - (int64_t)ts->period;
- jitter = INV_SENSORS_TIMESTAMP_JITTER((int64_t)ts->period, ts->chip.jitter);
- if (delta > jitter)
- adjust = add_max;
- else if (delta < -jitter)
- adjust = sub_max;
- else
- adjust = 0;
+ const s64 period_min = (s64)ts->min_period * ts->mult;
+ const s64 period_max = (s64)ts->max_period * ts->mult;
+ s64 new_period;
+
+ /* compute new period aligning last timestamp with interrupt timestamp */
+ new_period = div_s64(ts->it.up - ts->timestamp, sample_nb);
- ts->timestamp += adjust;
+ /* ensure that period never overflows the jitter */
+ return clamp(new_period, period_min, period_max);
}
void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts,
- size_t sample_nb, int64_t timestamp)
+ size_t sample_nb, s64 timestamp)
{
struct inv_sensors_timestamp_interval *it;
- int64_t delta, interval;
- uint32_t period;
+ s64 delta, delta_threshold, interval;
+ u32 period;
bool valid = false;
if (sample_nb == 0)
return;
+ /* no previous data, compute theoretical value from interrupt */
+ if (ts->timestamp == 0) {
+ /* elapsed time: sensor period * sensor samples number */
+ interval = (s64)ts->period * (s64)sample_nb;
+ ts->timestamp = timestamp - interval;
+ }
+
+ /* update delta timestamps and estimated period */
+ it = &ts->delta;
+ ts->delta_counter += sample_nb;
+ delta = timestamp - it->up;
+ delta_threshold = INV_SENSORS_TIMESTAMP_MIN(INV_SENSORS_MIN_IT_DELTA, ts->chip.jitter);
+ if (delta >= delta_threshold) {
+ it->lo = it->up;
+ it->up = timestamp;
+ if (it->lo != 0) {
+ /* compute period: delta time divided by number of samples */
+ delta = it->up - it->lo;
+ period = div_s64(delta, ts->delta_counter);
+ inv_update_chip_period(ts, period);
+ }
+ ts->delta_counter = 0;
+ }
+
/* update interrupt timestamp and compute chip and sensor periods */
it = &ts->it;
it->lo = it->up;
it->up = timestamp;
delta = it->up - it->lo;
if (it->lo != 0) {
- /* compute period: delta time divided by number of samples */
+ /* compute period and check validity */
period = div_s64(delta, sample_nb);
- valid = inv_update_chip_period(ts, period);
- }
-
- /* no previous data, compute theoritical value from interrupt */
- if (ts->timestamp == 0) {
- /* elapsed time: sensor period * sensor samples number */
- interval = (int64_t)ts->period * (int64_t)sample_nb;
- ts->timestamp = it->up - interval;
- return;
+ valid = inv_validate_period(ts, period);
}
/* if interrupt interval is valid, sync with interrupt timestamp */
if (valid)
- inv_align_timestamp_it(ts);
+ ts->period = inv_align_timestamp_it(ts, sample_nb);
+ else
+ ts->period = ts->mult * ts->chip_period.val;
}
EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_interrupt, "IIO_INV_SENSORS_TIMESTAMP");
void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts,
- uint32_t fifo_period, size_t fifo_nb,
+ u32 fifo_period, size_t fifo_nb,
unsigned int fifo_no)
{
- int64_t interval;
- uint32_t fifo_mult;
+ s64 interval;
+ u32 fifo_mult;
if (ts->new_mult == 0)
return;
@@ -185,7 +192,7 @@ void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts,
/*
* After ODR change the time interval with the previous sample is
- * undertermined (depends when the change occures). So we compute the
+ * undertermined (depends when the change occurs). So we compute the
* timestamp from the current interrupt using the new FIFO period, the
* total number of samples and the current sample numero.
*/
@@ -194,7 +201,7 @@ void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts,
fifo_mult = fifo_period / ts->chip.clock_period;
fifo_period = fifo_mult * ts->chip_period.val;
/* computes time interval between interrupt and this sample */
- interval = (int64_t)(fifo_nb - fifo_no) * (int64_t)fifo_period;
+ interval = (s64)(fifo_nb - fifo_no) * (s64)fifo_period;
ts->timestamp = ts->it.up - interval;
}
}
diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
index 588470863681..1960a2ce82a8 100644
--- a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
+++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
@@ -96,7 +96,7 @@ EXPORT_SYMBOL_NS(ms_sensors_read_prom_word, "IIO_MEAS_SPEC_SENSORS");
*
* Generic ADC conversion & read function for Measurement Specialties
* devices.
- * The function will issue conversion command, sleep appopriate delay, and
+ * The function will issue conversion command, sleep appropriate delay, and
* issue command to read ADC.
*
* Return: 0 on success, negative errno otherwise.
diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c
index 5136ad9ada04..442b40ef27cf 100644
--- a/drivers/iio/common/scmi_sensors/scmi_iio.c
+++ b/drivers/iio/common/scmi_sensors/scmi_iio.c
@@ -419,17 +419,6 @@ static const struct iio_chan_spec_ext_info scmi_iio_ext_info[] = {
{ }
};
-static void scmi_iio_set_timestamp_channel(struct iio_chan_spec *iio_chan,
- int scan_index)
-{
- iio_chan->type = IIO_TIMESTAMP;
- iio_chan->channel = -1;
- iio_chan->scan_index = scan_index;
- iio_chan->scan_type.sign = 'u';
- iio_chan->scan_type.realbits = 64;
- iio_chan->scan_type.storagebits = 64;
-}
-
static void scmi_iio_set_data_channel(struct iio_chan_spec *iio_chan,
enum iio_chan_type type,
enum iio_modifier mod, int scan_index)
@@ -629,7 +618,7 @@ scmi_alloc_iiodev(struct scmi_device *sdev,
"Error in registering sensor update notifier for sensor %s\n",
sensor->sensor_info->name);
- scmi_iio_set_timestamp_channel(&iio_channels[i], i);
+ iio_channels[i] = IIO_CHAN_SOFT_TIMESTAMP(i);
iiodev->channels = iio_channels;
return iiodev;
}
diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c
index da09c9f3ceb6..828fcfe1d4f1 100644
--- a/drivers/iio/common/ssp_sensors/ssp_dev.c
+++ b/drivers/iio/common/ssp_sensors/ssp_dev.c
@@ -7,7 +7,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/mfd/core.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
@@ -28,7 +27,7 @@ struct ssp_instruction {
__le32 a;
__le32 b;
u8 c;
-} __attribute__((__packed__));
+} __packed__;
static const u8 ssp_magnitude_table[] = {110, 85, 171, 71, 203, 195, 0, 67,
208, 56, 175, 244, 206, 213, 0, 92, 250, 0, 55, 48, 189, 252, 171,
@@ -590,6 +589,7 @@ static void ssp_remove(struct spi_device *spi)
ssp_clean_pending_list(data);
free_irq(data->spi->irq, data);
+ cancel_delayed_work_sync(&data->work_refresh);
timer_delete_sync(&data->wdt_timer);
cancel_work_sync(&data->work_wdt);
diff --git a/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h b/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h
index 4528ab55eb68..05fcad61c848 100644
--- a/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h
+++ b/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h
@@ -18,18 +18,6 @@
},\
}
-/* It is defined here as it is a mixed timestamp */
-#define SSP_CHAN_TIMESTAMP(_si) { \
- .type = IIO_TIMESTAMP, \
- .channel = -1, \
- .scan_index = _si, \
- .scan_type = { \
- .sign = 's', \
- .realbits = 64, \
- .storagebits = 64, \
- }, \
-}
-
#define SSP_MS_PER_S 1000
#define SSP_INVERTED_SCALING_FACTOR 1000000U
diff --git a/drivers/iio/common/ssp_sensors/ssp_spi.c b/drivers/iio/common/ssp_sensors/ssp_spi.c
index 6c81c0385fb5..08ed92859be0 100644
--- a/drivers/iio/common/ssp_sensors/ssp_spi.c
+++ b/drivers/iio/common/ssp_sensors/ssp_spi.c
@@ -6,7 +6,7 @@
#include "ssp.h"
#define SSP_DEV (&data->spi->dev)
-#define SSP_GET_MESSAGE_TYPE(data) (data & (3 << SSP_RW))
+#define SSP_GET_MESSAGE_TYPE(data) ((data) & (3 << SSP_RW))
/*
* SSP -> AP Instruction
@@ -29,7 +29,7 @@ struct ssp_msg_header {
__le16 length;
__le16 options;
__le32 data;
-} __attribute__((__packed__));
+} __packed;
struct ssp_msg {
u16 length;
@@ -119,9 +119,9 @@ static inline void ssp_get_buffer(struct ssp_msg *m, unsigned int offset,
}
#define SSP_GET_BUFFER_AT_INDEX(m, index) \
- (m->buffer[SSP_HEADER_SIZE_ALIGNED + index])
+ ((m)->buffer[SSP_HEADER_SIZE_ALIGNED + (index)])
#define SSP_SET_BUFFER_AT_INDEX(m, index, val) \
- (m->buffer[SSP_HEADER_SIZE_ALIGNED + index] = val)
+ ((m)->buffer[SSP_HEADER_SIZE_ALIGNED + (index)] = val)
static void ssp_clean_msg(struct ssp_msg *m)
{
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index dac593be5695..76f91696f66a 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -498,29 +498,35 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
u8 *outdata;
struct st_sensor_data *sdata = iio_priv(indio_dev);
unsigned int byte_for_channel;
+ u32 tmp;
byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits +
ch->scan_type.shift, 8);
- outdata = kmalloc(byte_for_channel, GFP_DMA | GFP_KERNEL);
- if (!outdata)
- return -ENOMEM;
+ outdata = sdata->buffer_data;
err = regmap_bulk_read(sdata->regmap, ch->address,
outdata, byte_for_channel);
if (err < 0)
- goto st_sensors_free_memory;
-
- if (byte_for_channel == 1)
- *data = (s8)*outdata;
- else if (byte_for_channel == 2)
- *data = (s16)get_unaligned_le16(outdata);
- else if (byte_for_channel == 3)
- *data = (s32)sign_extend32(get_unaligned_le24(outdata), 23);
+ return err;
-st_sensors_free_memory:
- kfree(outdata);
+ if (byte_for_channel == 1) {
+ tmp = *outdata;
+ } else if (byte_for_channel == 2) {
+ if (ch->scan_type.endianness == IIO_BE)
+ tmp = get_unaligned_be16(outdata);
+ else
+ tmp = get_unaligned_le16(outdata);
+ } else if (byte_for_channel == 3) {
+ if (ch->scan_type.endianness == IIO_BE)
+ tmp = get_unaligned_be24(outdata);
+ else
+ tmp = get_unaligned_le24(outdata);
+ } else {
+ return -EINVAL;
+ }
+ *data = sign_extend32(tmp, BYTES_TO_BITS(byte_for_channel) - 1);
- return err;
+ return 0;
}
int st_sensors_read_info_raw(struct iio_dev *indio_dev,
diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c
index 8a8ab688d798..7b3e9732cc3e 100644
--- a/drivers/iio/common/st_sensors/st_sensors_trigger.c
+++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
@@ -211,10 +211,8 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
irq_trig,
sdata->trig->name,
sdata->trig);
- if (err) {
- dev_err(parent, "failed to request trigger IRQ.\n");
+ if (err)
return err;
- }
err = devm_iio_trigger_register(parent, sdata->trig);
if (err < 0) {
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index db9f5c711b3d..3b3c77d8b3e1 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -11,8 +11,11 @@ config AD3530R
depends on SPI
select REGMAP_SPI
help
- Say yes here to build support for Analog Devices AD3530R, AD3531R
- Digital to Analog Converter.
+ Say yes here to build support for the following Analog Devices
+ Digital to Analog Converters:
+ - AD3530/AD3530R (8-channel)
+ - AD3531/AD3531R (4-channel)
+ - AD3532/AD3532R (16-channel)
To compile this driver as a module, choose M here: the
module will be called ad3530r.
@@ -178,6 +181,17 @@ config AD5624R_SPI
Say yes here to build support for Analog Devices AD5624R, AD5644R and
AD5664R converters (DAC). This driver uses the common SPI interface.
+config AD5706R
+ tristate "Analog Devices AD5706R DAC driver"
+ depends on SPI
+ select REGMAP
+ help
+ Say yes here to build support for Analog Devices AD5706R 4-channel,
+ 16-bit current output DAC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad5706r.
+
config AD9739A
tristate "Analog Devices AD9739A RF DAC spi driver"
depends on SPI
@@ -229,15 +243,26 @@ config LTC2688
config AD5686
tristate
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
config AD5686_SPI
tristate "Analog Devices AD5686 and similar multi-channel DACs (SPI)"
depends on SPI
select AD5686
help
- Say yes here to build support for Analog Devices AD5672R, AD5674R,
- AD5676, AD5676R, AD5679R, AD5684, AD5684R, AD5684R, AD5685R, AD5686,
- AD5686R Voltage Output Digital to Analog Converter.
+ Say yes here to build support for Analog Devices Voltage Output
+ Digital to Analog Converters:
+ - Single-channel:
+ AD5310R, AD5681R, AD5682R, AD5683, AD5683R
+ - Dual-channel:
+ AD5313R, AD5687, AD5687R, AD5689, AD5689R
+ - Quad-channel:
+ AD5317R, AD5684, AD5684R, AD5685R, AD5686, AD5686R
+ - 8-channel:
+ AD5672R, AD5676, AD5676R
+ - 16-channel:
+ AD5674, AD5674R, AD5679, AD5679R
To compile this driver as a module, choose M here: the
module will be called ad5686.
@@ -247,10 +272,18 @@ config AD5696_I2C
depends on I2C
select AD5686
help
- Say yes here to build support for Analog Devices AD5311R, AD5337,
- AD5338R, AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693,
- AD5693R, AD5694, AD5694R, AD5695R, AD5696, and AD5696R Digital to
- Analog converters.
+ Say yes here to build support for Analog Devices Voltage Output
+ Digital to Analog Converters:
+ - Single-channel:
+ AD5311R, AD5691R, AD5692R, AD5693, AD5693R
+ - Dual-channel:
+ AD5338R, AD5697R
+ - Quad-channel:
+ AD5316R, AD5694, AD5694R, AD5695R, AD5696, AD5696R
+ - 8-channel:
+ AD5671R, AD5675, AD5675R
+ - 16-channel:
+ AD5673R, AD5677R
To compile this driver as a module, choose M here: the module will be
called ad5696.
@@ -408,6 +441,7 @@ config DPOT_DAC
config DS4424
tristate "Maxim Integrated DS4422/DS4424 DAC driver"
depends on I2C
+ select REGMAP_I2C
help
If you say yes here you get support for Maxim chips DS4422, DS4424.
@@ -515,6 +549,17 @@ config MAX5821
Say yes here to build support for Maxim MAX5821
10 bits DAC.
+config MCF54415_DAC
+ tristate "NXP MCF54415 DAC driver"
+ depends on M5441x || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ Say yes here if you want to build support for NXP ColdFire
+ MCF54415/6/7/8 12-bit DAC module.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mcf54415_dac.
+
config MCP4725
tristate "MCP4725/6 DAC driver"
depends on I2C
@@ -537,9 +582,20 @@ config MCP4728
To compile this driver as a module, choose M here: the module
will be called mcp4728.
+config MCP47A1
+ tristate "MCP47A1 DAC driver"
+ depends on I2C
+ help
+ Say Y here if you want to build a driver for the Microchip
+ MCP47A1 digital-to-analog converter with an I2C interface.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mcp47a1.
+
config MCP47FEB02
tristate "MCP47F(E/V)B01/02/04/08/11/12/14/18/21/22/24/28 DAC driver"
depends on I2C
+ select REGMAP_I2C
help
Say yes here if you want to build the driver for the Microchip:
- 8-bit DAC:
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 2a80bbf4e80a..992f8930f95c 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_AD5449) += ad5449.o
obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o
obj-$(CONFIG_AD5592R) += ad5592r.o
obj-$(CONFIG_AD5593R) += ad5593r.o
+obj-$(CONFIG_AD5706R) += ad5706r.o
obj-$(CONFIG_AD5755) += ad5755.o
obj-$(CONFIG_AD5758) += ad5758.o
obj-$(CONFIG_AD5761) += ad5761.o
@@ -51,8 +52,10 @@ obj-$(CONFIG_MAX517) += max517.o
obj-$(CONFIG_MAX22007) += max22007.o
obj-$(CONFIG_MAX5522) += max5522.o
obj-$(CONFIG_MAX5821) += max5821.o
+obj-$(CONFIG_MCF54415_DAC) += mcf54415_dac.o
obj-$(CONFIG_MCP4725) += mcp4725.o
obj-$(CONFIG_MCP4728) += mcp4728.o
+obj-$(CONFIG_MCP47A1) += mcp47a1.o
obj-$(CONFIG_MCP47FEB02) += mcp47feb02.o
obj-$(CONFIG_MCP4821) += mcp4821.o
obj-$(CONFIG_MCP4922) += mcp4922.o
diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c
index b97b46090d80..06b7f280f61b 100644
--- a/drivers/iio/dac/ad3530r.c
+++ b/drivers/iio/dac/ad3530r.c
@@ -2,6 +2,7 @@
/*
* AD3530R/AD3530 8-channel, 16-bit Voltage Output DAC Driver
* AD3531R/AD3531 4-channel, 16-bit Voltage Output DAC Driver
+ * AD3532R/AD3532 16-channel, 16-bit Voltage Output DAC Driver
*
* Copyright 2025 Analog Devices Inc.
*/
@@ -16,7 +17,6 @@
#include <linux/gpio/consumer.h>
#include <linux/iio/iio.h>
#include <linux/kstrtox.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/property.h>
@@ -39,6 +39,25 @@
#define AD3531R_SW_LDAC_TRIG_A 0xDD
#define AD3531R_INPUT_CH 0xE3
+/* AD3532R/AD3532 bank 0 registers (channels 0-7) */
+#define AD3532R_INTERFACE_CONFIG_A_0 0x1000
+#define AD3532R_OUTPUT_OPERATING_MODE_0 0x1020
+#define AD3532R_OUTPUT_OPERATING_MODE_1 0x1021
+#define AD3532R_OUTPUT_CONTROL_0 0x102A
+#define AD3532R_REFERENCE_CONTROL_0 0x103C
+#define AD3532R_SW_LDAC_TRIG_0 0x10E5
+#define AD3532R_INPUT_CH_0 0x10EB
+
+/* AD3532R/AD3532 bank 1 registers (channels 8-15) */
+#define AD3532R_INTERFACE_CONFIG_A_1 0x3000
+#define AD3532R_OUTPUT_OPERATING_MODE_2 0x3020
+#define AD3532R_OUTPUT_OPERATING_MODE_3 0x3021
+#define AD3532R_OUTPUT_CONTROL_1 0x302A
+#define AD3532R_REFERENCE_CONTROL_1 0x303C
+#define AD3532R_SW_LDAC_TRIG_1 0x30E5
+#define AD3532R_INPUT_CH_1 0x30EB
+#define AD3532R_MAX_REG_ADDR 0x30F9
+
#define AD3530R_SLD_TRIG_A BIT(7)
#define AD3530R_OUTPUT_CONTROL_RANGE BIT(2)
#define AD3530R_REFERENCE_CONTROL_SEL BIT(0)
@@ -50,8 +69,10 @@
#define AD3530R_LDAC_PULSE_US 100
#define AD3530R_DAC_MAX_VAL GENMASK(15, 0)
-#define AD3530R_MAX_CHANNELS 8
+#define AD3530R_CH_PER_REG 4
+#define AD3530R_CH_PER_BANK 8
#define AD3531R_MAX_CHANNELS 4
+#define AD3532R_MAX_CHANNELS 16
enum ad3530r_mode {
AD3530R_NORMAL_OP,
@@ -68,9 +89,16 @@ struct ad3530r_chan {
struct ad3530r_chip_info {
const char *name;
const struct iio_chan_spec *channels;
+ const struct regmap_config *regmap_config;
int (*input_ch_reg)(unsigned int channel);
+ int (*sw_ldac_trig_reg)(unsigned int channel);
+ const unsigned int *interface_config_a;
+ const unsigned int *output_control;
+ const unsigned int *reference_control;
+ const unsigned int *op_mode;
unsigned int num_channels;
- unsigned int sw_ldac_trig_reg;
+ unsigned int num_banks;
+ unsigned int num_op_mode_regs;
bool internal_ref_support;
};
@@ -78,7 +106,7 @@ struct ad3530r_state {
struct regmap *regmap;
/* lock to protect against multiple access to the device and shared data */
struct mutex lock;
- struct ad3530r_chan chan[AD3530R_MAX_CHANNELS];
+ struct ad3530r_chan chan[AD3532R_MAX_CHANNELS];
const struct ad3530r_chip_info *chip_info;
struct gpio_desc *ldac_gpio;
int vref_mV;
@@ -99,12 +127,32 @@ static int ad3531r_input_ch_reg(unsigned int channel)
return 2 * channel + AD3531R_INPUT_CH;
}
+static int ad3532r_input_ch_reg(unsigned int channel)
+{
+ unsigned int bank = channel / AD3530R_CH_PER_BANK;
+ unsigned int local_ch = channel % AD3530R_CH_PER_BANK;
+
+ return 2 * local_ch + (bank ? AD3532R_INPUT_CH_1 : AD3532R_INPUT_CH_0);
+}
+
static const char * const ad3530r_powerdown_modes[] = {
"1kohm_to_gnd",
"7.7kohm_to_gnd",
"32kohm_to_gnd",
};
+static const char * const ad3531r_powerdown_modes[] = {
+ "500ohm_to_gnd",
+ "3.85kohm_to_gnd",
+ "16kohm_to_gnd",
+};
+
+static const char * const ad3532r_powerdown_modes[] = {
+ "1kohm_to_gnd",
+ "10kohm_to_gnd",
+ "three_state",
+};
+
static int ad3530r_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
@@ -133,6 +181,20 @@ static const struct iio_enum ad3530r_powerdown_mode_enum = {
.set = ad3530r_set_powerdown_mode,
};
+static const struct iio_enum ad3531r_powerdown_mode_enum = {
+ .items = ad3531r_powerdown_modes,
+ .num_items = ARRAY_SIZE(ad3531r_powerdown_modes),
+ .get = ad3530r_get_powerdown_mode,
+ .set = ad3530r_set_powerdown_mode,
+};
+
+static const struct iio_enum ad3532r_powerdown_mode_enum = {
+ .items = ad3532r_powerdown_modes,
+ .num_items = ARRAY_SIZE(ad3532r_powerdown_modes),
+ .get = ad3530r_get_powerdown_mode,
+ .set = ad3530r_set_powerdown_mode,
+};
+
static ssize_t ad3530r_get_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
@@ -177,6 +239,62 @@ static ssize_t ad3530r_set_dac_powerdown(struct iio_dev *indio_dev,
return len;
}
+static ssize_t ad3532r_set_dac_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct ad3530r_state *st = iio_priv(indio_dev);
+ unsigned int bank, local_ch, reg_in_bank, ch_in_reg;
+ unsigned int reg, mask, val;
+ bool powerdown;
+ int ret;
+
+ ret = kstrtobool(buf, &powerdown);
+ if (ret)
+ return ret;
+
+ bank = chan->channel / AD3530R_CH_PER_BANK;
+ local_ch = chan->channel % AD3530R_CH_PER_BANK;
+ reg_in_bank = local_ch / AD3530R_CH_PER_REG;
+ ch_in_reg = local_ch % AD3530R_CH_PER_REG;
+
+ reg = reg_in_bank + (bank ? AD3532R_OUTPUT_OPERATING_MODE_2 :
+ AD3532R_OUTPUT_OPERATING_MODE_0);
+ mask = AD3530R_OP_MODE_CHAN_MSK(ch_in_reg);
+
+ guard(mutex)(&st->lock);
+ if (powerdown) {
+ val = field_prep(mask, st->chan[chan->channel].powerdown_mode);
+ ret = regmap_update_bits(st->regmap, reg, mask, val);
+ } else {
+ ret = regmap_clear_bits(st->regmap, reg, mask);
+ }
+ if (ret)
+ return ret;
+
+ st->chan[chan->channel].powerdown = powerdown;
+
+ return len;
+}
+
+static int ad3530r_trigger_sw_ldac_reg(unsigned int channel)
+{
+ return AD3530R_SW_LDAC_TRIG_A;
+}
+
+static int ad3531r_trigger_sw_ldac_reg(unsigned int channel)
+{
+ return AD3531R_SW_LDAC_TRIG_A;
+}
+
+static int ad3532r_trigger_sw_ldac_reg(unsigned int channel)
+{
+ unsigned int bank = channel / AD3530R_CH_PER_BANK;
+
+ return bank ? AD3532R_SW_LDAC_TRIG_1 : AD3532R_SW_LDAC_TRIG_0;
+}
+
static int ad3530r_trigger_hw_ldac(struct gpio_desc *ldac_gpio)
{
gpiod_set_value_cansleep(ldac_gpio, 1);
@@ -202,7 +320,7 @@ static int ad3530r_dac_write(struct ad3530r_state *st, unsigned int chan,
if (st->ldac_gpio)
return ad3530r_trigger_hw_ldac(st->ldac_gpio);
- return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg,
+ return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg(chan),
AD3530R_SLD_TRIG_A);
}
@@ -276,7 +394,33 @@ static const struct iio_chan_spec_ext_info ad3530r_ext_info[] = {
{ }
};
-#define AD3530R_CHAN(_chan) \
+static const struct iio_chan_spec_ext_info ad3531r_ext_info[] = {
+ {
+ .name = "powerdown",
+ .shared = IIO_SEPARATE,
+ .read = ad3530r_get_dac_powerdown,
+ .write = ad3530r_set_dac_powerdown,
+ },
+ IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad3531r_powerdown_mode_enum),
+ IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,
+ &ad3531r_powerdown_mode_enum),
+ { }
+};
+
+static const struct iio_chan_spec_ext_info ad3532r_ext_info[] = {
+ {
+ .name = "powerdown",
+ .shared = IIO_SEPARATE,
+ .read = ad3530r_get_dac_powerdown,
+ .write = ad3532r_set_dac_powerdown,
+ },
+ IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad3532r_powerdown_mode_enum),
+ IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,
+ &ad3532r_powerdown_mode_enum),
+ { }
+};
+
+#define AD3530R_CHAN(_chan, _ext_info) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
@@ -284,69 +428,236 @@ static const struct iio_chan_spec_ext_info ad3530r_ext_info[] = {
.output = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
- .ext_info = ad3530r_ext_info, \
+ .ext_info = _ext_info, \
}
static const struct iio_chan_spec ad3530r_channels[] = {
- AD3530R_CHAN(0),
- AD3530R_CHAN(1),
- AD3530R_CHAN(2),
- AD3530R_CHAN(3),
- AD3530R_CHAN(4),
- AD3530R_CHAN(5),
- AD3530R_CHAN(6),
- AD3530R_CHAN(7),
+ AD3530R_CHAN(0, ad3530r_ext_info),
+ AD3530R_CHAN(1, ad3530r_ext_info),
+ AD3530R_CHAN(2, ad3530r_ext_info),
+ AD3530R_CHAN(3, ad3530r_ext_info),
+ AD3530R_CHAN(4, ad3530r_ext_info),
+ AD3530R_CHAN(5, ad3530r_ext_info),
+ AD3530R_CHAN(6, ad3530r_ext_info),
+ AD3530R_CHAN(7, ad3530r_ext_info),
};
static const struct iio_chan_spec ad3531r_channels[] = {
- AD3530R_CHAN(0),
- AD3530R_CHAN(1),
- AD3530R_CHAN(2),
- AD3530R_CHAN(3),
+ AD3530R_CHAN(0, ad3531r_ext_info),
+ AD3530R_CHAN(1, ad3531r_ext_info),
+ AD3530R_CHAN(2, ad3531r_ext_info),
+ AD3530R_CHAN(3, ad3531r_ext_info),
+};
+
+static const struct iio_chan_spec ad3532r_channels[] = {
+ AD3530R_CHAN(0, ad3532r_ext_info),
+ AD3530R_CHAN(1, ad3532r_ext_info),
+ AD3530R_CHAN(2, ad3532r_ext_info),
+ AD3530R_CHAN(3, ad3532r_ext_info),
+ AD3530R_CHAN(4, ad3532r_ext_info),
+ AD3530R_CHAN(5, ad3532r_ext_info),
+ AD3530R_CHAN(6, ad3532r_ext_info),
+ AD3530R_CHAN(7, ad3532r_ext_info),
+ AD3530R_CHAN(8, ad3532r_ext_info),
+ AD3530R_CHAN(9, ad3532r_ext_info),
+ AD3530R_CHAN(10, ad3532r_ext_info),
+ AD3530R_CHAN(11, ad3532r_ext_info),
+ AD3530R_CHAN(12, ad3532r_ext_info),
+ AD3530R_CHAN(13, ad3532r_ext_info),
+ AD3530R_CHAN(14, ad3532r_ext_info),
+ AD3530R_CHAN(15, ad3532r_ext_info),
+};
+
+static const unsigned int ad3530r_if_config[] = {
+ AD3530R_INTERFACE_CONFIG_A,
+};
+
+static const unsigned int ad3530r_out_ctrl[] = {
+ AD3530R_OUTPUT_CONTROL_0,
+};
+
+static const unsigned int ad3530r_ref_ctrl[] = {
+ AD3530R_REFERENCE_CONTROL_0,
+};
+
+static const unsigned int ad3530r_op_mode[] = {
+ AD3530R_OUTPUT_OPERATING_MODE_0,
+ AD3530R_OUTPUT_OPERATING_MODE_1,
+};
+
+static const unsigned int ad3531r_op_mode[] = {
+ AD3530R_OUTPUT_OPERATING_MODE_0,
+};
+
+static const unsigned int ad3532r_if_config[] = {
+ AD3532R_INTERFACE_CONFIG_A_0,
+ AD3532R_INTERFACE_CONFIG_A_1,
+};
+
+static const unsigned int ad3532r_out_ctrl[] = {
+ AD3532R_OUTPUT_CONTROL_0,
+ AD3532R_OUTPUT_CONTROL_1,
+};
+
+static const unsigned int ad3532r_ref_ctrl[] = {
+ AD3532R_REFERENCE_CONTROL_0,
+ AD3532R_REFERENCE_CONTROL_1,
+};
+
+static const unsigned int ad3532r_op_mode[] = {
+ AD3532R_OUTPUT_OPERATING_MODE_0,
+ AD3532R_OUTPUT_OPERATING_MODE_1,
+ AD3532R_OUTPUT_OPERATING_MODE_2,
+ AD3532R_OUTPUT_OPERATING_MODE_3,
+};
+
+static const struct regmap_config ad3530r_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = AD3530R_MAX_REG_ADDR,
+};
+
+static const struct regmap_config ad3532r_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = AD3532R_MAX_REG_ADDR,
};
static const struct ad3530r_chip_info ad3530_chip = {
.name = "ad3530",
.channels = ad3530r_channels,
+ .regmap_config = &ad3530r_regmap_config,
.num_channels = ARRAY_SIZE(ad3530r_channels),
- .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A,
+ .sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg,
.input_ch_reg = ad3530r_input_ch_reg,
+ .interface_config_a = ad3530r_if_config,
+ .output_control = ad3530r_out_ctrl,
+ .reference_control = ad3530r_ref_ctrl,
+ .op_mode = ad3530r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3530r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3530r_op_mode),
.internal_ref_support = false,
};
static const struct ad3530r_chip_info ad3530r_chip = {
.name = "ad3530r",
.channels = ad3530r_channels,
+ .regmap_config = &ad3530r_regmap_config,
.num_channels = ARRAY_SIZE(ad3530r_channels),
- .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A,
+ .sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg,
.input_ch_reg = ad3530r_input_ch_reg,
+ .interface_config_a = ad3530r_if_config,
+ .output_control = ad3530r_out_ctrl,
+ .reference_control = ad3530r_ref_ctrl,
+ .op_mode = ad3530r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3530r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3530r_op_mode),
.internal_ref_support = true,
};
static const struct ad3530r_chip_info ad3531_chip = {
.name = "ad3531",
.channels = ad3531r_channels,
+ .regmap_config = &ad3530r_regmap_config,
.num_channels = ARRAY_SIZE(ad3531r_channels),
- .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A,
+ .sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg,
.input_ch_reg = ad3531r_input_ch_reg,
+ .interface_config_a = ad3530r_if_config,
+ .output_control = ad3530r_out_ctrl,
+ .reference_control = ad3530r_ref_ctrl,
+ .op_mode = ad3531r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3530r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3531r_op_mode),
.internal_ref_support = false,
};
static const struct ad3530r_chip_info ad3531r_chip = {
.name = "ad3531r",
.channels = ad3531r_channels,
+ .regmap_config = &ad3530r_regmap_config,
.num_channels = ARRAY_SIZE(ad3531r_channels),
- .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A,
+ .sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg,
.input_ch_reg = ad3531r_input_ch_reg,
+ .interface_config_a = ad3530r_if_config,
+ .output_control = ad3530r_out_ctrl,
+ .reference_control = ad3530r_ref_ctrl,
+ .op_mode = ad3531r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3530r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3531r_op_mode),
.internal_ref_support = true,
};
+static const struct ad3530r_chip_info ad3532_chip = {
+ .name = "ad3532",
+ .channels = ad3532r_channels,
+ .regmap_config = &ad3532r_regmap_config,
+ .num_channels = ARRAY_SIZE(ad3532r_channels),
+ .sw_ldac_trig_reg = ad3532r_trigger_sw_ldac_reg,
+ .input_ch_reg = ad3532r_input_ch_reg,
+ .interface_config_a = ad3532r_if_config,
+ .output_control = ad3532r_out_ctrl,
+ .reference_control = ad3532r_ref_ctrl,
+ .op_mode = ad3532r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3532r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3532r_op_mode),
+ .internal_ref_support = false,
+};
+
+static const struct ad3530r_chip_info ad3532r_chip = {
+ .name = "ad3532r",
+ .channels = ad3532r_channels,
+ .regmap_config = &ad3532r_regmap_config,
+ .num_channels = ARRAY_SIZE(ad3532r_channels),
+ .sw_ldac_trig_reg = ad3532r_trigger_sw_ldac_reg,
+ .input_ch_reg = ad3532r_input_ch_reg,
+ .interface_config_a = ad3532r_if_config,
+ .output_control = ad3532r_out_ctrl,
+ .reference_control = ad3532r_ref_ctrl,
+ .op_mode = ad3532r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3532r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3532r_op_mode),
+ .internal_ref_support = true,
+};
+
+static int ad3530r_set_reg_bank_bits(const struct ad3530r_state *st,
+ const unsigned int *regs,
+ unsigned int num_regs,
+ unsigned int mask)
+{
+ int ret;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ ret = regmap_set_bits(st->regmap, regs[i], mask);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad3530r_write_reg_banks(const struct ad3530r_state *st,
+ const unsigned int *regs,
+ unsigned int num_regs,
+ unsigned int val)
+{
+ int ret;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ ret = regmap_write(st->regmap, regs[i], val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
{
+ const struct ad3530r_chip_info *chip_info = st->chip_info;
struct device *dev = regmap_get_device(st->regmap);
struct gpio_desc *reset_gpio;
- int i, ret;
u8 range_multiplier, val;
+ int ret;
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpio))
@@ -359,8 +670,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
gpiod_set_value_cansleep(reset_gpio, 0);
} else {
/* Perform software reset */
- ret = regmap_update_bits(st->regmap, AD3530R_INTERFACE_CONFIG_A,
- AD3530R_SW_RESET, AD3530R_SW_RESET);
+ ret = ad3530r_set_reg_bank_bits(st, chip_info->interface_config_a,
+ chip_info->num_banks,
+ AD3530R_SW_RESET);
if (ret)
return ret;
}
@@ -369,8 +681,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
range_multiplier = 1;
if (device_property_read_bool(dev, "adi,range-double")) {
- ret = regmap_set_bits(st->regmap, AD3530R_OUTPUT_CONTROL_0,
- AD3530R_OUTPUT_CONTROL_RANGE);
+ ret = ad3530r_set_reg_bank_bits(st, chip_info->output_control,
+ chip_info->num_banks,
+ AD3530R_OUTPUT_CONTROL_RANGE);
if (ret)
return ret;
@@ -380,8 +693,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
if (external_vref_uV) {
st->vref_mV = range_multiplier * external_vref_uV / MILLI;
} else {
- ret = regmap_set_bits(st->regmap, AD3530R_REFERENCE_CONTROL_0,
- AD3530R_REFERENCE_CONTROL_SEL);
+ ret = ad3530r_set_reg_bank_bits(st, chip_info->reference_control,
+ chip_info->num_banks,
+ AD3530R_REFERENCE_CONTROL_SEL);
if (ret)
return ret;
@@ -394,18 +708,12 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(2), AD3530R_NORMAL_OP) |
FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(3), AD3530R_NORMAL_OP);
- ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_0, val);
+ ret = ad3530r_write_reg_banks(st, st->chip_info->op_mode,
+ st->chip_info->num_op_mode_regs, val);
if (ret)
return ret;
- if (st->chip_info->num_channels > 4) {
- ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_1,
- val);
- if (ret)
- return ret;
- }
-
- for (i = 0; i < st->chip_info->num_channels; i++)
+ for (unsigned int i = 0; i < st->chip_info->num_channels; i++)
st->chan[i].powerdown_mode = AD3530R_POWERDOWN_32K;
st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_LOW);
@@ -416,12 +724,6 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
return 0;
}
-static const struct regmap_config ad3530r_regmap_config = {
- .reg_bits = 16,
- .val_bits = 8,
- .max_register = AD3530R_MAX_REG_ADDR,
-};
-
static const struct iio_info ad3530r_info = {
.read_raw = ad3530r_read_raw,
.write_raw = ad3530r_write_raw,
@@ -442,7 +744,11 @@ static int ad3530r_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
- st->regmap = devm_regmap_init_spi(spi, &ad3530r_regmap_config);
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return -ENODEV;
+
+ st->regmap = devm_regmap_init_spi(spi, st->chip_info->regmap_config);
if (IS_ERR(st->regmap))
return dev_err_probe(dev, PTR_ERR(st->regmap),
"Failed to init regmap");
@@ -451,10 +757,6 @@ static int ad3530r_probe(struct spi_device *spi)
if (ret)
return ret;
- st->chip_info = spi_get_device_match_data(spi);
- if (!st->chip_info)
- return -ENODEV;
-
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators),
regulators);
if (ret)
@@ -484,10 +786,12 @@ static int ad3530r_probe(struct spi_device *spi)
}
static const struct spi_device_id ad3530r_id[] = {
- { "ad3530", (kernel_ulong_t)&ad3530_chip },
- { "ad3530r", (kernel_ulong_t)&ad3530r_chip },
- { "ad3531", (kernel_ulong_t)&ad3531_chip },
- { "ad3531r", (kernel_ulong_t)&ad3531r_chip },
+ { .name = "ad3530", .driver_data = (kernel_ulong_t)&ad3530_chip },
+ { .name = "ad3530r", .driver_data = (kernel_ulong_t)&ad3530r_chip },
+ { .name = "ad3531", .driver_data = (kernel_ulong_t)&ad3531_chip },
+ { .name = "ad3531r", .driver_data = (kernel_ulong_t)&ad3531r_chip },
+ { .name = "ad3532", .driver_data = (kernel_ulong_t)&ad3532_chip },
+ { .name = "ad3532r", .driver_data = (kernel_ulong_t)&ad3532r_chip },
{ }
};
MODULE_DEVICE_TABLE(spi, ad3530r_id);
@@ -497,6 +801,8 @@ static const struct of_device_id ad3530r_of_match[] = {
{ .compatible = "adi,ad3530r", .data = &ad3530r_chip },
{ .compatible = "adi,ad3531", .data = &ad3531_chip },
{ .compatible = "adi,ad3531r", .data = &ad3531r_chip },
+ { .compatible = "adi,ad3532", .data = &ad3532_chip },
+ { .compatible = "adi,ad3532r", .data = &ad3532r_chip },
{ }
};
MODULE_DEVICE_TABLE(of, ad3530r_of_match);
diff --git a/drivers/iio/dac/ad3552r-hs.c b/drivers/iio/dac/ad3552r-hs.c
index a9578afa7015..f865843aa439 100644
--- a/drivers/iio/dac/ad3552r-hs.c
+++ b/drivers/iio/dac/ad3552r-hs.c
@@ -12,7 +12,6 @@
#include <linux/gpio/consumer.h>
#include <linux/iio/backend.h>
#include <linux/iio/buffer.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/units.h>
@@ -549,7 +548,7 @@ static ssize_t ad3552r_hs_write_data_source(struct file *f,
guard(mutex)(&st->lock);
- if (count >= sizeof(buf))
+ if (*ppos != 0 || count >= sizeof(buf))
return -ENOSPC;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf,
@@ -591,7 +590,7 @@ static ssize_t ad3552r_hs_show_data_source_avail(struct file *f,
int i;
for (i = 0; i < ARRAY_SIZE(dbgfs_attr_source); i++) {
- len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
+ len += scnprintf(buf + len, sizeof(buf) - len, "%s ",
dbgfs_attr_source[i]);
}
buf[len - 1] = '\n';
diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c
index 93c33bc3e1be..16db94fef9d4 100644
--- a/drivers/iio/dac/ad3552r.c
+++ b/drivers/iio/dac/ad3552r.c
@@ -167,8 +167,7 @@ static int ad3552r_read_raw(struct iio_dev *indio_dev,
mutex_unlock(&dac->lock);
if (err < 0)
return err;
- *val = !((tmp_val & AD3552R_MASK_CH_DAC_POWERDOWN(ch)) >>
- __ffs(AD3552R_MASK_CH_DAC_POWERDOWN(ch)));
+ *val = !field_get(AD3552R_MASK_CH_DAC_POWERDOWN(ch), tmp_val);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = dac->ch_data[ch].scale_int;
@@ -629,7 +628,9 @@ static int ad3552r_probe(struct spi_device *spi)
if (!dac->model_data)
return -EINVAL;
- mutex_init(&dac->lock);
+ err = devm_mutex_init(&spi->dev, &dac->lock);
+ if (err)
+ return err;
err = ad3552r_init(dac);
if (err)
diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c
index 84be5174babd..298f3a703571 100644
--- a/drivers/iio/dac/ad5064.c
+++ b/drivers/iio/dac/ad5064.c
@@ -920,22 +920,22 @@ static int ad5064_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id ad5064_spi_ids[] = {
- {"ad5024", ID_AD5024},
- {"ad5025", ID_AD5025},
- {"ad5044", ID_AD5044},
- {"ad5045", ID_AD5045},
- {"ad5064", ID_AD5064},
- {"ad5064-1", ID_AD5064_1},
- {"ad5065", ID_AD5065},
- {"ad5628-1", ID_AD5628_1},
- {"ad5628-2", ID_AD5628_2},
- {"ad5648-1", ID_AD5648_1},
- {"ad5648-2", ID_AD5648_2},
- {"ad5666-1", ID_AD5666_1},
- {"ad5666-2", ID_AD5666_2},
- {"ad5668-1", ID_AD5668_1},
- {"ad5668-2", ID_AD5668_2},
- {"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */
+ { .name = "ad5024", .driver_data = ID_AD5024 },
+ { .name = "ad5025", .driver_data = ID_AD5025 },
+ { .name = "ad5044", .driver_data = ID_AD5044 },
+ { .name = "ad5045", .driver_data = ID_AD5045 },
+ { .name = "ad5064", .driver_data = ID_AD5064 },
+ { .name = "ad5064-1", .driver_data = ID_AD5064_1 },
+ { .name = "ad5065", .driver_data = ID_AD5065 },
+ { .name = "ad5628-1", .driver_data = ID_AD5628_1 },
+ { .name = "ad5628-2", .driver_data = ID_AD5628_2 },
+ { .name = "ad5648-1", .driver_data = ID_AD5648_1 },
+ { .name = "ad5648-2", .driver_data = ID_AD5648_2 },
+ { .name = "ad5666-1", .driver_data = ID_AD5666_1 },
+ { .name = "ad5666-2", .driver_data = ID_AD5666_2 },
+ { .name = "ad5668-1", .driver_data = ID_AD5668_1 },
+ { .name = "ad5668-2", .driver_data = ID_AD5668_2 },
+ { .name = "ad5668-3", .driver_data = ID_AD5668_2 }, /* similar enough to ad5668-2 */
{ }
};
MODULE_DEVICE_TABLE(spi, ad5064_spi_ids);
@@ -1001,53 +1001,53 @@ static int ad5064_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id ad5064_i2c_ids[] = {
- {"ad5625", ID_AD5625 },
- {"ad5625r-1v25", ID_AD5625R_1V25 },
- {"ad5625r-2v5", ID_AD5625R_2V5 },
- {"ad5627", ID_AD5627 },
- {"ad5627r-1v25", ID_AD5627R_1V25 },
- {"ad5627r-2v5", ID_AD5627R_2V5 },
- {"ad5629-1", ID_AD5629_1},
- {"ad5629-2", ID_AD5629_2},
- {"ad5629-3", ID_AD5629_2}, /* similar enough to ad5629-2 */
- {"ad5645r-1v25", ID_AD5645R_1V25 },
- {"ad5645r-2v5", ID_AD5645R_2V5 },
- {"ad5665", ID_AD5665 },
- {"ad5665r-1v25", ID_AD5665R_1V25 },
- {"ad5665r-2v5", ID_AD5665R_2V5 },
- {"ad5667", ID_AD5667 },
- {"ad5667r-1v25", ID_AD5667R_1V25 },
- {"ad5667r-2v5", ID_AD5667R_2V5 },
- {"ad5669-1", ID_AD5669_1},
- {"ad5669-2", ID_AD5669_2},
- {"ad5669-3", ID_AD5669_2}, /* similar enough to ad5669-2 */
- {"ltc2606", ID_LTC2606},
- {"ltc2607", ID_LTC2607},
- {"ltc2609", ID_LTC2609},
- {"ltc2616", ID_LTC2616},
- {"ltc2617", ID_LTC2617},
- {"ltc2619", ID_LTC2619},
- {"ltc2626", ID_LTC2626},
- {"ltc2627", ID_LTC2627},
- {"ltc2629", ID_LTC2629},
- {"ltc2631-l12", ID_LTC2631_L12},
- {"ltc2631-h12", ID_LTC2631_H12},
- {"ltc2631-l10", ID_LTC2631_L10},
- {"ltc2631-h10", ID_LTC2631_H10},
- {"ltc2631-l8", ID_LTC2631_L8},
- {"ltc2631-h8", ID_LTC2631_H8},
- {"ltc2633-l12", ID_LTC2633_L12},
- {"ltc2633-h12", ID_LTC2633_H12},
- {"ltc2633-l10", ID_LTC2633_L10},
- {"ltc2633-h10", ID_LTC2633_H10},
- {"ltc2633-l8", ID_LTC2633_L8},
- {"ltc2633-h8", ID_LTC2633_H8},
- {"ltc2635-l12", ID_LTC2635_L12},
- {"ltc2635-h12", ID_LTC2635_H12},
- {"ltc2635-l10", ID_LTC2635_L10},
- {"ltc2635-h10", ID_LTC2635_H10},
- {"ltc2635-l8", ID_LTC2635_L8},
- {"ltc2635-h8", ID_LTC2635_H8},
+ { .name = "ad5625", .driver_data = ID_AD5625 },
+ { .name = "ad5625r-1v25", .driver_data = ID_AD5625R_1V25 },
+ { .name = "ad5625r-2v5", .driver_data = ID_AD5625R_2V5 },
+ { .name = "ad5627", .driver_data = ID_AD5627 },
+ { .name = "ad5627r-1v25", .driver_data = ID_AD5627R_1V25 },
+ { .name = "ad5627r-2v5", .driver_data = ID_AD5627R_2V5 },
+ { .name = "ad5629-1", .driver_data = ID_AD5629_1 },
+ { .name = "ad5629-2", .driver_data = ID_AD5629_2 },
+ { .name = "ad5629-3", .driver_data = ID_AD5629_2 }, /* similar enough to ad5629-2 */
+ { .name = "ad5645r-1v25", .driver_data = ID_AD5645R_1V25 },
+ { .name = "ad5645r-2v5", .driver_data = ID_AD5645R_2V5 },
+ { .name = "ad5665", .driver_data = ID_AD5665 },
+ { .name = "ad5665r-1v25", .driver_data = ID_AD5665R_1V25 },
+ { .name = "ad5665r-2v5", .driver_data = ID_AD5665R_2V5 },
+ { .name = "ad5667", .driver_data = ID_AD5667 },
+ { .name = "ad5667r-1v25", .driver_data = ID_AD5667R_1V25 },
+ { .name = "ad5667r-2v5", .driver_data = ID_AD5667R_2V5 },
+ { .name = "ad5669-1", .driver_data = ID_AD5669_1 },
+ { .name = "ad5669-2", .driver_data = ID_AD5669_2 },
+ { .name = "ad5669-3", .driver_data = ID_AD5669_2 }, /* similar enough to ad5669-2 */
+ { .name = "ltc2606", .driver_data = ID_LTC2606 },
+ { .name = "ltc2607", .driver_data = ID_LTC2607 },
+ { .name = "ltc2609", .driver_data = ID_LTC2609 },
+ { .name = "ltc2616", .driver_data = ID_LTC2616 },
+ { .name = "ltc2617", .driver_data = ID_LTC2617 },
+ { .name = "ltc2619", .driver_data = ID_LTC2619 },
+ { .name = "ltc2626", .driver_data = ID_LTC2626 },
+ { .name = "ltc2627", .driver_data = ID_LTC2627 },
+ { .name = "ltc2629", .driver_data = ID_LTC2629 },
+ { .name = "ltc2631-l12", .driver_data = ID_LTC2631_L12 },
+ { .name = "ltc2631-h12", .driver_data = ID_LTC2631_H12 },
+ { .name = "ltc2631-l10", .driver_data = ID_LTC2631_L10 },
+ { .name = "ltc2631-h10", .driver_data = ID_LTC2631_H10 },
+ { .name = "ltc2631-l8", .driver_data = ID_LTC2631_L8 },
+ { .name = "ltc2631-h8", .driver_data = ID_LTC2631_H8 },
+ { .name = "ltc2633-l12", .driver_data = ID_LTC2633_L12 },
+ { .name = "ltc2633-h12", .driver_data = ID_LTC2633_H12 },
+ { .name = "ltc2633-l10", .driver_data = ID_LTC2633_L10 },
+ { .name = "ltc2633-h10", .driver_data = ID_LTC2633_H10 },
+ { .name = "ltc2633-l8", .driver_data = ID_LTC2633_L8 },
+ { .name = "ltc2633-h8", .driver_data = ID_LTC2633_H8 },
+ { .name = "ltc2635-l12", .driver_data = ID_LTC2635_L12 },
+ { .name = "ltc2635-h12", .driver_data = ID_LTC2635_H12 },
+ { .name = "ltc2635-l10", .driver_data = ID_LTC2635_L10 },
+ { .name = "ltc2635-h10", .driver_data = ID_LTC2635_H10 },
+ { .name = "ltc2635-l8", .driver_data = ID_LTC2635_L8 },
+ { .name = "ltc2635-h8", .driver_data = ID_LTC2635_H8 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids);
diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c
index bd32fa57b1d7..c1553f18a26a 100644
--- a/drivers/iio/dac/ad5360.c
+++ b/drivers/iio/dac/ad5360.c
@@ -206,14 +206,10 @@ static int ad5360_write_unlocked(struct iio_dev *indio_dev,
static int ad5360_write(struct iio_dev *indio_dev, unsigned int cmd,
unsigned int addr, unsigned int val, unsigned int shift)
{
- int ret;
struct ad5360_state *st = iio_priv(indio_dev);
- mutex_lock(&st->lock);
- ret = ad5360_write_unlocked(indio_dev, cmd, addr, val, shift);
- mutex_unlock(&st->lock);
-
- return ret;
+ guard(mutex)(&st->lock);
+ return ad5360_write_unlocked(indio_dev, cmd, addr, val, shift);
}
static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
@@ -232,7 +228,7 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
},
};
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) |
AD5360_ADDR(AD5360_REG_SF_READBACK) |
@@ -240,12 +236,10 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
AD5360_READBACK_ADDR(addr));
ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
- if (ret >= 0)
- ret = be32_to_cpu(st->data[1].d32) & 0xffff;
-
- mutex_unlock(&st->lock);
+ if (ret < 0)
+ return ret;
- return ret;
+ return be32_to_cpu(st->data[1].d32) & 0xffff;
}
static ssize_t ad5360_read_dac_powerdown(struct device *dev,
@@ -262,19 +256,14 @@ static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
unsigned int clr)
{
struct ad5360_state *st = iio_priv(indio_dev);
- int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
st->ctrl |= set;
st->ctrl &= ~clr;
- ret = ad5360_write_unlocked(indio_dev, AD5360_CMD_SPECIAL_FUNCTION,
- AD5360_REG_SF_CTRL, st->ctrl, 0);
-
- mutex_unlock(&st->lock);
-
- return ret;
+ return ad5360_write_unlocked(indio_dev, AD5360_CMD_SPECIAL_FUNCTION,
+ AD5360_REG_SF_CTRL, st->ctrl, 0);
}
static ssize_t ad5360_write_dac_powerdown(struct device *dev,
@@ -534,14 +523,14 @@ static void ad5360_remove(struct spi_device *spi)
}
static const struct spi_device_id ad5360_ids[] = {
- { "ad5360", ID_AD5360 },
- { "ad5361", ID_AD5361 },
- { "ad5362", ID_AD5362 },
- { "ad5363", ID_AD5363 },
- { "ad5370", ID_AD5370 },
- { "ad5371", ID_AD5371 },
- { "ad5372", ID_AD5372 },
- { "ad5373", ID_AD5373 },
+ { .name = "ad5360", .driver_data = ID_AD5360 },
+ { .name = "ad5361", .driver_data = ID_AD5361 },
+ { .name = "ad5362", .driver_data = ID_AD5362 },
+ { .name = "ad5363", .driver_data = ID_AD5363 },
+ { .name = "ad5370", .driver_data = ID_AD5370 },
+ { .name = "ad5371", .driver_data = ID_AD5371 },
+ { .name = "ad5372", .driver_data = ID_AD5372 },
+ { .name = "ad5373", .driver_data = ID_AD5373 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5360_ids);
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c
index 8b813cee7625..4a5ad419f4ea 100644
--- a/drivers/iio/dac/ad5380.c
+++ b/drivers/iio/dac/ad5380.c
@@ -446,22 +446,22 @@ static int ad5380_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id ad5380_spi_ids[] = {
- { "ad5380-3", ID_AD5380_3 },
- { "ad5380-5", ID_AD5380_5 },
- { "ad5381-3", ID_AD5381_3 },
- { "ad5381-5", ID_AD5381_5 },
- { "ad5382-3", ID_AD5382_3 },
- { "ad5382-5", ID_AD5382_5 },
- { "ad5383-3", ID_AD5383_3 },
- { "ad5383-5", ID_AD5383_5 },
- { "ad5384-3", ID_AD5380_3 },
- { "ad5384-5", ID_AD5380_5 },
- { "ad5390-3", ID_AD5390_3 },
- { "ad5390-5", ID_AD5390_5 },
- { "ad5391-3", ID_AD5391_3 },
- { "ad5391-5", ID_AD5391_5 },
- { "ad5392-3", ID_AD5392_3 },
- { "ad5392-5", ID_AD5392_5 },
+ { .name = "ad5380-3", .driver_data = ID_AD5380_3 },
+ { .name = "ad5380-5", .driver_data = ID_AD5380_5 },
+ { .name = "ad5381-3", .driver_data = ID_AD5381_3 },
+ { .name = "ad5381-5", .driver_data = ID_AD5381_5 },
+ { .name = "ad5382-3", .driver_data = ID_AD5382_3 },
+ { .name = "ad5382-5", .driver_data = ID_AD5382_5 },
+ { .name = "ad5383-3", .driver_data = ID_AD5383_3 },
+ { .name = "ad5383-5", .driver_data = ID_AD5383_5 },
+ { .name = "ad5384-3", .driver_data = ID_AD5380_3 },
+ { .name = "ad5384-5", .driver_data = ID_AD5380_5 },
+ { .name = "ad5390-3", .driver_data = ID_AD5390_3 },
+ { .name = "ad5390-5", .driver_data = ID_AD5390_5 },
+ { .name = "ad5391-3", .driver_data = ID_AD5391_3 },
+ { .name = "ad5391-5", .driver_data = ID_AD5391_5 },
+ { .name = "ad5392-3", .driver_data = ID_AD5392_3 },
+ { .name = "ad5392-5", .driver_data = ID_AD5392_5 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5380_spi_ids);
@@ -513,22 +513,22 @@ static int ad5380_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id ad5380_i2c_ids[] = {
- { "ad5380-3", ID_AD5380_3 },
- { "ad5380-5", ID_AD5380_5 },
- { "ad5381-3", ID_AD5381_3 },
- { "ad5381-5", ID_AD5381_5 },
- { "ad5382-3", ID_AD5382_3 },
- { "ad5382-5", ID_AD5382_5 },
- { "ad5383-3", ID_AD5383_3 },
- { "ad5383-5", ID_AD5383_5 },
- { "ad5384-3", ID_AD5380_3 },
- { "ad5384-5", ID_AD5380_5 },
- { "ad5390-3", ID_AD5390_3 },
- { "ad5390-5", ID_AD5390_5 },
- { "ad5391-3", ID_AD5391_3 },
- { "ad5391-5", ID_AD5391_5 },
- { "ad5392-3", ID_AD5392_3 },
- { "ad5392-5", ID_AD5392_5 },
+ { .name = "ad5380-3", .driver_data = ID_AD5380_3 },
+ { .name = "ad5380-5", .driver_data = ID_AD5380_5 },
+ { .name = "ad5381-3", .driver_data = ID_AD5381_3 },
+ { .name = "ad5381-5", .driver_data = ID_AD5381_5 },
+ { .name = "ad5382-3", .driver_data = ID_AD5382_3 },
+ { .name = "ad5382-5", .driver_data = ID_AD5382_5 },
+ { .name = "ad5383-3", .driver_data = ID_AD5383_3 },
+ { .name = "ad5383-5", .driver_data = ID_AD5383_5 },
+ { .name = "ad5384-3", .driver_data = ID_AD5380_3 },
+ { .name = "ad5384-5", .driver_data = ID_AD5380_5 },
+ { .name = "ad5390-3", .driver_data = ID_AD5390_3 },
+ { .name = "ad5390-5", .driver_data = ID_AD5390_5 },
+ { .name = "ad5391-3", .driver_data = ID_AD5391_3 },
+ { .name = "ad5391-5", .driver_data = ID_AD5391_5 },
+ { .name = "ad5392-3", .driver_data = ID_AD5392_3 },
+ { .name = "ad5392-5", .driver_data = ID_AD5392_5 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids);
diff --git a/drivers/iio/dac/ad5446-i2c.c b/drivers/iio/dac/ad5446-i2c.c
index 40fe7e17fce4..286695e240c3 100644
--- a/drivers/iio/dac/ad5446-i2c.c
+++ b/drivers/iio/dac/ad5446-i2c.c
@@ -6,7 +6,6 @@
*/
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <asm/byteorder.h>
@@ -65,12 +64,12 @@ static const struct ad5446_chip_info ad5622_chip_info = {
};
static const struct i2c_device_id ad5446_i2c_ids[] = {
- {"ad5301", (kernel_ulong_t)&ad5602_chip_info},
- {"ad5311", (kernel_ulong_t)&ad5612_chip_info},
- {"ad5321", (kernel_ulong_t)&ad5622_chip_info},
- {"ad5602", (kernel_ulong_t)&ad5602_chip_info},
- {"ad5612", (kernel_ulong_t)&ad5612_chip_info},
- {"ad5622", (kernel_ulong_t)&ad5622_chip_info},
+ { .name = "ad5301", .driver_data = (kernel_ulong_t)&ad5602_chip_info },
+ { .name = "ad5311", .driver_data = (kernel_ulong_t)&ad5612_chip_info },
+ { .name = "ad5321", .driver_data = (kernel_ulong_t)&ad5622_chip_info },
+ { .name = "ad5602", .driver_data = (kernel_ulong_t)&ad5602_chip_info },
+ { .name = "ad5612", .driver_data = (kernel_ulong_t)&ad5612_chip_info },
+ { .name = "ad5622", .driver_data = (kernel_ulong_t)&ad5622_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids);
@@ -84,7 +83,7 @@ static const struct of_device_id ad5446_i2c_of_ids[] = {
{ .compatible = "adi,ad5622", .data = &ad5622_chip_info },
{ }
};
-MODULE_DEVICE_TABLE(OF, ad5446_i2c_of_ids);
+MODULE_DEVICE_TABLE(of, ad5446_i2c_of_ids);
static struct i2c_driver ad5446_i2c_driver = {
.driver = {
diff --git a/drivers/iio/dac/ad5446-spi.c b/drivers/iio/dac/ad5446-spi.c
index e29d77f21482..85bb8829046a 100644
--- a/drivers/iio/dac/ad5446-spi.c
+++ b/drivers/iio/dac/ad5446-spi.c
@@ -6,7 +6,6 @@
*/
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/unaligned.h>
@@ -164,38 +163,38 @@ static const struct ad5446_chip_info ad5662_chip_info = {
};
static const struct spi_device_id ad5446_spi_ids[] = {
- {"ad5300", (kernel_ulong_t)&ad5300_chip_info},
- {"ad5310", (kernel_ulong_t)&ad5310_chip_info},
- {"ad5320", (kernel_ulong_t)&ad5320_chip_info},
- {"ad5444", (kernel_ulong_t)&ad5444_chip_info},
- {"ad5446", (kernel_ulong_t)&ad5446_chip_info},
- {"ad5450", (kernel_ulong_t)&ad5450_chip_info},
- {"ad5451", (kernel_ulong_t)&ad5451_chip_info},
- {"ad5452", (kernel_ulong_t)&ad5444_chip_info}, /* ad5452 is compatible to the ad5444 */
- {"ad5453", (kernel_ulong_t)&ad5446_chip_info}, /* ad5453 is compatible to the ad5446 */
- {"ad5512a", (kernel_ulong_t)&ad5512a_chip_info},
- {"ad5541a", (kernel_ulong_t)&ad5541a_chip_info},
- {"ad5542", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5542 are compatible */
- {"ad5542a", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5542a are compatible */
- {"ad5543", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5543 are compatible */
- {"ad5553", (kernel_ulong_t)&ad5553_chip_info},
- {"ad5600", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5600 are compatible */
- {"ad5601", (kernel_ulong_t)&ad5601_chip_info},
- {"ad5611", (kernel_ulong_t)&ad5611_chip_info},
- {"ad5621", (kernel_ulong_t)&ad5621_chip_info},
- {"ad5641", (kernel_ulong_t)&ad5641_chip_info},
- {"ad5620-2500", (kernel_ulong_t)&ad5620_2500_chip_info}, /* AD5620/40/60: */
+ { .name = "ad5300", .driver_data = (kernel_ulong_t)&ad5300_chip_info },
+ { .name = "ad5310", .driver_data = (kernel_ulong_t)&ad5310_chip_info },
+ { .name = "ad5320", .driver_data = (kernel_ulong_t)&ad5320_chip_info },
+ { .name = "ad5444", .driver_data = (kernel_ulong_t)&ad5444_chip_info },
+ { .name = "ad5446", .driver_data = (kernel_ulong_t)&ad5446_chip_info },
+ { .name = "ad5450", .driver_data = (kernel_ulong_t)&ad5450_chip_info },
+ { .name = "ad5451", .driver_data = (kernel_ulong_t)&ad5451_chip_info },
+ { .name = "ad5452", .driver_data = (kernel_ulong_t)&ad5444_chip_info }, /* ad5452 is compatible to the ad5444 */
+ { .name = "ad5453", .driver_data = (kernel_ulong_t)&ad5446_chip_info }, /* ad5453 is compatible to the ad5446 */
+ { .name = "ad5512a", .driver_data = (kernel_ulong_t)&ad5512a_chip_info },
+ { .name = "ad5541a", .driver_data = (kernel_ulong_t)&ad5541a_chip_info },
+ { .name = "ad5542", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5542 are compatible */
+ { .name = "ad5542a", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5542a are compatible */
+ { .name = "ad5543", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5543 are compatible */
+ { .name = "ad5553", .driver_data = (kernel_ulong_t)&ad5553_chip_info },
+ { .name = "ad5600", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5600 are compatible */
+ { .name = "ad5601", .driver_data = (kernel_ulong_t)&ad5601_chip_info },
+ { .name = "ad5611", .driver_data = (kernel_ulong_t)&ad5611_chip_info },
+ { .name = "ad5621", .driver_data = (kernel_ulong_t)&ad5621_chip_info },
+ { .name = "ad5641", .driver_data = (kernel_ulong_t)&ad5641_chip_info },
+ { .name = "ad5620-2500", .driver_data = (kernel_ulong_t)&ad5620_2500_chip_info }, /* AD5620/40/60: */
/* part numbers may look differently */
- {"ad5620-1250", (kernel_ulong_t)&ad5620_1250_chip_info},
- {"ad5640-2500", (kernel_ulong_t)&ad5640_2500_chip_info},
- {"ad5640-1250", (kernel_ulong_t)&ad5640_1250_chip_info},
- {"ad5660-2500", (kernel_ulong_t)&ad5660_2500_chip_info},
- {"ad5660-1250", (kernel_ulong_t)&ad5660_1250_chip_info},
- {"ad5662", (kernel_ulong_t)&ad5662_chip_info},
- {"dac081s101", (kernel_ulong_t)&ad5300_chip_info}, /* compatible Texas Instruments chips */
- {"dac101s101", (kernel_ulong_t)&ad5310_chip_info},
- {"dac121s101", (kernel_ulong_t)&ad5320_chip_info},
- {"dac7512", (kernel_ulong_t)&ad5320_chip_info},
+ { .name = "ad5620-1250", .driver_data = (kernel_ulong_t)&ad5620_1250_chip_info },
+ { .name = "ad5640-2500", .driver_data = (kernel_ulong_t)&ad5640_2500_chip_info },
+ { .name = "ad5640-1250", .driver_data = (kernel_ulong_t)&ad5640_1250_chip_info },
+ { .name = "ad5660-2500", .driver_data = (kernel_ulong_t)&ad5660_2500_chip_info },
+ { .name = "ad5660-1250", .driver_data = (kernel_ulong_t)&ad5660_1250_chip_info },
+ { .name = "ad5662", .driver_data = (kernel_ulong_t)&ad5662_chip_info },
+ { .name = "dac081s101", .driver_data = (kernel_ulong_t)&ad5300_chip_info }, /* compatible Texas Instruments chips */
+ { .name = "dac101s101", .driver_data = (kernel_ulong_t)&ad5310_chip_info },
+ { .name = "dac121s101", .driver_data = (kernel_ulong_t)&ad5320_chip_info },
+ { .name = "dac7512", .driver_data = (kernel_ulong_t)&ad5320_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5446_spi_ids);
diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c
index d8c325260259..19e66bc69676 100644
--- a/drivers/iio/dac/ad5449.c
+++ b/drivers/iio/dac/ad5449.c
@@ -330,13 +330,13 @@ static void ad5449_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id ad5449_spi_ids[] = {
- { "ad5415", ID_AD5449 },
- { "ad5426", ID_AD5426 },
- { "ad5429", ID_AD5429 },
- { "ad5432", ID_AD5432 },
- { "ad5439", ID_AD5439 },
- { "ad5443", ID_AD5443 },
- { "ad5449", ID_AD5449 },
+ { .name = "ad5415", .driver_data = ID_AD5449 },
+ { .name = "ad5426", .driver_data = ID_AD5426 },
+ { .name = "ad5429", .driver_data = ID_AD5429 },
+ { .name = "ad5432", .driver_data = ID_AD5432 },
+ { .name = "ad5439", .driver_data = ID_AD5439 },
+ { .name = "ad5443", .driver_data = ID_AD5443 },
+ { .name = "ad5449", .driver_data = ID_AD5449 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5449_spi_ids);
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index 355bcb6a8ba0..ad1a74678cf2 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -5,21 +5,21 @@
* Copyright 2011 Analog Devices Inc.
*/
-#include <linux/interrupt.h>
-#include <linux/fs.h>
+#include <linux/bitops.h>
#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/spi/spi.h>
#include <linux/sysfs.h>
-#include <linux/regulator/consumer.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
+#include <linux/iio/dac/ad5504.h>
+#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-#include <linux/iio/dac/ad5504.h>
#define AD5504_RES_MASK GENMASK(11, 0)
#define AD5504_CMD_READ BIT(15)
@@ -270,25 +270,26 @@ static const struct iio_chan_spec ad5504_channels[] = {
static int ad5504_probe(struct spi_device *spi)
{
- const struct ad5504_platform_data *pdata = dev_get_platdata(&spi->dev);
+ struct device *dev = &spi->dev;
+ const struct ad5504_platform_data *pdata = dev_get_platdata(dev);
struct iio_dev *indio_dev;
struct ad5504_state *st;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
- ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc");
+ ret = devm_regulator_get_enable_read_voltage(dev, "vcc");
if (ret < 0 && ret != -ENODEV)
return ret;
if (ret == -ENODEV) {
if (pdata->vref_mv)
st->vref_mv = pdata->vref_mv;
else
- dev_warn(&spi->dev, "reference voltage unspecified\n");
+ dev_warn(dev, "reference voltage unspecified\n");
} else {
st->vref_mv = ret / 1000;
}
@@ -304,22 +305,22 @@ static int ad5504_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
if (spi->irq) {
- ret = devm_request_threaded_irq(&spi->dev, spi->irq,
- NULL,
- &ad5504_event_handler,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- spi_get_device_id(st->spi)->name,
- indio_dev);
+ ret = devm_request_threaded_irq(dev, spi->irq,
+ NULL,
+ &ad5504_event_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ spi_get_device_id(st->spi)->name,
+ indio_dev);
if (ret)
return ret;
}
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id ad5504_id[] = {
- {"ad5504", ID_AD5504},
- {"ad5501", ID_AD5501},
+ { .name = "ad5504", .driver_data = ID_AD5504 },
+ { .name = "ad5501", .driver_data = ID_AD5501 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5504_id);
diff --git a/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c
index 92d1b629b85d..88197bc6a70b 100644
--- a/drivers/iio/dac/ad5592r.c
+++ b/drivers/iio/dac/ad5592r.c
@@ -10,7 +10,6 @@
#include <linux/bitops.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#define AD5592R_GPIO_READBACK_EN BIT(10)
diff --git a/drivers/iio/dac/ad5593r.c b/drivers/iio/dac/ad5593r.c
index 9a8525c61173..3e4215f0ca7e 100644
--- a/drivers/iio/dac/ad5593r.c
+++ b/drivers/iio/dac/ad5593r.c
@@ -11,7 +11,6 @@
#include <linux/bitops.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/unaligned.h>
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c
index 13aefe769bad..56aea4b1c167 100644
--- a/drivers/iio/dac/ad5624r_spi.c
+++ b/drivers/iio/dac/ad5624r_spi.c
@@ -260,12 +260,12 @@ static int ad5624r_probe(struct spi_device *spi)
}
static const struct spi_device_id ad5624r_id[] = {
- {"ad5624r3", ID_AD5624R3},
- {"ad5644r3", ID_AD5644R3},
- {"ad5664r3", ID_AD5664R3},
- {"ad5624r5", ID_AD5624R5},
- {"ad5644r5", ID_AD5644R5},
- {"ad5664r5", ID_AD5664R5},
+ { .name = "ad5624r3", .driver_data = ID_AD5624R3 },
+ { .name = "ad5644r3", .driver_data = ID_AD5644R3 },
+ { .name = "ad5664r3", .driver_data = ID_AD5664R3 },
+ { .name = "ad5624r5", .driver_data = ID_AD5624R5 },
+ { .name = "ad5644r5", .driver_data = ID_AD5644R5 },
+ { .name = "ad5664r5", .driver_data = ID_AD5664R5 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5624r_id);
diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c
index df8619e0c092..69cd9753f339 100644
--- a/drivers/iio/dac/ad5686-spi.c
+++ b/drivers/iio/dac/ad5686-spi.c
@@ -1,65 +1,109 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * AD5672R, AD5674R, AD5676, AD5676R, AD5679R,
- * AD5681R, AD5682R, AD5683, AD5683R, AD5684,
- * AD5684R, AD5685R, AD5686, AD5686R
- * Digital to analog converters driver
+ * SPI driver for AD5686 and similar Digital to Analog Converters
*
* Copyright 2018 Analog Devices Inc.
*/
-#include "ad5686.h"
-
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/errno.h>
#include <linux/module.h>
+#include <linux/overflow.h>
#include <linux/spi/spi.h>
+#include <asm/byteorder.h>
+
+#include "ad5686.h"
+
+/**
+ * struct ad5686_spi_data - SPI bus specific data
+ * @msg: SPI message used for transfers
+ * @size: number of transfers currently in the message
+ * @capacity: maximum number of transfers that can be added to the message
+ * @xfers: array of SPI transfers, allocated with the provided capacity
+ */
+struct ad5686_spi_data {
+ struct spi_message msg;
+ unsigned int size;
+ unsigned int capacity;
+ struct spi_transfer xfers[] __counted_by(capacity);
+};
+
static int ad5686_spi_write(struct ad5686_state *st,
u8 cmd, u8 addr, u16 val)
{
- struct spi_device *spi = to_spi_device(st->dev);
- u8 tx_len, *buf;
-
+ struct ad5686_spi_data *bus_data = st->bus_data;
+ struct spi_transfer *xfer;
+
+ if (bus_data->size >= bus_data->capacity)
+ return -E2BIG;
+
+ /*
+ * This function stores spi transfers to a spi message to be sent over
+ * the bus when sync() op is called. If there are already transfers in
+ * the spi message, set the cs_change flag on the last transfer to
+ * ensure that the chip select is deasserted between transfers. If this
+ * is the first transfer, initialize the spi message. Later on, the
+ * current transfer is added to the message with spi_message_add_tail().
+ */
+ if (bus_data->size)
+ bus_data->xfers[bus_data->size - 1].cs_change = 1;
+ else
+ spi_message_init(&bus_data->msg);
+
+ xfer = &bus_data->xfers[bus_data->size];
+ auto buf = &st->data[bus_data->size];
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
- st->data[0].d16 = cpu_to_be16(AD5310_CMD(cmd) |
- val);
- buf = &st->data[0].d8[0];
- tx_len = 2;
+ buf->d16 = cpu_to_be16(FIELD_PREP(AD5310_CMD_MSK, cmd) |
+ FIELD_PREP(AD5310_DATA_MSK, val));
+ *xfer = (struct spi_transfer) {
+ .tx_buf = &buf->d16,
+ .len = sizeof(buf->d16),
+ };
break;
case AD5683_REGMAP:
- st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
- AD5683_DATA(val));
- buf = &st->data[0].d8[1];
- tx_len = 3;
+ buf->d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) |
+ FIELD_PREP(AD5683_DATA_MSK, val));
+ *xfer = (struct spi_transfer) {
+ .tx_buf = &buf->d8[1],
+ .len = sizeof(buf->d8) - 1,
+ };
break;
case AD5686_REGMAP:
- st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
- AD5686_ADDR(addr) |
- val);
- buf = &st->data[0].d8[1];
- tx_len = 3;
+ buf->d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) |
+ FIELD_PREP(AD5686_ADDR_MSK, addr) |
+ FIELD_PREP(AD5686_DATA_MSK, val));
+ *xfer = (struct spi_transfer) {
+ .tx_buf = &buf->d8[1],
+ .len = sizeof(buf->d8) - 1,
+ };
break;
default:
return -EINVAL;
}
- return spi_write(spi, buf, tx_len);
+ spi_message_add_tail(xfer, &bus_data->msg);
+ bus_data->size++;
+
+ return 0;
+}
+
+static int ad5686_spi_sync(struct ad5686_state *st)
+{
+ struct spi_device *spi = to_spi_device(st->dev);
+ struct ad5686_spi_data *bus_data = st->bus_data;
+
+ bus_data->size = 0; /* always reset, even on sync failure */
+ return spi_sync(spi, &bus_data->msg);
}
static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
{
- struct spi_transfer t[] = {
- {
- .tx_buf = &st->data[0].d8[1],
- .len = 3,
- .cs_change = 1,
- }, {
- .tx_buf = &st->data[1].d8[1],
- .rx_buf = &st->data[2].d8[1],
- .len = 3,
- },
- };
struct spi_device *spi = to_spi_device(st->dev);
+ struct ad5686_spi_data *bus_data = st->bus_data;
+ struct spi_transfer *xfer = &bus_data->xfers[0];
u8 cmd = 0;
int ret;
@@ -76,49 +120,120 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
return -EINVAL;
}
- st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
- AD5686_ADDR(addr));
- st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
+ st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) |
+ FIELD_PREP(AD5686_ADDR_MSK, addr));
+ st->data[1].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, AD5686_CMD_NOOP));
- ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t));
- if (ret < 0)
+ xfer[0] = (struct spi_transfer) {
+ .tx_buf = &st->data[0].d8[1],
+ .len = sizeof(st->data[0].d8) - 1,
+ .cs_change = 1,
+ };
+ xfer[1] = (struct spi_transfer) {
+ .tx_buf = &st->data[1].d8[1],
+ .rx_buf = &st->data[2].d8[1],
+ .len = sizeof(st->data[1].d8) - 1,
+ };
+
+ spi_message_init_with_transfers(&bus_data->msg, xfer, 2);
+
+ ret = spi_sync(spi, &bus_data->msg);
+ if (ret)
return ret;
return be32_to_cpu(st->data[2].d32);
}
+static const struct ad5686_bus_ops ad5686_spi_ops = {
+ .write = ad5686_spi_write,
+ .read = ad5686_spi_read,
+ .sync = ad5686_spi_sync,
+};
+
static int ad5686_spi_probe(struct spi_device *spi)
{
- const struct spi_device_id *id = spi_get_device_id(spi);
+ const struct ad5686_chip_info *info;
+ struct ad5686_spi_data *bus_data;
+ struct device *dev = &spi->dev;
+ unsigned int capacity;
+
+ info = spi_get_device_match_data(spi);
+ if (!info)
+ return -ENODATA;
+
+ /* read operation requires at least 2 transfers */
+ capacity = max(info->num_channels, 2);
+ bus_data = devm_kzalloc(dev, struct_size(bus_data, xfers, capacity),
+ GFP_KERNEL);
+ if (!bus_data)
+ return -ENOMEM;
+
+ bus_data->capacity = capacity;
- return ad5686_probe(&spi->dev, id->driver_data, id->name,
- ad5686_spi_write, ad5686_spi_read);
+ return ad5686_probe(dev, info, spi->modalias, &ad5686_spi_ops, bus_data);
}
static const struct spi_device_id ad5686_spi_id[] = {
- {"ad5310r", ID_AD5310R},
- {"ad5672r", ID_AD5672R},
- {"ad5674r", ID_AD5674R},
- {"ad5676", ID_AD5676},
- {"ad5676r", ID_AD5676R},
- {"ad5679r", ID_AD5679R},
- {"ad5681r", ID_AD5681R},
- {"ad5682r", ID_AD5682R},
- {"ad5683", ID_AD5683},
- {"ad5683r", ID_AD5683R},
- {"ad5684", ID_AD5684},
- {"ad5684r", ID_AD5684R},
- {"ad5685", ID_AD5685R}, /* Does not exist */
- {"ad5685r", ID_AD5685R},
- {"ad5686", ID_AD5686},
- {"ad5686r", ID_AD5686R},
+ { .name = "ad5310r", .driver_data = (kernel_ulong_t)&ad5310r_chip_info },
+ { .name = "ad5313r", .driver_data = (kernel_ulong_t)&ad5338r_chip_info },
+ { .name = "ad5317r", .driver_data = (kernel_ulong_t)&ad5317r_chip_info },
+ { .name = "ad5672r", .driver_data = (kernel_ulong_t)&ad5672r_chip_info },
+ { .name = "ad5674", .driver_data = (kernel_ulong_t)&ad5674_chip_info },
+ { .name = "ad5674r", .driver_data = (kernel_ulong_t)&ad5674r_chip_info },
+ { .name = "ad5676", .driver_data = (kernel_ulong_t)&ad5676_chip_info },
+ { .name = "ad5676r", .driver_data = (kernel_ulong_t)&ad5676r_chip_info },
+ { .name = "ad5679", .driver_data = (kernel_ulong_t)&ad5679_chip_info },
+ { .name = "ad5679r", .driver_data = (kernel_ulong_t)&ad5679r_chip_info },
+ { .name = "ad5681r", .driver_data = (kernel_ulong_t)&ad5681r_chip_info },
+ { .name = "ad5682r", .driver_data = (kernel_ulong_t)&ad5682r_chip_info },
+ { .name = "ad5683", .driver_data = (kernel_ulong_t)&ad5683_chip_info },
+ { .name = "ad5683r", .driver_data = (kernel_ulong_t)&ad5683r_chip_info },
+ { .name = "ad5684", .driver_data = (kernel_ulong_t)&ad5684_chip_info },
+ { .name = "ad5684r", .driver_data = (kernel_ulong_t)&ad5684r_chip_info },
+ { .name = "ad5685", .driver_data = (kernel_ulong_t)&ad5685r_chip_info }, /* nonexistent */
+ { .name = "ad5685r", .driver_data = (kernel_ulong_t)&ad5685r_chip_info },
+ { .name = "ad5686", .driver_data = (kernel_ulong_t)&ad5686_chip_info },
+ { .name = "ad5686r", .driver_data = (kernel_ulong_t)&ad5686r_chip_info },
+ { .name = "ad5687", .driver_data = (kernel_ulong_t)&ad5687_chip_info },
+ { .name = "ad5687r", .driver_data = (kernel_ulong_t)&ad5687r_chip_info },
+ { .name = "ad5689", .driver_data = (kernel_ulong_t)&ad5689_chip_info },
+ { .name = "ad5689r", .driver_data = (kernel_ulong_t)&ad5689r_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5686_spi_id);
+static const struct of_device_id ad5686_of_match[] = {
+ { .compatible = "adi,ad5310r", .data = &ad5310r_chip_info },
+ { .compatible = "adi,ad5313r", .data = &ad5338r_chip_info },
+ { .compatible = "adi,ad5317r", .data = &ad5317r_chip_info },
+ { .compatible = "adi,ad5672r", .data = &ad5672r_chip_info },
+ { .compatible = "adi,ad5674", .data = &ad5674_chip_info },
+ { .compatible = "adi,ad5674r", .data = &ad5674r_chip_info },
+ { .compatible = "adi,ad5676", .data = &ad5676_chip_info },
+ { .compatible = "adi,ad5676r", .data = &ad5676r_chip_info },
+ { .compatible = "adi,ad5679", .data = &ad5679_chip_info },
+ { .compatible = "adi,ad5679r", .data = &ad5679r_chip_info },
+ { .compatible = "adi,ad5681r", .data = &ad5681r_chip_info },
+ { .compatible = "adi,ad5682r", .data = &ad5682r_chip_info },
+ { .compatible = "adi,ad5683", .data = &ad5683_chip_info },
+ { .compatible = "adi,ad5683r", .data = &ad5683r_chip_info },
+ { .compatible = "adi,ad5684", .data = &ad5684_chip_info },
+ { .compatible = "adi,ad5684r", .data = &ad5684r_chip_info },
+ { .compatible = "adi,ad5685r", .data = &ad5685r_chip_info },
+ { .compatible = "adi,ad5686", .data = &ad5686_chip_info },
+ { .compatible = "adi,ad5686r", .data = &ad5686r_chip_info },
+ { .compatible = "adi,ad5687", .data = &ad5687_chip_info },
+ { .compatible = "adi,ad5687r", .data = &ad5687r_chip_info },
+ { .compatible = "adi,ad5689", .data = &ad5689_chip_info },
+ { .compatible = "adi,ad5689r", .data = &ad5689r_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad5686_of_match);
+
static struct spi_driver ad5686_spi_driver = {
.driver = {
.name = "ad5686",
+ .of_match_table = ad5686_of_match,
},
.probe = ad5686_spi_probe,
.id_table = ad5686_spi_id,
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 4b18498aa074..0cc1c9c22a28 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -1,21 +1,34 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * AD5686R, AD5685R, AD5684R Digital to analog converters driver
+ * Core driver for AD5686 and similar Digital to Analog Converters
*
* Copyright 2011 Analog Devices Inc.
*/
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/device.h>
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kstrtox.h>
+#include <linux/math64.h>
#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
+#include <linux/property.h>
#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/sysfs.h>
+#include <linux/units.h>
+#include <linux/wordpart.h>
+#include <linux/iio/buffer.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 "ad5686.h"
@@ -25,12 +38,59 @@ static const char * const ad5686_powerdown_modes[] = {
"three_state"
};
+static int ad5310_control_sync(struct ad5686_state *st)
+{
+ unsigned int pd_val = st->pwr_down_mask & st->pwr_down_mode;
+
+ return ad5686_write(st, AD5686_CMD_CONTROL_REG, 0,
+ FIELD_PREP(AD5310_DATA_PD_MSK, pd_val & AD5686_PD_MSK) |
+ FIELD_PREP(AD5310_DATA_REF_MSK, st->use_internal_vref ? 0 : 1) |
+ FIELD_PREP(AD5310_DATA_GAIN_MSK, st->double_scale ? 1 : 0));
+}
+
+static int ad5683_control_sync(struct ad5686_state *st)
+{
+ unsigned int pd_val = st->pwr_down_mask & st->pwr_down_mode;
+
+ return ad5686_write(st, AD5686_CMD_CONTROL_REG, 0,
+ FIELD_PREP(AD5683_DATA_PD_MSK, pd_val & AD5686_PD_MSK) |
+ FIELD_PREP(AD5683_DATA_REF_MSK, st->use_internal_vref ? 0 : 1) |
+ FIELD_PREP(AD5683_DATA_GAIN_MSK, st->double_scale ? 1 : 0));
+}
+
+static inline unsigned int ad5686_pd_mask_shift(const struct iio_chan_spec *chan)
+{
+ if (chan->channel == chan->address)
+ return chan->channel * 2;
+
+ /* one-hot encoding is used in dual/quad channel devices */
+ return __ffs(chan->address) * 2;
+}
+
+static inline void ad5686_pd_field_set(const struct iio_chan_spec *chan,
+ unsigned int *pd, unsigned int val)
+{
+ unsigned int shift = ad5686_pd_mask_shift(chan);
+
+ *pd = (*pd & ~(AD5686_PD_MSK << shift)) | ((val & AD5686_PD_MSK) << shift);
+}
+
+static inline unsigned int ad5686_pd_field_get(const struct iio_chan_spec *chan,
+ unsigned int pd)
+{
+ unsigned int shift = ad5686_pd_mask_shift(chan);
+
+ return (pd >> shift) & AD5686_PD_MSK;
+}
+
static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad5686_state *st = iio_priv(indio_dev);
- return ((st->pwr_down_mode >> (chan->channel * 2)) & 0x3) - 1;
+ guard(mutex)(&st->lock);
+
+ return ad5686_pd_field_get(chan, st->pwr_down_mode) - 1;
}
static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev,
@@ -39,8 +99,8 @@ static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev,
{
struct ad5686_state *st = iio_priv(indio_dev);
- st->pwr_down_mode &= ~(0x3 << (chan->channel * 2));
- st->pwr_down_mode |= ((mode + 1) << (chan->channel * 2));
+ guard(mutex)(&st->lock);
+ ad5686_pd_field_set(chan, &st->pwr_down_mode, mode + 1);
return 0;
}
@@ -57,8 +117,10 @@ static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev,
{
struct ad5686_state *st = iio_priv(indio_dev);
- return sysfs_emit(buf, "%d\n", !!(st->pwr_down_mask &
- (0x3 << (chan->channel * 2))));
+ guard(mutex)(&st->lock);
+
+ return sysfs_emit(buf, "%d\n",
+ !!ad5686_pd_field_get(chan, st->pwr_down_mask));
}
static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
@@ -70,50 +132,50 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
bool readin;
int ret;
struct ad5686_state *st = iio_priv(indio_dev);
- unsigned int val, ref_bit_msk;
- u8 shift, address = 0;
+ unsigned int val;
+ u8 address;
ret = kstrtobool(buf, &readin);
if (ret)
return ret;
+ guard(mutex)(&st->lock);
+
if (readin)
- st->pwr_down_mask |= (0x3 << (chan->channel * 2));
+ ad5686_pd_field_set(chan, &st->pwr_down_mask, AD5686_PD_MSK_PWR_DOWN);
else
- st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
+ ad5686_pd_field_set(chan, &st->pwr_down_mask, AD5686_PD_MSK_PWR_UP);
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
- shift = 9;
- ref_bit_msk = AD5310_REF_BIT_MSK;
+ ret = ad5310_control_sync(st);
+ if (ret)
+ return ret;
break;
case AD5683_REGMAP:
- shift = 13;
- ref_bit_msk = AD5683_REF_BIT_MSK;
+ ret = ad5683_control_sync(st);
+ if (ret)
+ return ret;
break;
case AD5686_REGMAP:
- shift = 0;
- ref_bit_msk = 0;
/* AD5674R/AD5679R have 16 channels and 2 powerdown registers */
- if (chan->channel > 0x7)
+ val = st->pwr_down_mask & st->pwr_down_mode;
+ if (chan->channel > 0x7) {
address = 0x8;
- break;
- case AD5693_REGMAP:
- shift = 13;
- ref_bit_msk = AD5693_REF_BIT_MSK;
+ val = upper_16_bits(val);
+ } else {
+ address = 0x0;
+ val = lower_16_bits(val);
+ }
+ ret = ad5686_write(st, AD5686_CMD_POWERDOWN_DAC, address, val);
+ if (ret)
+ return ret;
break;
default:
return -EINVAL;
}
- val = ((st->pwr_down_mask & st->pwr_down_mode) << shift);
- if (!st->use_internal_vref)
- val |= ref_bit_msk;
-
- ret = st->write(st, AD5686_CMD_POWERDOWN_DAC,
- address, val >> (address * 2));
-
- return ret ? ret : len;
+ return len;
}
static int ad5686_read_raw(struct iio_dev *indio_dev,
@@ -125,20 +187,25 @@ static int ad5686_read_raw(struct iio_dev *indio_dev,
struct ad5686_state *st = iio_priv(indio_dev);
int ret;
+ guard(mutex)(&st->lock);
+
switch (m) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&st->lock);
- ret = st->read(st, chan->address);
- mutex_unlock(&st->lock);
+ ret = ad5686_read(st, chan->address);
if (ret < 0)
return ret;
*val = (ret >> chan->scan_type.shift) &
GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- *val = st->vref_mv;
- *val2 = chan->scan_type.realbits;
- return IIO_VAL_FRACTIONAL_LOG2;
+ if (st->double_scale) {
+ *val = st->scale_avail[2];
+ *val2 = st->scale_avail[3];
+ } else {
+ *val = st->scale_avail[0];
+ *val2 = st->scale_avail[1];
+ }
+ return IIO_VAL_INT_PLUS_NANO;
}
return -EINVAL;
}
@@ -150,30 +217,104 @@ static int ad5686_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct ad5686_state *st = iio_priv(indio_dev);
+ bool double_scale;
int ret;
+ guard(mutex)(&st->lock);
+
switch (mask) {
case IIO_CHAN_INFO_RAW:
- if (val > (1 << chan->scan_type.realbits) || val < 0)
+ if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
- mutex_lock(&st->lock);
- ret = st->write(st,
- AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
- chan->address,
- val << chan->scan_type.shift);
- mutex_unlock(&st->lock);
- break;
+ return ad5686_write(st, AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
+ chan->address, val << chan->scan_type.shift);
+ case IIO_CHAN_INFO_SCALE:
+ if (val == st->scale_avail[0] && val2 == st->scale_avail[1])
+ double_scale = false;
+ else if (val == st->scale_avail[2] && val2 == st->scale_avail[3])
+ double_scale = true;
+ else
+ return -EINVAL;
+
+ if (st->double_scale == double_scale)
+ return 0; /* no change */
+
+ if (st->chip_info->regmap_type == AD5686_REGMAP && !st->gain_gpio)
+ return -EINVAL; /* GAIN pin is board-strapped */
+
+ st->double_scale = double_scale;
+ switch (st->chip_info->regmap_type) {
+ case AD5310_REGMAP:
+ ret = ad5310_control_sync(st);
+ break;
+ case AD5683_REGMAP:
+ ret = ad5683_control_sync(st);
+ break;
+ case AD5686_REGMAP:
+ ret = gpiod_set_value_cansleep(st->gain_gpio,
+ st->double_scale ? 1 : 0);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (ret)
+ st->double_scale = !double_scale; /* revert on failure */
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad5686_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
+}
+
+static int ad5686_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct ad5686_state *st = iio_priv(indio_dev);
- return ret;
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *type = IIO_VAL_INT_PLUS_NANO;
+
+ if (st->chip_info->regmap_type == AD5686_REGMAP && !st->gain_gpio) {
+ /*
+ * GAIN pin is board-strapped, so only the current
+ * scale is available.
+ */
+ *vals = st->double_scale ? &st->scale_avail[2] :
+ &st->scale_avail[0];
+ *length = 2;
+ return IIO_AVAIL_LIST;
+ }
+
+ *vals = st->scale_avail;
+ *length = ARRAY_SIZE(st->scale_avail);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
}
static const struct iio_info ad5686_info = {
.read_raw = ad5686_read_raw,
.write_raw = ad5686_write_raw,
+ .write_raw_get_fmt = ad5686_write_raw_get_fmt,
+ .read_avail = ad5686_read_avail,
};
static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
@@ -195,7 +336,9 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),\
.address = addr, \
+ .scan_index = chan, \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
@@ -205,7 +348,7 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
.ext_info = ad5686_ext_info, \
}
-#define DECLARE_AD5693_CHANNELS(name, bits, _shift) \
+#define DECLARE_AD5683_CHANNELS(name, bits, _shift) \
static const struct iio_chan_spec name[] = { \
AD5868_CHANNEL(0, 0, bits, _shift), \
}
@@ -256,213 +399,295 @@ static const struct iio_chan_spec name[] = { \
AD5868_CHANNEL(15, 15, bits, _shift), \
}
-DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2);
-DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6);
+/* single-channel */
+DECLARE_AD5683_CHANNELS(ad5310r_channels, 10, 2);
+DECLARE_AD5683_CHANNELS(ad5311r_channels, 10, 6);
+DECLARE_AD5683_CHANNELS(ad5681r_channels, 12, 4);
+DECLARE_AD5683_CHANNELS(ad5682r_channels, 14, 2);
+DECLARE_AD5683_CHANNELS(ad5683r_channels, 16, 0);
+
+/* dual-channel */
DECLARE_AD5338_CHANNELS(ad5337r_channels, 8, 8);
DECLARE_AD5338_CHANNELS(ad5338r_channels, 10, 6);
-DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
+DECLARE_AD5338_CHANNELS(ad5687r_channels, 12, 4);
+DECLARE_AD5338_CHANNELS(ad5689r_channels, 16, 0);
+
+/* quad-channel */
+DECLARE_AD5686_CHANNELS(ad5317r_channels, 10, 6);
+DECLARE_AD5686_CHANNELS(ad5684r_channels, 12, 4);
+DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2);
+DECLARE_AD5686_CHANNELS(ad5686r_channels, 16, 0);
+
+/* 8-channel */
+DECLARE_AD5676_CHANNELS(ad5672r_channels, 12, 4);
+DECLARE_AD5676_CHANNELS(ad5676r_channels, 16, 0);
+
+/* 16-channel */
DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4);
-DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0);
DECLARE_AD5679_CHANNELS(ad5679r_channels, 16, 0);
-DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4);
-DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2);
-DECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0);
-DECLARE_AD5693_CHANNELS(ad5693_channels, 16, 0);
-DECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2);
-DECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4);
-
-static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
- [ID_AD5310R] = {
- .channels = ad5310r_channels,
- .int_vref_mv = 2500,
- .num_channels = 1,
- .regmap_type = AD5310_REGMAP,
- },
- [ID_AD5311R] = {
- .channels = ad5311r_channels,
- .int_vref_mv = 2500,
- .num_channels = 1,
- .regmap_type = AD5693_REGMAP,
- },
- [ID_AD5337R] = {
- .channels = ad5337r_channels,
- .int_vref_mv = 2500,
- .num_channels = 2,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5338R] = {
- .channels = ad5338r_channels,
- .int_vref_mv = 2500,
- .num_channels = 2,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5671R] = {
- .channels = ad5672_channels,
- .int_vref_mv = 2500,
- .num_channels = 8,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5672R] = {
- .channels = ad5672_channels,
- .int_vref_mv = 2500,
- .num_channels = 8,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5673R] = {
- .channels = ad5674r_channels,
- .int_vref_mv = 2500,
- .num_channels = 16,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5674R] = {
- .channels = ad5674r_channels,
- .int_vref_mv = 2500,
- .num_channels = 16,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5675R] = {
- .channels = ad5676_channels,
- .int_vref_mv = 2500,
- .num_channels = 8,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5676] = {
- .channels = ad5676_channels,
- .num_channels = 8,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5676R] = {
- .channels = ad5676_channels,
- .int_vref_mv = 2500,
- .num_channels = 8,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5677R] = {
- .channels = ad5679r_channels,
- .int_vref_mv = 2500,
- .num_channels = 16,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5679R] = {
- .channels = ad5679r_channels,
- .int_vref_mv = 2500,
- .num_channels = 16,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5681R] = {
- .channels = ad5691r_channels,
- .int_vref_mv = 2500,
- .num_channels = 1,
- .regmap_type = AD5683_REGMAP,
- },
- [ID_AD5682R] = {
- .channels = ad5692r_channels,
- .int_vref_mv = 2500,
- .num_channels = 1,
- .regmap_type = AD5683_REGMAP,
- },
- [ID_AD5683] = {
- .channels = ad5693_channels,
- .num_channels = 1,
- .regmap_type = AD5683_REGMAP,
- },
- [ID_AD5683R] = {
- .channels = ad5693_channels,
- .int_vref_mv = 2500,
- .num_channels = 1,
- .regmap_type = AD5683_REGMAP,
- },
- [ID_AD5684] = {
- .channels = ad5684_channels,
- .num_channels = 4,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5684R] = {
- .channels = ad5684_channels,
- .int_vref_mv = 2500,
- .num_channels = 4,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5685R] = {
- .channels = ad5685r_channels,
- .int_vref_mv = 2500,
- .num_channels = 4,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5686] = {
- .channels = ad5686_channels,
- .num_channels = 4,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5686R] = {
- .channels = ad5686_channels,
- .int_vref_mv = 2500,
- .num_channels = 4,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5691R] = {
- .channels = ad5691r_channels,
- .int_vref_mv = 2500,
- .num_channels = 1,
- .regmap_type = AD5693_REGMAP,
- },
- [ID_AD5692R] = {
- .channels = ad5692r_channels,
- .int_vref_mv = 2500,
- .num_channels = 1,
- .regmap_type = AD5693_REGMAP,
- },
- [ID_AD5693] = {
- .channels = ad5693_channels,
- .num_channels = 1,
- .regmap_type = AD5693_REGMAP,
- },
- [ID_AD5693R] = {
- .channels = ad5693_channels,
- .int_vref_mv = 2500,
- .num_channels = 1,
- .regmap_type = AD5693_REGMAP,
- },
- [ID_AD5694] = {
- .channels = ad5684_channels,
- .num_channels = 4,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5694R] = {
- .channels = ad5684_channels,
- .int_vref_mv = 2500,
- .num_channels = 4,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5695R] = {
- .channels = ad5685r_channels,
- .int_vref_mv = 2500,
- .num_channels = 4,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5696] = {
- .channels = ad5686_channels,
- .num_channels = 4,
- .regmap_type = AD5686_REGMAP,
- },
- [ID_AD5696R] = {
- .channels = ad5686_channels,
- .int_vref_mv = 2500,
- .num_channels = 4,
- .regmap_type = AD5686_REGMAP,
- },
+
+const struct ad5686_chip_info ad5310r_chip_info = {
+ .channels = ad5310r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 1,
+ .regmap_type = AD5310_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5310r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5311r_chip_info = {
+ .channels = ad5311r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 1,
+ .regmap_type = AD5683_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5311r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5681r_chip_info = {
+ .channels = ad5681r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 1,
+ .regmap_type = AD5683_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5681r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5682r_chip_info = {
+ .channels = ad5682r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 1,
+ .regmap_type = AD5683_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5682r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5683_chip_info = {
+ .channels = ad5683r_channels,
+ .num_channels = 1,
+ .regmap_type = AD5683_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5683_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5683r_chip_info = {
+ .channels = ad5683r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 1,
+ .regmap_type = AD5683_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5683r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5337r_chip_info = {
+ .channels = ad5337r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 2,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5337r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5338r_chip_info = {
+ .channels = ad5338r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 2,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5338r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5687_chip_info = {
+ .channels = ad5687r_channels,
+ .num_channels = 2,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5687_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5687r_chip_info = {
+ .channels = ad5687r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 2,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5687r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5689_chip_info = {
+ .channels = ad5689r_channels,
+ .num_channels = 2,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5689_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5689r_chip_info = {
+ .channels = ad5689r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 2,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5689r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5317r_chip_info = {
+ .channels = ad5317r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 4,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5317r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5684_chip_info = {
+ .channels = ad5684r_channels,
+ .num_channels = 4,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5684_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5684r_chip_info = {
+ .channels = ad5684r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 4,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5684r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5685r_chip_info = {
+ .channels = ad5685r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 4,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5685r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5686_chip_info = {
+ .channels = ad5686r_channels,
+ .num_channels = 4,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5686_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5686r_chip_info = {
+ .channels = ad5686r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 4,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5686r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5672r_chip_info = {
+ .channels = ad5672r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 8,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5672r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5676_chip_info = {
+ .channels = ad5676r_channels,
+ .num_channels = 8,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5676_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5676r_chip_info = {
+ .channels = ad5676r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 8,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5676r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5674_chip_info = {
+ .channels = ad5674r_channels,
+ .num_channels = 16,
+ .regmap_type = AD5686_REGMAP,
};
+EXPORT_SYMBOL_NS_GPL(ad5674_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5674r_chip_info = {
+ .channels = ad5674r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 16,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5674r_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5679_chip_info = {
+ .channels = ad5679r_channels,
+ .num_channels = 16,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5679_chip_info, "IIO_AD5686");
+
+const struct ad5686_chip_info ad5679r_chip_info = {
+ .channels = ad5679r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 16,
+ .regmap_type = AD5686_REGMAP,
+};
+EXPORT_SYMBOL_NS_GPL(ad5679r_chip_info, "IIO_AD5686");
+
+static void ad5686_init_scale_avail(struct ad5686_state *st)
+{
+ int realbits = st->chip_info->channels[0].scan_type.realbits;
+ s64 tmp = 2ULL * st->vref_mv * NANO >> realbits;
+
+ st->scale_avail[2] = div_s64_rem(tmp, NANO, &st->scale_avail[3]);
+ st->scale_avail[0] = div_s64_rem(tmp >> 1, NANO, &st->scale_avail[1]);
+}
+
+static void do_ad5686_trigger_handler(struct iio_dev *indio_dev)
+{
+ struct ad5686_state *st = iio_priv(indio_dev);
+ u16 val[AD5686_MAX_CHANNELS] = { };
+ unsigned int scan_count, ch, i;
+ bool async_update;
+ u8 cmd;
+
+ if (iio_pop_from_buffer(indio_dev->buffer, val))
+ return;
+
+ guard(mutex)(&st->lock);
+
+ scan_count = bitmap_weight(indio_dev->active_scan_mask,
+ iio_get_masklength(indio_dev));
+ async_update = st->ldac_gpio && scan_count > 1;
+ if (async_update) {
+ /* use LDAC to update all channels simultaneously */
+ cmd = AD5686_CMD_WRITE_INPUT_N;
+ gpiod_set_value_cansleep(st->ldac_gpio, 0);
+ } else {
+ cmd = AD5686_CMD_WRITE_INPUT_N_UPDATE_N;
+ }
+
+ i = 0;
+ iio_for_each_active_channel(indio_dev, ch) {
+ if (st->ops->write(st, cmd, indio_dev->channels[ch].address, val[i++]))
+ break;
+ }
+
+ /*
+ * If sync() is available, it is called here regardless of write
+ * failure to allow bus implementation to reset. In that case, partial
+ * writes are unlikely as the write operations would just queue up
+ * the transfers.
+ */
+ if (st->ops->sync)
+ st->ops->sync(st);
+
+ if (async_update)
+ gpiod_set_value_cansleep(st->ldac_gpio, 1);
+}
+
+static irqreturn_t ad5686_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+
+ do_ad5686_trigger_handler(indio_dev);
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
int ad5686_probe(struct device *dev,
- enum ad5686_supported_device_ids chip_type,
- const char *name, ad5686_write_func write,
- ad5686_read_func read)
+ const struct ad5686_chip_info *chip_info,
+ const char *name, const struct ad5686_bus_ops *ops,
+ void *bus_data)
{
+ struct reset_control *rstc;
struct ad5686_state *st;
struct iio_dev *indio_dev;
- unsigned int val, ref_bit_msk;
- bool has_external_vref;
- u8 cmd;
int ret, i;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
@@ -472,21 +697,69 @@ int ad5686_probe(struct device *dev,
st = iio_priv(indio_dev);
st->dev = dev;
- st->write = write;
- st->read = read;
+ st->ops = ops;
+ st->bus_data = bus_data;
+ st->chip_info = chip_info;
+
+ rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
+ if (IS_ERR(rstc))
+ return dev_err_probe(dev, PTR_ERR(rstc),
+ "Failed to get reset control\n");
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable vdd supply\n");
- st->chip_info = &ad5686_chip_info_tbl[chip_type];
+ ret = devm_regulator_get_enable(dev, "vlogic");
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable vlogic supply\n");
- ret = devm_regulator_get_enable_read_voltage(dev, "vcc");
+ ret = devm_regulator_get_enable_read_voltage(dev, "vref");
+ if (ret == -ENODEV) /* vcc-supply is deprecated, but supported still */
+ ret = devm_regulator_get_enable_read_voltage(dev, "vcc");
if (ret < 0 && ret != -ENODEV)
- return ret;
+ return dev_err_probe(dev, ret, "failed to read vref voltage\n");
+
+ st->use_internal_vref = ret == -ENODEV;
+ st->vref_mv = st->use_internal_vref ? st->chip_info->int_vref_mv : ret / 1000;
+ if (!st->vref_mv)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid or not provided vref voltage\n");
+
+ /* 4.5us power-up time: Datasheet Table 4: Timing Characteristics */
+ fsleep(5);
+
+ /* 1us >> 30ns reset pulse activation time: Datasheet Table 4 */
+ reset_control_assert(rstc);
+ fsleep(1);
+ reset_control_deassert(rstc);
- has_external_vref = ret != -ENODEV;
- st->vref_mv = has_external_vref ? ret / 1000 : st->chip_info->int_vref_mv;
+ st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH);
+ if (IS_ERR(st->ldac_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->ldac_gpio),
+ "Failed to get LDAC GPIO\n");
+
+ st->double_scale = device_property_read_bool(dev, "adi,range-double");
+ st->gain_gpio = devm_gpiod_get_optional(dev, "gain",
+ st->double_scale ? GPIOD_OUT_HIGH :
+ GPIOD_OUT_LOW);
+ if (IS_ERR(st->gain_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->gain_gpio),
+ "Failed to get GAIN GPIO\n");
+
+ ad5686_init_scale_avail(st);
+
+ /* Initialize masks to all ones */
+ st->pwr_down_mask = ~0;
+ st->pwr_down_mode = ~0;
/* Set all the power down mode for all channels to 1K pulldown */
- for (i = 0; i < st->chip_info->num_channels; i++)
- st->pwr_down_mode |= (0x01 << (i * 2));
+ for (i = 0; i < st->chip_info->num_channels; i++) {
+ ad5686_pd_field_set(&st->chip_info->channels[i],
+ &st->pwr_down_mask, AD5686_PD_MSK_PWR_UP);
+ ad5686_pd_field_set(&st->chip_info->channels[i],
+ &st->pwr_down_mode, AD5686_PD_MODE_1K_TO_GND);
+ }
indio_dev->name = name;
indio_dev->info = &ad5686_info;
@@ -494,35 +767,35 @@ int ad5686_probe(struct device *dev,
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
- mutex_init(&st->lock);
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
- cmd = AD5686_CMD_CONTROL_REG;
- ref_bit_msk = AD5310_REF_BIT_MSK;
- st->use_internal_vref = !has_external_vref;
+ ret = ad5310_control_sync(st);
+ if (ret)
+ return ret;
break;
case AD5683_REGMAP:
- cmd = AD5686_CMD_CONTROL_REG;
- ref_bit_msk = AD5683_REF_BIT_MSK;
- st->use_internal_vref = !has_external_vref;
+ ret = ad5683_control_sync(st);
+ if (ret)
+ return ret;
break;
case AD5686_REGMAP:
- cmd = AD5686_CMD_INTERNAL_REFER_SETUP;
- ref_bit_msk = 0;
- break;
- case AD5693_REGMAP:
- cmd = AD5686_CMD_CONTROL_REG;
- ref_bit_msk = AD5693_REF_BIT_MSK;
- st->use_internal_vref = !has_external_vref;
+ ret = ad5686_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0,
+ st->use_internal_vref ? 0 : AD5686_DATA_REF_MSK);
+ if (ret)
+ return ret;
break;
default:
return -EINVAL;
}
- val = (has_external_vref | ref_bit_msk);
-
- ret = st->write(st, cmd, 0, !!val);
+ ret = devm_iio_triggered_buffer_setup_ext(dev, indio_dev, NULL,
+ &ad5686_trigger_handler,
+ IIO_BUFFER_DIRECTION_OUT,
+ NULL, NULL);
if (ret)
return ret;
diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h
index e7d36bae3e59..482bc70515f7 100644
--- a/drivers/iio/dac/ad5686.h
+++ b/drivers/iio/dac/ad5686.h
@@ -8,22 +8,24 @@
#ifndef __DRIVERS_IIO_DAC_AD5686_H__
#define __DRIVERS_IIO_DAC_AD5686_H__
-#include <linux/types.h>
-#include <linux/cache.h>
+#include <linux/bits.h>
#include <linux/mutex.h>
-#include <linux/kernel.h>
+#include <linux/types.h>
#include <linux/iio/iio.h>
-#define AD5310_CMD(x) ((x) << 12)
+#define AD5310_CMD_MSK GENMASK(15, 12)
+#define AD5310_DATA_MSK GENMASK(11, 0)
-#define AD5683_DATA(x) ((x) << 4)
+#define AD5683_DATA_MSK GENMASK(19, 4)
-#define AD5686_ADDR(x) ((x) << 16)
-#define AD5686_CMD(x) ((x) << 20)
+#define AD5686_CMD_MSK GENMASK(23, 20)
+#define AD5686_ADDR_MSK GENMASK(19, 16)
+#define AD5686_DATA_MSK GENMASK(15, 0)
#define AD5686_ADDR_DAC(chan) (0x1 << (chan))
#define AD5686_ADDR_ALL_DAC 0xF
+#define AD5686_MAX_CHANNELS 16
#define AD5686_CMD_NOOP 0x0
#define AD5686_CMD_WRITE_INPUT_N 0x1
@@ -36,77 +38,56 @@
#define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8
#define AD5686_CMD_READBACK_ENABLE 0x9
-#define AD5686_LDAC_PWRDN_NONE 0x0
-#define AD5686_LDAC_PWRDN_1K 0x1
-#define AD5686_LDAC_PWRDN_100K 0x2
-#define AD5686_LDAC_PWRDN_3STATE 0x3
-
#define AD5686_CMD_CONTROL_REG 0x4
#define AD5686_CMD_READBACK_ENABLE_V2 0x5
-#define AD5310_REF_BIT_MSK BIT(8)
-#define AD5683_REF_BIT_MSK BIT(12)
-#define AD5693_REF_BIT_MSK BIT(12)
+#define AD5310_DATA_GAIN_MSK BIT(7)
+#define AD5310_DATA_REF_MSK BIT(8)
+#define AD5310_DATA_PD_MSK GENMASK(10, 9)
-/**
- * ad5686_supported_device_ids:
- */
-enum ad5686_supported_device_ids {
- ID_AD5310R,
- ID_AD5311R,
- ID_AD5337R,
- ID_AD5338R,
- ID_AD5671R,
- ID_AD5672R,
- ID_AD5673R,
- ID_AD5674R,
- ID_AD5675R,
- ID_AD5676,
- ID_AD5676R,
- ID_AD5677R,
- ID_AD5679R,
- ID_AD5681R,
- ID_AD5682R,
- ID_AD5683,
- ID_AD5683R,
- ID_AD5684,
- ID_AD5684R,
- ID_AD5685R,
- ID_AD5686,
- ID_AD5686R,
- ID_AD5691R,
- ID_AD5692R,
- ID_AD5693,
- ID_AD5693R,
- ID_AD5694,
- ID_AD5694R,
- ID_AD5695R,
- ID_AD5696,
- ID_AD5696R,
-};
+#define AD5683_DATA_GAIN_MSK BIT(11) /* DB15 */
+#define AD5683_DATA_REF_MSK BIT(12) /* DB16 */
+#define AD5683_DATA_PD_MSK GENMASK(14, 13) /* DB18:DB17 */
+
+#define AD5686_DATA_REF_MSK BIT(0)
+
+#define AD5686_PD_MSK GENMASK(1, 0)
+#define AD5686_PD_MODE_1K_TO_GND 0x1
+#define AD5686_PD_MODE_100K_TO_GND 0x2
+#define AD5686_PD_MODE_THREE_STATE 0x3
+
+#define AD5686_PD_MSK_PWR_UP 0x0
+#define AD5686_PD_MSK_PWR_DOWN 0x3
enum ad5686_regmap_type {
AD5310_REGMAP,
AD5683_REGMAP,
AD5686_REGMAP,
- AD5693_REGMAP
};
-struct ad5686_state;
+struct gpio_desc;
-typedef int (*ad5686_write_func)(struct ad5686_state *st,
- u8 cmd, u8 addr, u16 val);
+struct ad5686_state;
-typedef int (*ad5686_read_func)(struct ad5686_state *st, u8 addr);
+/**
+ * struct ad5686_bus_ops - bus specific read/write operations
+ * @read: read a register value at the given address
+ * @write: write a command, address and value to the device
+ * @sync: ensure the completion of the write operation (optional)
+ */
+struct ad5686_bus_ops {
+ int (*read)(struct ad5686_state *st, u8 addr);
+ int (*write)(struct ad5686_state *st, u8 cmd, u8 addr, u16 val);
+ int (*sync)(struct ad5686_state *st);
+};
/**
* struct ad5686_chip_info - chip specific information
- * @int_vref_mv: AD5620/40/60: the internal reference voltage
+ * @int_vref_mv: the internal reference voltage
* @num_channels: number of channels
* @channel: channel specification
* @regmap_type: register map layout variant
*/
-
struct ad5686_chip_info {
u16 int_vref_mv;
unsigned int num_channels;
@@ -114,28 +95,73 @@ struct ad5686_chip_info {
enum ad5686_regmap_type regmap_type;
};
+/* single-channel instances */
+extern const struct ad5686_chip_info ad5310r_chip_info;
+extern const struct ad5686_chip_info ad5311r_chip_info;
+extern const struct ad5686_chip_info ad5681r_chip_info;
+extern const struct ad5686_chip_info ad5682r_chip_info;
+extern const struct ad5686_chip_info ad5683_chip_info;
+extern const struct ad5686_chip_info ad5683r_chip_info;
+
+/* dual-channel instances */
+extern const struct ad5686_chip_info ad5337r_chip_info;
+extern const struct ad5686_chip_info ad5338r_chip_info;
+extern const struct ad5686_chip_info ad5687_chip_info;
+extern const struct ad5686_chip_info ad5687r_chip_info;
+extern const struct ad5686_chip_info ad5689_chip_info;
+extern const struct ad5686_chip_info ad5689r_chip_info;
+
+/* quad-channel instances */
+extern const struct ad5686_chip_info ad5317r_chip_info;
+extern const struct ad5686_chip_info ad5684_chip_info;
+extern const struct ad5686_chip_info ad5684r_chip_info;
+extern const struct ad5686_chip_info ad5685r_chip_info;
+extern const struct ad5686_chip_info ad5686_chip_info;
+extern const struct ad5686_chip_info ad5686r_chip_info;
+
+/* 8-channel instances */
+extern const struct ad5686_chip_info ad5672r_chip_info;
+extern const struct ad5686_chip_info ad5676_chip_info;
+extern const struct ad5686_chip_info ad5676r_chip_info;
+
+/* 16-channel instances */
+extern const struct ad5686_chip_info ad5674_chip_info;
+extern const struct ad5686_chip_info ad5674r_chip_info;
+extern const struct ad5686_chip_info ad5679_chip_info;
+extern const struct ad5686_chip_info ad5679r_chip_info;
+
/**
* struct ad5686_state - driver instance specific data
- * @spi: spi_device
+ * @dev: device instance
* @chip_info: chip model specific constants, available modes etc
- * @vref_mv: actual reference voltage used
+ * @ops: bus specific operations
+ * @ldac_gpio: LDAC pin GPIO descriptor
+ * @gain_gpio: GAIN pin GPIO descriptor
* @pwr_down_mask: power down mask
* @pwr_down_mode: current power down mode
+ * @scale_avail: pre-calculated available scale values
+ * @vref_mv: actual reference voltage used
+ * @double_scale: flag to indicate the gain multiplier is applied
* @use_internal_vref: set to true if the internal reference voltage is used
- * @lock lock to protect the data buffer during regmap ops
- * @data: spi transfer buffers
+ * @lock: lock to protect access to state fields, which includes
+ * the data buffer during regmap ops
+ * @bus_data: bus specific data
+ * @data: transfer buffers
*/
-
struct ad5686_state {
struct device *dev;
const struct ad5686_chip_info *chip_info;
- unsigned short vref_mv;
+ const struct ad5686_bus_ops *ops;
+ struct gpio_desc *ldac_gpio;
+ struct gpio_desc *gain_gpio;
unsigned int pwr_down_mask;
unsigned int pwr_down_mode;
- ad5686_write_func write;
- ad5686_read_func read;
+ int scale_avail[4];
+ unsigned short vref_mv;
+ bool double_scale;
bool use_internal_vref;
struct mutex lock;
+ void *bus_data;
/*
* DMA (thus cache coherency maintenance) may require the
@@ -146,14 +172,29 @@ struct ad5686_state {
__be32 d32;
__be16 d16;
u8 d8[4];
- } data[3] __aligned(IIO_DMA_MINALIGN);
+ } data[AD5686_MAX_CHANNELS] __aligned(IIO_DMA_MINALIGN);
};
int ad5686_probe(struct device *dev,
- enum ad5686_supported_device_ids chip_type,
- const char *name, ad5686_write_func write,
- ad5686_read_func read);
+ const struct ad5686_chip_info *chip_info,
+ const char *name, const struct ad5686_bus_ops *ops,
+ void *bus_data);
+
+static inline int ad5686_write(struct ad5686_state *st, u8 cmd, u8 addr, u16 val)
+{
+ int ret;
+
+ ret = st->ops->write(st, cmd, addr, val);
+ if (ret)
+ return ret;
+
+ return st->ops->sync ? st->ops->sync(st) : 0;
+}
+static inline int ad5686_read(struct ad5686_state *st, u8 addr)
+{
+ return st->ops->read(st, addr);
+}
#endif /* __DRIVERS_IIO_DAC_AD5686_H__ */
diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c
index d3327bca0e07..f91abfcdbada 100644
--- a/drivers/iio/dac/ad5696-i2c.c
+++ b/drivers/iio/dac/ad5696-i2c.c
@@ -1,16 +1,18 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * AD5338R, AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693,
- * AD5693R, AD5694, AD5694R, AD5695R, AD5696, AD5696R
- * Digital to analog converters driver
+ * I2C driver for AD5696 and similar Digital to Analog Converters
*
* Copyright 2018 Analog Devices Inc.
*/
-#include "ad5686.h"
-
-#include <linux/module.h>
+#include <linux/bitfield.h>
+#include <linux/errno.h>
#include <linux/i2c.h>
+#include <linux/module.h>
+
+#include <asm/byteorder.h>
+
+#include "ad5686.h"
static int ad5686_i2c_read(struct ad5686_state *st, u8 addr)
{
@@ -31,9 +33,8 @@ static int ad5686_i2c_read(struct ad5686_state *st, u8 addr)
};
int ret;
- st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP) |
- AD5686_ADDR(addr) |
- 0x00);
+ st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, AD5686_CMD_NOOP) |
+ FIELD_PREP(AD5686_ADDR_MSK, addr));
ret = i2c_transfer(i2c->adapter, msg, 2);
if (ret < 0)
@@ -48,8 +49,9 @@ static int ad5686_i2c_write(struct ad5686_state *st,
struct i2c_client *i2c = to_i2c_client(st->dev);
int ret;
- st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | AD5686_ADDR(addr)
- | val);
+ st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) |
+ FIELD_PREP(AD5686_ADDR_MSK, addr) |
+ FIELD_PREP(AD5686_DATA_MSK, val));
ret = i2c_master_send(i2c, &st->data[0].d8[1], 3);
if (ret < 0)
@@ -58,49 +60,66 @@ static int ad5686_i2c_write(struct ad5686_state *st,
return (ret != 3) ? -EIO : 0;
}
+static const struct ad5686_bus_ops ad5686_i2c_ops = {
+ .write = ad5686_i2c_write,
+ .read = ad5686_i2c_read,
+};
+
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);
+ const struct ad5686_chip_info *info;
+
+ info = i2c_get_match_data(i2c);
+ if (!info)
+ return -ENODATA;
+
+ return ad5686_probe(&i2c->dev, info, i2c->name, &ad5686_i2c_ops, NULL);
}
static const struct i2c_device_id ad5686_i2c_id[] = {
- {"ad5311r", ID_AD5311R},
- {"ad5337r", ID_AD5337R},
- {"ad5338r", ID_AD5338R},
- {"ad5671r", ID_AD5671R},
- {"ad5673r", ID_AD5673R},
- {"ad5675r", ID_AD5675R},
- {"ad5677r", ID_AD5677R},
- {"ad5691r", ID_AD5691R},
- {"ad5692r", ID_AD5692R},
- {"ad5693", ID_AD5693},
- {"ad5693r", ID_AD5693R},
- {"ad5694", ID_AD5694},
- {"ad5694r", ID_AD5694R},
- {"ad5695r", ID_AD5695R},
- {"ad5696", ID_AD5696},
- {"ad5696r", ID_AD5696R},
+ { .name = "ad5311r", .driver_data = (kernel_ulong_t)&ad5311r_chip_info },
+ { .name = "ad5316r", .driver_data = (kernel_ulong_t)&ad5317r_chip_info },
+ { .name = "ad5337r", .driver_data = (kernel_ulong_t)&ad5337r_chip_info },
+ { .name = "ad5338r", .driver_data = (kernel_ulong_t)&ad5338r_chip_info },
+ { .name = "ad5671r", .driver_data = (kernel_ulong_t)&ad5672r_chip_info },
+ { .name = "ad5673r", .driver_data = (kernel_ulong_t)&ad5674r_chip_info },
+ { .name = "ad5675", .driver_data = (kernel_ulong_t)&ad5676_chip_info },
+ { .name = "ad5675r", .driver_data = (kernel_ulong_t)&ad5676r_chip_info },
+ { .name = "ad5677r", .driver_data = (kernel_ulong_t)&ad5679r_chip_info },
+ { .name = "ad5691r", .driver_data = (kernel_ulong_t)&ad5681r_chip_info },
+ { .name = "ad5692r", .driver_data = (kernel_ulong_t)&ad5682r_chip_info },
+ { .name = "ad5693", .driver_data = (kernel_ulong_t)&ad5683_chip_info },
+ { .name = "ad5693r", .driver_data = (kernel_ulong_t)&ad5683r_chip_info },
+ { .name = "ad5694", .driver_data = (kernel_ulong_t)&ad5684_chip_info },
+ { .name = "ad5694r", .driver_data = (kernel_ulong_t)&ad5684r_chip_info },
+ { .name = "ad5695r", .driver_data = (kernel_ulong_t)&ad5685r_chip_info },
+ { .name = "ad5696", .driver_data = (kernel_ulong_t)&ad5686_chip_info },
+ { .name = "ad5696r", .driver_data = (kernel_ulong_t)&ad5686r_chip_info },
+ { .name = "ad5697r", .driver_data = (kernel_ulong_t)&ad5687r_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id);
static const struct of_device_id ad5686_of_match[] = {
- { .compatible = "adi,ad5311r" },
- { .compatible = "adi,ad5337r" },
- { .compatible = "adi,ad5338r" },
- { .compatible = "adi,ad5671r" },
- { .compatible = "adi,ad5675r" },
- { .compatible = "adi,ad5691r" },
- { .compatible = "adi,ad5692r" },
- { .compatible = "adi,ad5693" },
- { .compatible = "adi,ad5693r" },
- { .compatible = "adi,ad5694" },
- { .compatible = "adi,ad5694r" },
- { .compatible = "adi,ad5695r" },
- { .compatible = "adi,ad5696" },
- { .compatible = "adi,ad5696r" },
+ { .compatible = "adi,ad5311r", .data = &ad5311r_chip_info },
+ { .compatible = "adi,ad5316r", .data = &ad5317r_chip_info },
+ { .compatible = "adi,ad5337r", .data = &ad5337r_chip_info },
+ { .compatible = "adi,ad5338r", .data = &ad5338r_chip_info },
+ { .compatible = "adi,ad5671r", .data = &ad5672r_chip_info },
+ { .compatible = "adi,ad5673r", .data = &ad5674r_chip_info },
+ { .compatible = "adi,ad5675", .data = &ad5676_chip_info },
+ { .compatible = "adi,ad5675r", .data = &ad5676r_chip_info },
+ { .compatible = "adi,ad5677r", .data = &ad5679r_chip_info },
+ { .compatible = "adi,ad5691r", .data = &ad5681r_chip_info },
+ { .compatible = "adi,ad5692r", .data = &ad5682r_chip_info },
+ { .compatible = "adi,ad5693", .data = &ad5683_chip_info },
+ { .compatible = "adi,ad5693r", .data = &ad5683r_chip_info },
+ { .compatible = "adi,ad5694", .data = &ad5684_chip_info },
+ { .compatible = "adi,ad5694r", .data = &ad5684r_chip_info },
+ { .compatible = "adi,ad5695r", .data = &ad5685r_chip_info },
+ { .compatible = "adi,ad5696", .data = &ad5686_chip_info },
+ { .compatible = "adi,ad5696r", .data = &ad5686r_chip_info },
+ { .compatible = "adi,ad5697r", .data = &ad5687r_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad5686_of_match);
diff --git a/drivers/iio/dac/ad5706r.c b/drivers/iio/dac/ad5706r.c
new file mode 100644
index 000000000000..06c4860a7eba
--- /dev/null
+++ b/drivers/iio/dac/ad5706r.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AD5706R 16-bit Current Output Digital to Analog Converter
+ *
+ * Copyright 2026 Analog Devices Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+/* SPI frame layout */
+#define AD5706R_RD_MASK BIT(15)
+#define AD5706R_ADDR_MASK GENMASK(11, 0)
+
+/* Registers */
+#define AD5706R_REG_DAC_INPUT_A_CH(x) (0x60 + ((x) * 2))
+#define AD5706R_REG_DAC_DATA_READBACK_CH(x) (0x68 + ((x) * 2))
+
+#define AD5706R_DAC_RESOLUTION 16
+#define AD5706R_DAC_MAX_CODE GENMASK(15, 0)
+#define AD5706R_MULTIBYTE_REG_START 0x14
+#define AD5706R_MULTIBYTE_REG_END 0x71
+#define AD5706R_MAX_REG 0x77
+
+struct ad5706r_state {
+ struct spi_device *spi;
+ struct regmap *regmap;
+
+ u8 tx_buf[4] __aligned(IIO_DMA_MINALIGN);
+ u8 rx_buf[4];
+};
+
+static int ad5706r_reg_len(unsigned int reg)
+{
+ if (reg >= AD5706R_MULTIBYTE_REG_START && reg <= AD5706R_MULTIBYTE_REG_END)
+ return 2;
+
+ return 1;
+}
+
+static int ad5706r_regmap_write(void *context, const void *data, size_t count)
+{
+ struct ad5706r_state *st = context;
+ unsigned int num_bytes;
+ u16 reg, val;
+
+ if (count != 4)
+ return -EINVAL;
+
+ reg = get_unaligned_be16(data);
+ val = get_unaligned_be16(data + 2);
+ num_bytes = ad5706r_reg_len(reg);
+
+ struct spi_transfer xfer = {
+ .tx_buf = st->tx_buf,
+ .len = num_bytes + 2,
+ };
+
+ put_unaligned_be16(reg, &st->tx_buf[0]);
+
+ if (num_bytes == 1)
+ st->tx_buf[2] = (u8)val;
+ else if (num_bytes == 2)
+ put_unaligned_be16(val, &st->tx_buf[2]);
+ else
+ return -EINVAL;
+
+ return spi_sync_transfer(st->spi, &xfer, 1);
+}
+
+static int ad5706r_regmap_read(void *context, const void *reg_buf,
+ size_t reg_size, void *val_buf, size_t val_size)
+{
+ struct ad5706r_state *st = context;
+ unsigned int num_bytes;
+ u16 reg, cmd, val;
+ int ret;
+
+ if (reg_size != 2 || val_size != 2)
+ return -EINVAL;
+
+ reg = get_unaligned_be16(reg_buf);
+ num_bytes = ad5706r_reg_len(reg);
+
+ /* Full duplex, device responds immediately after command */
+ struct spi_transfer xfer = {
+ .tx_buf = st->tx_buf,
+ .rx_buf = st->rx_buf,
+ .len = 2 + num_bytes,
+ };
+
+ cmd = AD5706R_RD_MASK | (reg & AD5706R_ADDR_MASK);
+ put_unaligned_be16(cmd, &st->tx_buf[0]);
+ put_unaligned_be16(0, &st->tx_buf[2]);
+
+ ret = spi_sync_transfer(st->spi, &xfer, 1);
+ if (ret)
+ return ret;
+
+ /* Extract value from response (skip 2-byte command echo) */
+ if (num_bytes == 1)
+ val = st->rx_buf[2];
+ else if (num_bytes == 2)
+ val = get_unaligned_be16(&st->rx_buf[2]);
+ else
+ return -EINVAL;
+
+ put_unaligned_be16(val, val_buf);
+
+ return 0;
+}
+
+static int ad5706r_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ad5706r_state *st = iio_priv(indio_dev);
+ unsigned int reg, reg_val;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ reg = AD5706R_REG_DAC_DATA_READBACK_CH(chan->channel);
+ ret = regmap_read(st->regmap, reg, &reg_val);
+ if (ret)
+ return ret;
+
+ *val = reg_val;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 50;
+ *val2 = AD5706R_DAC_RESOLUTION;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad5706r_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ad5706r_state *st = iio_priv(indio_dev);
+ unsigned int reg;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (val < 0 || val > AD5706R_DAC_MAX_CODE)
+ return -EINVAL;
+
+ reg = AD5706R_REG_DAC_INPUT_A_CH(chan->channel);
+ return regmap_write(st->regmap, reg, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct regmap_bus ad5706r_regmap_bus = {
+ .write = ad5706r_regmap_write,
+ .read = ad5706r_regmap_read,
+ .reg_format_endian_default = REGMAP_ENDIAN_BIG,
+ .val_format_endian_default = REGMAP_ENDIAN_BIG,
+};
+
+static const struct regmap_config ad5706r_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 16,
+ .max_register = AD5706R_MAX_REG,
+};
+
+static const struct iio_info ad5706r_info = {
+ .read_raw = ad5706r_read_raw,
+ .write_raw = ad5706r_write_raw,
+};
+
+#define AD5706R_CHAN(_channel) { \
+ .type = IIO_CURRENT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .output = 1, \
+ .indexed = 1, \
+ .channel = _channel, \
+}
+
+static const struct iio_chan_spec ad5706r_channels[] = {
+ AD5706R_CHAN(0),
+ AD5706R_CHAN(1),
+ AD5706R_CHAN(2),
+ AD5706R_CHAN(3),
+};
+
+static int ad5706r_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct ad5706r_state *st;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+
+ st->regmap = devm_regmap_init(dev, &ad5706r_regmap_bus,
+ st, &ad5706r_regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
+ "Failed to init regmap\n");
+
+ indio_dev->name = "ad5706r";
+ indio_dev->info = &ad5706r_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ad5706r_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad5706r_channels);
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id ad5706r_of_match[] = {
+ { .compatible = "adi,ad5706r" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad5706r_of_match);
+
+static const struct spi_device_id ad5706r_id[] = {
+ { .name = "ad5706r" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad5706r_id);
+
+static struct spi_driver ad5706r_driver = {
+ .driver = {
+ .name = "ad5706r",
+ .of_match_table = ad5706r_of_match,
+ },
+ .probe = ad5706r_probe,
+ .id_table = ad5706r_id,
+};
+module_spi_driver(ad5706r_driver);
+
+MODULE_AUTHOR("Alexis Czezar Torreno <alexisczezar.torreno@analog.com>");
+MODULE_DESCRIPTION("AD5706R 16-bit Current Output DAC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c
index d0e5f35462b1..0828b9909099 100644
--- a/drivers/iio/dac/ad5755.c
+++ b/drivers/iio/dac/ad5755.c
@@ -827,8 +827,9 @@ static int ad5755_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = AD5755_NUM_CHANNELS;
- mutex_init(&st->lock);
-
+ ret = devm_mutex_init(&spi->dev, &st->lock);
+ if (ret)
+ return ret;
pdata = ad5755_parse_fw(&spi->dev);
if (!pdata) {
@@ -848,11 +849,11 @@ static int ad5755_probe(struct spi_device *spi)
}
static const struct spi_device_id ad5755_id[] = {
- { "ad5755", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] },
- { "ad5755-1", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] },
- { "ad5757", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5757] },
- { "ad5735", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5735] },
- { "ad5737", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5737] },
+ { .name = "ad5755", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] },
+ { .name = "ad5755-1", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] },
+ { .name = "ad5757", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5757] },
+ { .name = "ad5735", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5735] },
+ { .name = "ad5737", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5737] },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5755_id);
diff --git a/drivers/iio/dac/ad5758.c b/drivers/iio/dac/ad5758.c
index 4ed4fda76ea9..44efa373cd80 100644
--- a/drivers/iio/dac/ad5758.c
+++ b/drivers/iio/dac/ad5758.c
@@ -10,7 +10,6 @@
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
#include <linux/gpio/consumer.h>
@@ -851,7 +850,9 @@ static int ad5758_probe(struct spi_device *spi)
st->spi = spi;
- mutex_init(&st->lock);
+ ret = devm_mutex_init(&spi->dev, &st->lock);
+ if (ret)
+ return ret;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad5758_info;
@@ -877,7 +878,7 @@ static int ad5758_probe(struct spi_device *spi)
}
static const struct spi_device_id ad5758_id[] = {
- { "ad5758", 0 },
+ { .name = "ad5758" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5758_id);
diff --git a/drivers/iio/dac/ad5761.c b/drivers/iio/dac/ad5761.c
index b5d20f04f070..c49568b943d6 100644
--- a/drivers/iio/dac/ad5761.c
+++ b/drivers/iio/dac/ad5761.c
@@ -342,10 +342,10 @@ static int ad5761_probe(struct spi_device *spi)
}
static const struct spi_device_id ad5761_id[] = {
- {"ad5721", ID_AD5721},
- {"ad5721r", ID_AD5721R},
- {"ad5761", ID_AD5761},
- {"ad5761r", ID_AD5761R},
+ { .name = "ad5721", .driver_data = ID_AD5721 },
+ { .name = "ad5721r", .driver_data = ID_AD5721R },
+ { .name = "ad5761", .driver_data = ID_AD5761 },
+ { .name = "ad5761r", .driver_data = ID_AD5761R },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5761_id);
diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c
index fbbd7105a80c..2be4bee7eb01 100644
--- a/drivers/iio/dac/ad5764.c
+++ b/drivers/iio/dac/ad5764.c
@@ -342,10 +342,10 @@ static void ad5764_remove(struct spi_device *spi)
}
static const struct spi_device_id ad5764_ids[] = {
- { "ad5744", ID_AD5744 },
- { "ad5744r", ID_AD5744R },
- { "ad5764", ID_AD5764 },
- { "ad5764r", ID_AD5764R },
+ { .name = "ad5744", .driver_data = ID_AD5744 },
+ { .name = "ad5744r", .driver_data = ID_AD5744R },
+ { .name = "ad5764", .driver_data = ID_AD5764 },
+ { .name = "ad5764r", .driver_data = ID_AD5764R },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5764_ids);
diff --git a/drivers/iio/dac/ad5766.c b/drivers/iio/dac/ad5766.c
index f6a0a0d84fef..061b43fc0345 100644
--- a/drivers/iio/dac/ad5766.c
+++ b/drivers/iio/dac/ad5766.c
@@ -651,8 +651,8 @@ static const struct of_device_id ad5766_dt_match[] = {
MODULE_DEVICE_TABLE(of, ad5766_dt_match);
static const struct spi_device_id ad5766_spi_ids[] = {
- { "ad5766", ID_AD5766 },
- { "ad5767", ID_AD5767 },
+ { .name = "ad5766", .driver_data = ID_AD5766 },
+ { .name = "ad5767", .driver_data = ID_AD5767 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5766_spi_ids);
diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c
index cd47cb1c685c..bdc48e57013f 100644
--- a/drivers/iio/dac/ad5770r.c
+++ b/drivers/iio/dac/ad5770r.c
@@ -322,7 +322,7 @@ static int ad5770r_read_raw(struct iio_dev *indio_dev,
chan->address,
st->transf_buf, 2);
if (ret)
- return 0;
+ return ret;
buf16 = get_unaligned_le16(st->transf_buf);
*val = buf16 >> 2;
@@ -642,7 +642,7 @@ static const struct of_device_id ad5770r_of_id[] = {
MODULE_DEVICE_TABLE(of, ad5770r_of_id);
static const struct spi_device_id ad5770r_id[] = {
- { "ad5770r", 0 },
+ { .name = "ad5770r" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5770r_id);
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
index ae7297f08398..a5eda135c9bd 100644
--- a/drivers/iio/dac/ad5791.c
+++ b/drivers/iio/dac/ad5791.c
@@ -586,11 +586,11 @@ static const struct of_device_id ad5791_of_match[] = {
MODULE_DEVICE_TABLE(of, ad5791_of_match);
static const struct spi_device_id ad5791_id[] = {
- { "ad5760", (kernel_ulong_t)&ad5760_chip_info },
- { "ad5780", (kernel_ulong_t)&ad5780_chip_info },
- { "ad5781", (kernel_ulong_t)&ad5781_chip_info },
- { "ad5790", (kernel_ulong_t)&ad5790_chip_info },
- { "ad5791", (kernel_ulong_t)&ad5791_chip_info },
+ { .name = "ad5760", .driver_data = (kernel_ulong_t)&ad5760_chip_info },
+ { .name = "ad5780", .driver_data = (kernel_ulong_t)&ad5780_chip_info },
+ { .name = "ad5781", .driver_data = (kernel_ulong_t)&ad5781_chip_info },
+ { .name = "ad5790", .driver_data = (kernel_ulong_t)&ad5790_chip_info },
+ { .name = "ad5791", .driver_data = (kernel_ulong_t)&ad5791_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5791_id);
diff --git a/drivers/iio/dac/ad7293.c b/drivers/iio/dac/ad7293.c
index c3797e40cdd9..33a49813ece0 100644
--- a/drivers/iio/dac/ad7293.c
+++ b/drivers/iio/dac/ad7293.c
@@ -11,7 +11,6 @@
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/iio.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
@@ -776,27 +775,27 @@ static int ad7293_reset(struct ad7293_state *st)
static int ad7293_properties_parse(struct ad7293_state *st)
{
- struct spi_device *spi = st->spi;
+ struct device *dev = &st->spi->dev;
int ret;
- ret = devm_regulator_get_enable(&spi->dev, "avdd");
+ ret = devm_regulator_get_enable(dev, "avdd");
if (ret)
- return dev_err_probe(&spi->dev, ret, "failed to enable AVDD\n");
+ return dev_err_probe(dev, ret, "failed to enable AVDD\n");
- ret = devm_regulator_get_enable(&spi->dev, "vdrive");
+ ret = devm_regulator_get_enable(dev, "vdrive");
if (ret)
- return dev_err_probe(&spi->dev, ret, "failed to enable VDRIVE\n");
+ return dev_err_probe(dev, ret, "failed to enable VDRIVE\n");
- ret = devm_regulator_get_enable_optional(&spi->dev, "vrefin");
+ ret = devm_regulator_get_enable_optional(dev, "vrefin");
if (ret < 0 && ret != -ENODEV)
- return dev_err_probe(&spi->dev, ret, "failed to enable VREFIN\n");
+ return dev_err_probe(dev, ret, "failed to enable VREFIN\n");
st->vrefin_en = ret != -ENODEV;
- st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
+ st->gpio_reset = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(st->gpio_reset))
- return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_reset),
+ return dev_err_probe(dev, PTR_ERR(st->gpio_reset),
"failed to get the reset GPIO\n");
return 0;
@@ -806,7 +805,7 @@ static int ad7293_init(struct ad7293_state *st)
{
int ret;
u16 chip_id;
- struct spi_device *spi = st->spi;
+ struct device *dev = &st->spi->dev;
ret = ad7293_properties_parse(st);
if (ret)
@@ -821,10 +820,8 @@ static int ad7293_init(struct ad7293_state *st)
if (ret)
return ret;
- if (chip_id != AD7293_CHIP_ID) {
- dev_err(&spi->dev, "Invalid Chip ID.\n");
- return -EINVAL;
- }
+ if (chip_id != AD7293_CHIP_ID)
+ return dev_err_probe(dev, -EINVAL, "Invalid Chip ID.\n");
if (!st->vrefin_en)
return __ad7293_spi_update_bits(st, AD7293_REG_GENERAL,
@@ -845,9 +842,10 @@ static int ad7293_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ad7293_state *st;
+ struct device *dev = &spi->dev;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -867,11 +865,11 @@ static int ad7293_probe(struct spi_device *spi)
if (ret)
return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id ad7293_id[] = {
- { "ad7293", 0 },
+ { .name = "ad7293" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7293_id);
diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c
index a88cc639047d..83153e7d7fc8 100644
--- a/drivers/iio/dac/ad7303.c
+++ b/drivers/iio/dac/ad7303.c
@@ -7,7 +7,6 @@
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
@@ -218,7 +217,9 @@ static int ad7303_probe(struct spi_device *spi)
st->spi = spi;
- mutex_init(&st->lock);
+ ret = devm_mutex_init(&spi->dev, &st->lock);
+ if (ret)
+ return ret;
st->vdd_reg = devm_regulator_get(&spi->dev, "Vdd");
if (IS_ERR(st->vdd_reg))
@@ -269,7 +270,7 @@ static const struct of_device_id ad7303_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, ad7303_spi_of_match);
static const struct spi_device_id ad7303_spi_ids[] = {
- { "ad7303", 0 },
+ { .name = "ad7303" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7303_spi_ids);
diff --git a/drivers/iio/dac/ad8460.c b/drivers/iio/dac/ad8460.c
index 6e45686902dd..a2292810e4cf 100644
--- a/drivers/iio/dac/ad8460.c
+++ b/drivers/iio/dac/ad8460.c
@@ -14,7 +14,6 @@
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
@@ -955,3 +954,4 @@ MODULE_AUTHOR("Mariel Tinaco <mariel.tinaco@analog.com");
MODULE_DESCRIPTION("AD8460 DAC driver");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/dac/ad8801.c b/drivers/iio/dac/ad8801.c
index 60e663af1cc1..08d7d74e999e 100644
--- a/drivers/iio/dac/ad8801.c
+++ b/drivers/iio/dac/ad8801.c
@@ -151,8 +151,8 @@ static int ad8801_probe(struct spi_device *spi)
}
static const struct spi_device_id ad8801_ids[] = {
- {"ad8801", ID_AD8801},
- {"ad8803", ID_AD8803},
+ { .name = "ad8801", .driver_data = ID_AD8801 },
+ { .name = "ad8803", .driver_data = ID_AD8803 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad8801_ids);
diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c
index d77b46d83bd4..5263a0c968f5 100644
--- a/drivers/iio/dac/ad9739a.c
+++ b/drivers/iio/dac/ad9739a.c
@@ -14,7 +14,6 @@
#include <linux/gpio/consumer.h>
#include <linux/minmax.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -447,7 +446,7 @@ static const struct of_device_id ad9739a_of_match[] = {
MODULE_DEVICE_TABLE(of, ad9739a_of_match);
static const struct spi_device_id ad9739a_id[] = {
- {"ad9739a"},
+ { .name = "ad9739a" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad9739a_id);
diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
index 9cc895bbe51a..f4f3bc67c68e 100644
--- a/drivers/iio/dac/adi-axi-dac.c
+++ b/drivers/iio/dac/adi-axi-dac.c
@@ -17,7 +17,6 @@
#include <linux/math.h>
#include <linux/math64.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -114,7 +113,6 @@ struct axi_dac_state {
const struct axi_dac_info *info;
u64 dac_clk;
u32 reg_config;
- bool int_tone;
int dac_clk_rate;
};
@@ -869,11 +867,13 @@ static const struct iio_backend_ops axi_ad3552r_ops = {
static const struct iio_backend_info axi_dac_generic = {
.name = "axi-dac",
.ops = &axi_dac_generic_ops,
+ .caps = IIO_BACKEND_CAP_BUFFER | IIO_BACKEND_CAP_ENABLE,
};
static const struct iio_backend_info axi_ad3552r = {
.name = "axi-ad3552r",
.ops = &axi_ad3552r_ops,
+ .caps = IIO_BACKEND_CAP_BUFFER | IIO_BACKEND_CAP_ENABLE,
};
static const struct regmap_config axi_dac_regmap_config = {
diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c
index d1b8441051ae..de36e2e27330 100644
--- a/drivers/iio/dac/dpot-dac.c
+++ b/drivers/iio/dac/dpot-dac.c
@@ -30,7 +30,6 @@
#include <linux/iio/consumer.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -254,3 +253,4 @@ module_platform_driver(dpot_dac_driver);
MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer");
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c
index c61868f2de31..b6430b832cf0 100644
--- a/drivers/iio/dac/ds4424.c
+++ b/drivers/iio/dac/ds4424.c
@@ -5,22 +5,31 @@
* Copyright (C) 2017 Maxim Integrated
*/
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/i2c.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/iio/iio.h>
+#include <linux/time64.h>
+#include <linux/types.h>
+
#include <linux/iio/driver.h>
+#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
#define DS4422_MAX_DAC_CHANNELS 2
#define DS4424_MAX_DAC_CHANNELS 4
+#define DS4424_DAC_MASK GENMASK(6, 0)
+#define DS4404_DAC_MASK GENMASK(4, 0)
+#define DS4424_DAC_SOURCE BIT(7)
+
#define DS4424_DAC_ADDR(chan) ((chan) + 0xf8)
-#define DS4424_SOURCE_I 1
-#define DS4424_SINK_I 0
#define DS4424_CHANNEL(chan) { \
.type = IIO_CURRENT, \
@@ -30,33 +39,61 @@
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
-/*
- * DS4424 DAC control register 8 bits
- * [7] 0: to sink; 1: to source
- * [6:0] steps to sink/source
- * bit[7] looks like a sign bit, but the value of the register is
- * not a two's complement code considering the bit[6:0] is a absolute
- * distance from the zero point.
- */
-union ds4424_raw_data {
- struct {
- u8 dx:7;
- u8 source_bit:1;
- };
- u8 bits;
+#define DS4424_CHANNEL_WITH_SCALE(chan) { \
+ .type = IIO_CURRENT, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+struct ds4424_chip_info {
+ const char *name;
+ int vref_mV;
+ int scale_denom;
+ u8 result_mask;
+ u8 num_channels;
+};
+
+static const struct ds4424_chip_info ds4402_info = {
+ .name = "ds4402",
+ .vref_mV = 1230,
+ .scale_denom = 4,
+ .result_mask = DS4404_DAC_MASK,
+ .num_channels = DS4422_MAX_DAC_CHANNELS,
+};
+
+static const struct ds4424_chip_info ds4404_info = {
+ .name = "ds4404",
+ .vref_mV = 1230,
+ .scale_denom = 4,
+ .result_mask = DS4404_DAC_MASK,
+ .num_channels = DS4424_MAX_DAC_CHANNELS,
+};
+
+static const struct ds4424_chip_info ds4422_info = {
+ .name = "ds4422",
+ .vref_mV = 976,
+ .scale_denom = 16,
+ .result_mask = DS4424_DAC_MASK,
+ .num_channels = DS4422_MAX_DAC_CHANNELS,
};
-enum ds4424_device_ids {
- ID_DS4422,
- ID_DS4424,
+static const struct ds4424_chip_info ds4424_info = {
+ .name = "ds4424",
+ .vref_mV = 976,
+ .scale_denom = 16,
+ .result_mask = DS4424_DAC_MASK,
+ .num_channels = DS4424_MAX_DAC_CHANNELS,
};
struct ds4424_data {
- struct i2c_client *client;
- struct mutex lock;
- uint8_t save[DS4424_MAX_DAC_CHANNELS];
+ struct regmap *regmap;
struct regulator *vcc_reg;
- uint8_t raw[DS4424_MAX_DAC_CHANNELS];
+ const struct ds4424_chip_info *chip_info;
+ u32 rfs_ohms[DS4424_MAX_DAC_CHANNELS];
+ bool has_rfs;
};
static const struct iio_chan_spec ds4424_channels[] = {
@@ -66,63 +103,114 @@ static const struct iio_chan_spec ds4424_channels[] = {
DS4424_CHANNEL(3),
};
-static int ds4424_get_value(struct iio_dev *indio_dev,
- int *val, int channel)
-{
- struct ds4424_data *data = iio_priv(indio_dev);
- int ret;
+static const struct iio_chan_spec ds4424_channels_with_scale[] = {
+ DS4424_CHANNEL_WITH_SCALE(0),
+ DS4424_CHANNEL_WITH_SCALE(1),
+ DS4424_CHANNEL_WITH_SCALE(2),
+ DS4424_CHANNEL_WITH_SCALE(3),
+};
- mutex_lock(&data->lock);
- ret = i2c_smbus_read_byte_data(data->client, DS4424_DAC_ADDR(channel));
- if (ret < 0)
- goto fail;
+static const struct regmap_range ds44x2_ranges[] = {
+ regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(1)),
+};
- *val = ret;
+static const struct regmap_range ds44x4_ranges[] = {
+ regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(3)),
+};
-fail:
- mutex_unlock(&data->lock);
- return ret;
-}
+static const struct regmap_access_table ds44x2_table = {
+ .yes_ranges = ds44x2_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ds44x2_ranges),
+};
+
+static const struct regmap_access_table ds44x4_table = {
+ .yes_ranges = ds44x4_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ds44x4_ranges),
+};
-static int ds4424_set_value(struct iio_dev *indio_dev,
- int val, struct iio_chan_spec const *chan)
+static const struct regmap_config ds44x2_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .max_register = DS4424_DAC_ADDR(1),
+ .rd_table = &ds44x2_table,
+ .wr_table = &ds44x2_table,
+};
+
+static const struct regmap_config ds44x4_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .max_register = DS4424_DAC_ADDR(3),
+ .rd_table = &ds44x4_table,
+ .wr_table = &ds44x4_table,
+};
+
+static int ds4424_init_regmap(struct i2c_client *client,
+ struct iio_dev *indio_dev)
{
struct ds4424_data *data = iio_priv(indio_dev);
+ const struct regmap_config *regmap_config;
+ u8 vals[DS4424_MAX_DAC_CHANNELS];
int ret;
- mutex_lock(&data->lock);
- ret = i2c_smbus_write_byte_data(data->client,
- DS4424_DAC_ADDR(chan->channel), val);
- if (ret < 0)
- goto fail;
-
- data->raw[chan->channel] = val;
-
-fail:
- mutex_unlock(&data->lock);
- return ret;
+ if (indio_dev->num_channels == DS4424_MAX_DAC_CHANNELS)
+ regmap_config = &ds44x4_regmap_config;
+ else
+ regmap_config = &ds44x2_regmap_config;
+
+ data->regmap = devm_regmap_init_i2c(client, regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(data->regmap),
+ "Failed to init regmap.\n");
+
+ /*
+ * Prime the cache with the bootloader's configuration.
+ * regmap_bulk_read() will automatically populate the cache with
+ * the values read from the hardware.
+ */
+ ret = regmap_bulk_read(data->regmap, DS4424_DAC_ADDR(0), vals,
+ indio_dev->num_channels);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to read hardware values\n");
+
+ return 0;
}
static int ds4424_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
- union ds4424_raw_data raw;
+ struct ds4424_data *data = iio_priv(indio_dev);
+ unsigned int regval;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = ds4424_get_value(indio_dev, val, chan->channel);
+ ret = regmap_read(data->regmap, DS4424_DAC_ADDR(chan->channel),
+ &regval);
if (ret < 0) {
- pr_err("%s : ds4424_get_value returned %d\n",
- __func__, ret);
+ dev_err_ratelimited(indio_dev->dev.parent,
+ "Failed to read channel %d: %pe\n",
+ chan->channel, ERR_PTR(ret));
return ret;
}
- raw.bits = *val;
- *val = raw.dx;
- if (raw.source_bit == DS4424_SINK_I)
+
+ *val = regval & data->chip_info->result_mask;
+ if (!(regval & DS4424_DAC_SOURCE))
*val = -*val;
+
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ if (!data->has_rfs)
+ return -EINVAL;
+
+ /* SCALE is mA/step: mV / Ohm = mA. */
+ *val = data->chip_info->vref_mV;
+ *val2 = data->rfs_ohms[chan->channel] *
+ data->chip_info->scale_denom;
+ return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
@@ -133,107 +221,131 @@ static int ds4424_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
- union ds4424_raw_data raw;
+ struct ds4424_data *data = iio_priv(indio_dev);
+ unsigned int abs_val;
if (val2 != 0)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- if (val <= S8_MIN || val > S8_MAX)
+ abs_val = abs(val);
+ if (abs_val > data->chip_info->result_mask)
return -EINVAL;
- if (val > 0) {
- raw.source_bit = DS4424_SOURCE_I;
- raw.dx = val;
- } else {
- raw.source_bit = DS4424_SINK_I;
- raw.dx = -val;
- }
+ /*
+ * Currents exiting the IC (Source) are positive. 0 is a valid
+ * value for no current flow; the direction bit (Source vs Sink)
+ * is treated as don't-care by the hardware at 0.
+ */
+ if (val > 0)
+ abs_val |= DS4424_DAC_SOURCE;
- return ds4424_set_value(indio_dev, raw.bits, chan);
+ return regmap_write(data->regmap, DS4424_DAC_ADDR(chan->channel),
+ abs_val);
default:
return -EINVAL;
}
}
-static int ds4424_verify_chip(struct iio_dev *indio_dev)
+static int ds4424_parse_rfs(struct i2c_client *client,
+ struct ds4424_data *data,
+ struct iio_dev *indio_dev)
{
- int ret, val;
+ struct device *dev = &client->dev;
+ int count, ret;
+
+ if (!device_property_present(dev, "maxim,rfs-ohms"))
+ return 0;
+
+ count = device_property_count_u32(dev, "maxim,rfs-ohms");
+ if (count < 0)
+ return dev_err_probe(dev, count, "Failed to count maxim,rfs-ohms entries\n");
+ if (count != indio_dev->num_channels)
+ return dev_err_probe(dev, -EINVAL, "maxim,rfs-ohms must have %u entries\n",
+ indio_dev->num_channels);
+
+ ret = device_property_read_u32_array(dev, "maxim,rfs-ohms",
+ data->rfs_ohms,
+ indio_dev->num_channels);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read maxim,rfs-ohms property\n");
+
+ for (unsigned int i = 0; i < indio_dev->num_channels; i++) {
+ if (!data->rfs_ohms[i])
+ return dev_err_probe(dev, -EINVAL, "maxim,rfs-ohms entry %u is zero\n", i);
+ }
- ret = ds4424_get_value(indio_dev, &val, 0);
- if (ret < 0)
- dev_err(&indio_dev->dev,
- "%s failed. ret: %d\n", __func__, ret);
+ data->has_rfs = true;
- return ret;
+ return 0;
}
static int ds4424_suspend(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ds4424_data *data = iio_priv(indio_dev);
- int ret = 0;
- int i;
-
- for (i = 0; i < indio_dev->num_channels; i++) {
- data->save[i] = data->raw[i];
- ret = ds4424_set_value(indio_dev, 0,
- &indio_dev->channels[i]);
- if (ret < 0)
- return ret;
+ u8 zero_buf[DS4424_MAX_DAC_CHANNELS] = { };
+ int ret;
+
+ /* Disable all outputs, bypass cache so the '0' isn't saved */
+ regcache_cache_bypass(data->regmap, true);
+ ret = regmap_bulk_write(data->regmap, DS4424_DAC_ADDR(0),
+ zero_buf, indio_dev->num_channels);
+ regcache_cache_bypass(data->regmap, false);
+ if (ret) {
+ dev_err(dev, "Failed to zero outputs: %pe\n", ERR_PTR(ret));
+ return ret;
}
- return ret;
+
+ regcache_cache_only(data->regmap, true);
+ regcache_mark_dirty(data->regmap);
+
+ return 0;
}
static int ds4424_resume(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ds4424_data *data = iio_priv(indio_dev);
- int ret = 0;
- int i;
- for (i = 0; i < indio_dev->num_channels; i++) {
- ret = ds4424_set_value(indio_dev, data->save[i],
- &indio_dev->channels[i]);
- if (ret < 0)
- return ret;
- }
- return ret;
+ regcache_cache_only(data->regmap, false);
+ return regcache_sync(data->regmap);
}
static DEFINE_SIMPLE_DEV_PM_OPS(ds4424_pm_ops, ds4424_suspend, ds4424_resume);
-static const struct iio_info ds4424_info = {
+static const struct iio_info ds4424_iio_info = {
.read_raw = ds4424_read_raw,
.write_raw = ds4424_write_raw,
};
static int ds4424_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ const struct ds4424_chip_info *chip_info;
struct ds4424_data *data;
struct iio_dev *indio_dev;
int ret;
+ chip_info = i2c_get_match_data(client);
+ if (!chip_info)
+ return -ENODEV;
+
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
- data->client = client;
- indio_dev->name = id->name;
+ indio_dev->name = chip_info->name;
+ data->chip_info = chip_info;
data->vcc_reg = devm_regulator_get(&client->dev, "vcc");
if (IS_ERR(data->vcc_reg))
return dev_err_probe(&client->dev, PTR_ERR(data->vcc_reg),
"Failed to get vcc-supply regulator.\n");
- mutex_init(&data->lock);
ret = regulator_enable(data->vcc_reg);
if (ret < 0) {
dev_err(&client->dev,
@@ -241,28 +353,29 @@ static int ds4424_probe(struct i2c_client *client)
return ret;
}
- usleep_range(1000, 1200);
- ret = ds4424_verify_chip(indio_dev);
- if (ret < 0)
+ /*
+ * The datasheet does not specify a power-up to I2C ready time.
+ * Maintain the existing conservative 1ms delay to ensure the
+ * device is ready for communication.
+ */
+ fsleep(1 * USEC_PER_MSEC);
+
+ indio_dev->num_channels = chip_info->num_channels;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &ds4424_iio_info;
+
+ ret = ds4424_init_regmap(client, indio_dev);
+ if (ret)
goto fail;
- switch (id->driver_data) {
- case ID_DS4422:
- indio_dev->num_channels = DS4422_MAX_DAC_CHANNELS;
- break;
- case ID_DS4424:
- indio_dev->num_channels = DS4424_MAX_DAC_CHANNELS;
- break;
- default:
- dev_err(&client->dev,
- "ds4424: Invalid chip id.\n");
- ret = -ENXIO;
+ ret = ds4424_parse_rfs(client, data, indio_dev);
+ if (ret)
goto fail;
- }
- indio_dev->channels = ds4424_channels;
- indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->info = &ds4424_info;
+ if (data->has_rfs)
+ indio_dev->channels = ds4424_channels_with_scale;
+ else
+ indio_dev->channels = ds4424_channels;
ret = iio_device_register(indio_dev);
if (ret < 0) {
@@ -288,16 +401,20 @@ static void ds4424_remove(struct i2c_client *client)
}
static const struct i2c_device_id ds4424_id[] = {
- { "ds4422", ID_DS4422 },
- { "ds4424", ID_DS4424 },
+ { .name = "ds4402", .driver_data = (kernel_ulong_t)&ds4402_info },
+ { .name = "ds4404", .driver_data = (kernel_ulong_t)&ds4404_info },
+ { .name = "ds4422", .driver_data = (kernel_ulong_t)&ds4422_info },
+ { .name = "ds4424", .driver_data = (kernel_ulong_t)&ds4424_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds4424_id);
static const struct of_device_id ds4424_of_match[] = {
- { .compatible = "maxim,ds4422" },
- { .compatible = "maxim,ds4424" },
+ { .compatible = "maxim,ds4402", .data = &ds4402_info },
+ { .compatible = "maxim,ds4404", .data = &ds4404_info },
+ { .compatible = "maxim,ds4422", .data = &ds4422_info },
+ { .compatible = "maxim,ds4424", .data = &ds4424_info },
{ }
};
diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c
index aa1c73f8429d..43fb9e5a2c56 100644
--- a/drivers/iio/dac/lpc18xx_dac.c
+++ b/drivers/iio/dac/lpc18xx_dac.c
@@ -16,7 +16,6 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
diff --git a/drivers/iio/dac/ltc1660.c b/drivers/iio/dac/ltc1660.c
index 6e80b49f4665..90ffb58e7927 100644
--- a/drivers/iio/dac/ltc1660.c
+++ b/drivers/iio/dac/ltc1660.c
@@ -224,8 +224,8 @@ static const struct of_device_id ltc1660_dt_ids[] = {
MODULE_DEVICE_TABLE(of, ltc1660_dt_ids);
static const struct spi_device_id ltc1660_id[] = {
- {"ltc1660", ID_LTC1660},
- {"ltc1665", ID_LTC1665},
+ { .name = "ltc1660", .driver_data = ID_LTC1660 },
+ { .name = "ltc1665", .driver_data = ID_LTC1665 },
{ }
};
MODULE_DEVICE_TABLE(spi, ltc1660_id);
diff --git a/drivers/iio/dac/ltc2632.c b/drivers/iio/dac/ltc2632.c
index 105f939f7e54..3800aee8dd6e 100644
--- a/drivers/iio/dac/ltc2632.c
+++ b/drivers/iio/dac/ltc2632.c
@@ -48,27 +48,6 @@ struct ltc2632_state {
int vref_mv;
};
-enum ltc2632_supported_device_ids {
- ID_LTC2632L12,
- ID_LTC2632L10,
- ID_LTC2632L8,
- ID_LTC2632H12,
- ID_LTC2632H10,
- ID_LTC2632H8,
- ID_LTC2634L12,
- ID_LTC2634L10,
- ID_LTC2634L8,
- ID_LTC2634H12,
- ID_LTC2634H10,
- ID_LTC2634H8,
- ID_LTC2636L12,
- ID_LTC2636L10,
- ID_LTC2636L8,
- ID_LTC2636H12,
- ID_LTC2636H10,
- ID_LTC2636H8,
-};
-
static int ltc2632_spi_write(struct spi_device *spi,
u8 cmd, u8 addr, u16 val, u8 shift)
{
@@ -79,8 +58,9 @@ static int ltc2632_spi_write(struct spi_device *spi,
* The input shift register is 24 bits wide.
* The next four are the command bits, C3 to C0,
* followed by the 4-bit DAC address, A3 to A0, and then the
- * 12-, 10-, 8-bit data-word. The data-word comprises the 12-,
- * 10-, 8-bit input code followed by 4, 6, or 8 don't care bits.
+ * 16-, 12-, 10-, 8-bit data-word. The data-word comprises the
+ * 16-, 12-, 10-, 8-bit input code followed by 0, 4, 6, or 8
+ * don't care bits.
*/
data = (cmd << 20) | (addr << 16) | (val << shift);
put_unaligned_be24(data, &msg[0]);
@@ -206,101 +186,129 @@ static const struct iio_chan_spec_ext_info ltc2632_ext_info[] = {
LTC2632_CHANNEL(7, _bits), \
}
+static DECLARE_LTC2632_CHANNELS(ltc2632x16, 16);
static DECLARE_LTC2632_CHANNELS(ltc2632x12, 12);
static DECLARE_LTC2632_CHANNELS(ltc2632x10, 10);
static DECLARE_LTC2632_CHANNELS(ltc2632x8, 8);
-static const struct ltc2632_chip_info ltc2632_chip_info_tbl[] = {
- [ID_LTC2632L12] = {
- .channels = ltc2632x12_channels,
- .num_channels = 2,
- .vref_mv = 2500,
- },
- [ID_LTC2632L10] = {
- .channels = ltc2632x10_channels,
- .num_channels = 2,
- .vref_mv = 2500,
- },
- [ID_LTC2632L8] = {
- .channels = ltc2632x8_channels,
- .num_channels = 2,
- .vref_mv = 2500,
- },
- [ID_LTC2632H12] = {
- .channels = ltc2632x12_channels,
- .num_channels = 2,
- .vref_mv = 4096,
- },
- [ID_LTC2632H10] = {
- .channels = ltc2632x10_channels,
- .num_channels = 2,
- .vref_mv = 4096,
- },
- [ID_LTC2632H8] = {
- .channels = ltc2632x8_channels,
- .num_channels = 2,
- .vref_mv = 4096,
- },
- [ID_LTC2634L12] = {
- .channels = ltc2632x12_channels,
- .num_channels = 4,
- .vref_mv = 2500,
- },
- [ID_LTC2634L10] = {
- .channels = ltc2632x10_channels,
- .num_channels = 4,
- .vref_mv = 2500,
- },
- [ID_LTC2634L8] = {
- .channels = ltc2632x8_channels,
- .num_channels = 4,
- .vref_mv = 2500,
- },
- [ID_LTC2634H12] = {
- .channels = ltc2632x12_channels,
- .num_channels = 4,
- .vref_mv = 4096,
- },
- [ID_LTC2634H10] = {
- .channels = ltc2632x10_channels,
- .num_channels = 4,
- .vref_mv = 4096,
- },
- [ID_LTC2634H8] = {
- .channels = ltc2632x8_channels,
- .num_channels = 4,
- .vref_mv = 4096,
- },
- [ID_LTC2636L12] = {
- .channels = ltc2632x12_channels,
- .num_channels = 8,
- .vref_mv = 2500,
- },
- [ID_LTC2636L10] = {
- .channels = ltc2632x10_channels,
- .num_channels = 8,
- .vref_mv = 2500,
- },
- [ID_LTC2636L8] = {
- .channels = ltc2632x8_channels,
- .num_channels = 8,
- .vref_mv = 2500,
- },
- [ID_LTC2636H12] = {
- .channels = ltc2632x12_channels,
- .num_channels = 8,
- .vref_mv = 4096,
- },
- [ID_LTC2636H10] = {
- .channels = ltc2632x10_channels,
- .num_channels = 8,
- .vref_mv = 4096,
- },
- [ID_LTC2636H8] = {
- .channels = ltc2632x8_channels,
- .num_channels = 8,
- .vref_mv = 4096,
- },
+static const struct ltc2632_chip_info ltc2632l12_chip_info = {
+ .channels = ltc2632x12_channels,
+ .num_channels = 2,
+ .vref_mv = 2500,
+};
+
+static const struct ltc2632_chip_info ltc2632l10_chip_info = {
+ .channels = ltc2632x10_channels,
+ .num_channels = 2,
+ .vref_mv = 2500,
+};
+
+static const struct ltc2632_chip_info ltc2632l8_chip_info = {
+ .channels = ltc2632x8_channels,
+ .num_channels = 2,
+ .vref_mv = 2500,
+};
+
+static const struct ltc2632_chip_info ltc2632h12_chip_info = {
+ .channels = ltc2632x12_channels,
+ .num_channels = 2,
+ .vref_mv = 4096,
+};
+
+static const struct ltc2632_chip_info ltc2632h10_chip_info = {
+ .channels = ltc2632x10_channels,
+ .num_channels = 2,
+ .vref_mv = 4096,
+};
+
+static const struct ltc2632_chip_info ltc2632h8_chip_info = {
+ .channels = ltc2632x8_channels,
+ .num_channels = 2,
+ .vref_mv = 4096,
+};
+
+static const struct ltc2632_chip_info ltc2634l12_chip_info = {
+ .channels = ltc2632x12_channels,
+ .num_channels = 4,
+ .vref_mv = 2500,
+};
+
+static const struct ltc2632_chip_info ltc2634l10_chip_info = {
+ .channels = ltc2632x10_channels,
+ .num_channels = 4,
+ .vref_mv = 2500,
+};
+
+static const struct ltc2632_chip_info ltc2634l8_chip_info = {
+ .channels = ltc2632x8_channels,
+ .num_channels = 4,
+ .vref_mv = 2500,
+};
+
+static const struct ltc2632_chip_info ltc2634h12_chip_info = {
+ .channels = ltc2632x12_channels,
+ .num_channels = 4,
+ .vref_mv = 4096,
+};
+
+static const struct ltc2632_chip_info ltc2634h10_chip_info = {
+ .channels = ltc2632x10_channels,
+ .num_channels = 4,
+ .vref_mv = 4096,
+};
+
+static const struct ltc2632_chip_info ltc2634h8_chip_info = {
+ .channels = ltc2632x8_channels,
+ .num_channels = 4,
+ .vref_mv = 4096,
+};
+
+static const struct ltc2632_chip_info ltc2636l12_chip_info = {
+ .channels = ltc2632x12_channels,
+ .num_channels = 8,
+ .vref_mv = 2500,
+};
+
+static const struct ltc2632_chip_info ltc2636l10_chip_info = {
+ .channels = ltc2632x10_channels,
+ .num_channels = 8,
+ .vref_mv = 2500,
+};
+
+static const struct ltc2632_chip_info ltc2636l8_chip_info = {
+ .channels = ltc2632x8_channels,
+ .num_channels = 8,
+ .vref_mv = 2500,
+};
+
+static const struct ltc2632_chip_info ltc2636h12_chip_info = {
+ .channels = ltc2632x12_channels,
+ .num_channels = 8,
+ .vref_mv = 4096,
+};
+
+static const struct ltc2632_chip_info ltc2636h10_chip_info = {
+ .channels = ltc2632x10_channels,
+ .num_channels = 8,
+ .vref_mv = 4096,
+};
+
+static const struct ltc2632_chip_info ltc2636h8_chip_info = {
+ .channels = ltc2632x8_channels,
+ .num_channels = 8,
+ .vref_mv = 4096,
+};
+
+static const struct ltc2632_chip_info ltc2654l16_chip_info = {
+ .channels = ltc2632x16_channels,
+ .num_channels = 4,
+ .vref_mv = 2500,
+};
+
+static const struct ltc2632_chip_info ltc2654h16_chip_info = {
+ .channels = ltc2632x16_channels,
+ .num_channels = 4,
+ .vref_mv = 4096,
};
static int ltc2632_probe(struct spi_device *spi)
@@ -354,84 +362,53 @@ static int ltc2632_probe(struct spi_device *spi)
}
static const struct spi_device_id ltc2632_id[] = {
- { "ltc2632-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L12] },
- { "ltc2632-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L10] },
- { "ltc2632-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L8] },
- { "ltc2632-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H12] },
- { "ltc2632-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H10] },
- { "ltc2632-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H8] },
- { "ltc2634-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L12] },
- { "ltc2634-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L10] },
- { "ltc2634-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L8] },
- { "ltc2634-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H12] },
- { "ltc2634-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H10] },
- { "ltc2634-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H8] },
- { "ltc2636-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L12] },
- { "ltc2636-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L10] },
- { "ltc2636-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L8] },
- { "ltc2636-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H12] },
- { "ltc2636-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H10] },
- { "ltc2636-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H8] },
+ { .name = "ltc2632-l12", .driver_data = (kernel_ulong_t)&ltc2632l12_chip_info },
+ { .name = "ltc2632-l10", .driver_data = (kernel_ulong_t)&ltc2632l10_chip_info },
+ { .name = "ltc2632-l8", .driver_data = (kernel_ulong_t)&ltc2632l8_chip_info },
+ { .name = "ltc2632-h12", .driver_data = (kernel_ulong_t)&ltc2632h12_chip_info },
+ { .name = "ltc2632-h10", .driver_data = (kernel_ulong_t)&ltc2632h10_chip_info },
+ { .name = "ltc2632-h8", .driver_data = (kernel_ulong_t)&ltc2632h8_chip_info },
+ { .name = "ltc2634-l12", .driver_data = (kernel_ulong_t)&ltc2634l12_chip_info },
+ { .name = "ltc2634-l10", .driver_data = (kernel_ulong_t)&ltc2634l10_chip_info },
+ { .name = "ltc2634-l8", .driver_data = (kernel_ulong_t)&ltc2634l8_chip_info },
+ { .name = "ltc2634-h12", .driver_data = (kernel_ulong_t)&ltc2634h12_chip_info },
+ { .name = "ltc2634-h10", .driver_data = (kernel_ulong_t)&ltc2634h10_chip_info },
+ { .name = "ltc2634-h8", .driver_data = (kernel_ulong_t)&ltc2634h8_chip_info },
+ { .name = "ltc2636-l12", .driver_data = (kernel_ulong_t)&ltc2636l12_chip_info },
+ { .name = "ltc2636-l10", .driver_data = (kernel_ulong_t)&ltc2636l10_chip_info },
+ { .name = "ltc2636-l8", .driver_data = (kernel_ulong_t)&ltc2636l8_chip_info },
+ { .name = "ltc2636-h12", .driver_data = (kernel_ulong_t)&ltc2636h12_chip_info },
+ { .name = "ltc2636-h10", .driver_data = (kernel_ulong_t)&ltc2636h10_chip_info },
+ { .name = "ltc2636-h8", .driver_data = (kernel_ulong_t)&ltc2636h8_chip_info },
+ { .name = "ltc2654-l16", .driver_data = (kernel_ulong_t)&ltc2654l16_chip_info },
+ { .name = "ltc2654-l12", .driver_data = (kernel_ulong_t)&ltc2634l12_chip_info },
+ { .name = "ltc2654-h16", .driver_data = (kernel_ulong_t)&ltc2654h16_chip_info },
+ { .name = "ltc2654-h12", .driver_data = (kernel_ulong_t)&ltc2634h12_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ltc2632_id);
static const struct of_device_id ltc2632_of_match[] = {
- {
- .compatible = "lltc,ltc2632-l12",
- .data = &ltc2632_chip_info_tbl[ID_LTC2632L12]
- }, {
- .compatible = "lltc,ltc2632-l10",
- .data = &ltc2632_chip_info_tbl[ID_LTC2632L10]
- }, {
- .compatible = "lltc,ltc2632-l8",
- .data = &ltc2632_chip_info_tbl[ID_LTC2632L8]
- }, {
- .compatible = "lltc,ltc2632-h12",
- .data = &ltc2632_chip_info_tbl[ID_LTC2632H12]
- }, {
- .compatible = "lltc,ltc2632-h10",
- .data = &ltc2632_chip_info_tbl[ID_LTC2632H10]
- }, {
- .compatible = "lltc,ltc2632-h8",
- .data = &ltc2632_chip_info_tbl[ID_LTC2632H8]
- }, {
- .compatible = "lltc,ltc2634-l12",
- .data = &ltc2632_chip_info_tbl[ID_LTC2634L12]
- }, {
- .compatible = "lltc,ltc2634-l10",
- .data = &ltc2632_chip_info_tbl[ID_LTC2634L10]
- }, {
- .compatible = "lltc,ltc2634-l8",
- .data = &ltc2632_chip_info_tbl[ID_LTC2634L8]
- }, {
- .compatible = "lltc,ltc2634-h12",
- .data = &ltc2632_chip_info_tbl[ID_LTC2634H12]
- }, {
- .compatible = "lltc,ltc2634-h10",
- .data = &ltc2632_chip_info_tbl[ID_LTC2634H10]
- }, {
- .compatible = "lltc,ltc2634-h8",
- .data = &ltc2632_chip_info_tbl[ID_LTC2634H8]
- }, {
- .compatible = "lltc,ltc2636-l12",
- .data = &ltc2632_chip_info_tbl[ID_LTC2636L12]
- }, {
- .compatible = "lltc,ltc2636-l10",
- .data = &ltc2632_chip_info_tbl[ID_LTC2636L10]
- }, {
- .compatible = "lltc,ltc2636-l8",
- .data = &ltc2632_chip_info_tbl[ID_LTC2636L8]
- }, {
- .compatible = "lltc,ltc2636-h12",
- .data = &ltc2632_chip_info_tbl[ID_LTC2636H12]
- }, {
- .compatible = "lltc,ltc2636-h10",
- .data = &ltc2632_chip_info_tbl[ID_LTC2636H10]
- }, {
- .compatible = "lltc,ltc2636-h8",
- .data = &ltc2632_chip_info_tbl[ID_LTC2636H8]
- },
+ { .compatible = "lltc,ltc2632-l12", .data = &ltc2632l12_chip_info },
+ { .compatible = "lltc,ltc2632-l10", .data = &ltc2632l10_chip_info },
+ { .compatible = "lltc,ltc2632-l8", .data = &ltc2632l8_chip_info },
+ { .compatible = "lltc,ltc2632-h12", .data = &ltc2632h12_chip_info },
+ { .compatible = "lltc,ltc2632-h10", .data = &ltc2632h10_chip_info },
+ { .compatible = "lltc,ltc2632-h8", .data = &ltc2632h8_chip_info },
+ { .compatible = "lltc,ltc2634-l12", .data = &ltc2634l12_chip_info },
+ { .compatible = "lltc,ltc2634-l10", .data = &ltc2634l10_chip_info },
+ { .compatible = "lltc,ltc2634-l8", .data = &ltc2634l8_chip_info },
+ { .compatible = "lltc,ltc2634-h12", .data = &ltc2634h12_chip_info },
+ { .compatible = "lltc,ltc2634-h10", .data = &ltc2634h10_chip_info },
+ { .compatible = "lltc,ltc2634-h8", .data = &ltc2634h8_chip_info },
+ { .compatible = "lltc,ltc2636-l12", .data = &ltc2636l12_chip_info },
+ { .compatible = "lltc,ltc2636-l10", .data = &ltc2636l10_chip_info },
+ { .compatible = "lltc,ltc2636-l8", .data = &ltc2636l8_chip_info },
+ { .compatible = "lltc,ltc2636-h12", .data = &ltc2636h12_chip_info },
+ { .compatible = "lltc,ltc2636-h10", .data = &ltc2636h10_chip_info },
+ { .compatible = "lltc,ltc2636-h8", .data = &ltc2636h8_chip_info },
+ { .compatible = "lltc,ltc2654-l16", .data = &ltc2654l16_chip_info },
+ { .compatible = "lltc,ltc2654-h16", .data = &ltc2654h16_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ltc2632_of_match);
@@ -447,5 +424,5 @@ static struct spi_driver ltc2632_driver = {
module_spi_driver(ltc2632_driver);
MODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>");
-MODULE_DESCRIPTION("LTC2632 DAC SPI driver");
+MODULE_DESCRIPTION("LTC2632 and similar DAC SPI driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ltc2664.c b/drivers/iio/dac/ltc2664.c
index 67f14046cf77..35bec55ebde1 100644
--- a/drivers/iio/dac/ltc2664.c
+++ b/drivers/iio/dac/ltc2664.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -675,7 +674,9 @@ static int ltc2664_probe(struct spi_device *spi)
st->chip_info = chip_info;
- mutex_init(&st->lock);
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
st->regmap = devm_regmap_init_spi(spi, &ltc2664_regmap_config);
if (IS_ERR(st->regmap))
@@ -707,8 +708,8 @@ static int ltc2664_probe(struct spi_device *spi)
}
static const struct spi_device_id ltc2664_id[] = {
- { "ltc2664", (kernel_ulong_t)&ltc2664_chip },
- { "ltc2672", (kernel_ulong_t)&ltc2672_chip },
+ { .name = "ltc2664", .driver_data = (kernel_ulong_t)&ltc2664_chip },
+ { .name = "ltc2672", .driver_data = (kernel_ulong_t)&ltc2672_chip },
{ }
};
MODULE_DEVICE_TABLE(spi, ltc2664_id);
diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c
index 02f408229681..0301bb7dce31 100644
--- a/drivers/iio/dac/ltc2688.c
+++ b/drivers/iio/dac/ltc2688.c
@@ -14,7 +14,6 @@
#include <linux/limits.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/property.h>
@@ -992,7 +991,7 @@ static const struct of_device_id ltc2688_of_id[] = {
MODULE_DEVICE_TABLE(of, ltc2688_of_id);
static const struct spi_device_id ltc2688_id[] = {
- { "ltc2688" },
+ { .name = "ltc2688" },
{ }
};
MODULE_DEVICE_TABLE(spi, ltc2688_id);
diff --git a/drivers/iio/dac/m62332.c b/drivers/iio/dac/m62332.c
index 3497513854d7..60bb672b70e2 100644
--- a/drivers/iio/dac/m62332.c
+++ b/drivers/iio/dac/m62332.c
@@ -32,6 +32,7 @@ static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel)
{
struct m62332_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
+ bool enabling, disabling;
u8 outbuf[2];
int res;
@@ -43,7 +44,10 @@ static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel)
mutex_lock(&data->mutex);
- if (val) {
+ enabling = val && !data->raw[channel];
+ disabling = !val && data->raw[channel];
+
+ if (enabling) {
res = regulator_enable(data->vcc);
if (res)
goto out;
@@ -52,14 +56,17 @@ static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel)
res = i2c_master_send(client, outbuf, ARRAY_SIZE(outbuf));
if (res >= 0 && res != ARRAY_SIZE(outbuf))
res = -EIO;
- if (res < 0)
+ if (res < 0) {
+ if (enabling)
+ regulator_disable(data->vcc);
goto out;
+ }
- data->raw[channel] = val;
-
- if (!val)
+ if (disabling)
regulator_disable(data->vcc);
+ data->raw[channel] = val;
+
mutex_unlock(&data->mutex);
return 0;
@@ -228,7 +235,7 @@ static void m62332_remove(struct i2c_client *client)
}
static const struct i2c_device_id m62332_id[] = {
- { "m62332", },
+ { .name = "m62332" },
{ }
};
MODULE_DEVICE_TABLE(i2c, m62332_id);
diff --git a/drivers/iio/dac/max22007.c b/drivers/iio/dac/max22007.c
index 182ac7155a89..e2c7e2ad37ba 100644
--- a/drivers/iio/dac/max22007.c
+++ b/drivers/iio/dac/max22007.c
@@ -19,7 +19,6 @@
#include <linux/iio/iio.h>
#include <linux/kstrtox.h>
#include <linux/minmax.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -465,7 +464,7 @@ static int max22007_probe(struct spi_device *spi)
}
static const struct spi_device_id max22007_id[] = {
- { "max22007" },
+ { .name = "max22007" },
{ }
};
MODULE_DEVICE_TABLE(spi, max22007_id);
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
index d334c67821ad..d2ddc72e0e50 100644
--- a/drivers/iio/dac/max517.c
+++ b/drivers/iio/dac/max517.c
@@ -187,11 +187,11 @@ static int max517_probe(struct i2c_client *client)
}
static const struct i2c_device_id max517_id[] = {
- { "max517", ID_MAX517 },
- { "max518", ID_MAX518 },
- { "max519", ID_MAX519 },
- { "max520", ID_MAX520 },
- { "max521", ID_MAX521 },
+ { .name = "max517", .driver_data = ID_MAX517 },
+ { .name = "max518", .driver_data = ID_MAX518 },
+ { .name = "max519", .driver_data = ID_MAX519 },
+ { .name = "max520", .driver_data = ID_MAX520 },
+ { .name = "max521", .driver_data = ID_MAX521 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max517_id);
diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c
index 1b8fe6b8d26e..f3415748c765 100644
--- a/drivers/iio/dac/max5522.c
+++ b/drivers/iio/dac/max5522.c
@@ -9,11 +9,11 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
+#include <linux/units.h>
#include <linux/iio/iio.h>
@@ -24,17 +24,10 @@
#define MAX5522_REG_DATA(x) ((x) + MAX5522_CTRL_LOAD_IN_A)
-struct max5522_chip_info {
- const char *name;
- const struct iio_chan_spec *channels;
- unsigned int num_channels;
-};
-
struct max5522_state {
struct regmap *regmap;
- const struct max5522_chip_info *chip_info;
unsigned short dac_cache[2];
- struct regulator *vrefin_reg;
+ int vref_mV;
};
#define MAX5522_CHANNEL(chan) { \
@@ -57,18 +50,6 @@ static const struct iio_chan_spec max5522_channels[] = {
MAX5522_CHANNEL(1),
};
-enum max5522_type {
- ID_MAX5522,
-};
-
-static const struct max5522_chip_info max5522_chip_info_tbl[] = {
- [ID_MAX5522] = {
- .name = "max5522",
- .channels = max5522_channels,
- .num_channels = 2,
- },
-};
-
static inline int max5522_info_to_reg(struct iio_chan_spec const *chan)
{
return MAX5522_REG_DATA(chan->channel);
@@ -79,17 +60,13 @@ static int max5522_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long info)
{
struct max5522_state *state = iio_priv(indio_dev);
- int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
*val = state->dac_cache[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- ret = regulator_get_voltage(state->vrefin_reg);
- if (ret < 0)
- return -EINVAL;
- *val = ret / 1000;
+ *val = state->vref_mV;
*val2 = 10;
return IIO_VAL_FRACTIONAL_LOG2;
default:
@@ -143,20 +120,12 @@ static int max5522_spi_probe(struct spi_device *spi)
}
state = iio_priv(indio_dev);
- state->chip_info = spi_get_device_match_data(spi);
- if (!state->chip_info)
- return -EINVAL;
- state->vrefin_reg = devm_regulator_get(&spi->dev, "vrefin");
- if (IS_ERR(state->vrefin_reg))
- return dev_err_probe(&spi->dev, PTR_ERR(state->vrefin_reg),
- "Vrefin regulator not specified\n");
-
- ret = regulator_enable(state->vrefin_reg);
- if (ret) {
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vrefin");
+ if (ret < 0)
return dev_err_probe(&spi->dev, ret,
- "Failed to enable vref regulators\n");
- }
+ "Failed to get vrefin regulator\n");
+ state->vref_mV = ret / (MICRO / MILLI);
state->regmap = devm_regmap_init_spi(spi, &max5522_regmap_config);
@@ -167,22 +136,19 @@ static int max5522_spi_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = max5522_channels;
indio_dev->num_channels = ARRAY_SIZE(max5522_channels);
- indio_dev->name = max5522_chip_info_tbl[ID_MAX5522].name;
+ indio_dev->name = "max5522";
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id max5522_ids[] = {
- { "max5522", (kernel_ulong_t)&max5522_chip_info_tbl[ID_MAX5522] },
+ { .name = "max5522" },
{ }
};
MODULE_DEVICE_TABLE(spi, max5522_ids);
static const struct of_device_id max5522_of_match[] = {
- {
- .compatible = "maxim,max5522",
- .data = &max5522_chip_info_tbl[ID_MAX5522],
- },
+ { .compatible = "maxim,max5522" },
{ }
};
MODULE_DEVICE_TABLE(of, max5522_of_match);
diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c
index e7e29359f8fe..45def245626b 100644
--- a/drivers/iio/dac/max5821.c
+++ b/drivers/iio/dac/max5821.c
@@ -26,10 +26,6 @@
#define MAX5821_EXTENDED_DAC_A 0x04
#define MAX5821_EXTENDED_DAC_B 0x08
-enum max5821_device_ids {
- ID_MAX5821,
-};
-
struct max5821_data {
struct i2c_client *client;
unsigned short vref_mv;
@@ -90,6 +86,7 @@ static int max5821_sync_powerdown_mode(struct max5821_data *data,
const struct iio_chan_spec *chan)
{
u8 outbuf[2];
+ int ret;
outbuf[0] = MAX5821_EXTENDED_COMMAND_MODE;
@@ -103,7 +100,13 @@ static int max5821_sync_powerdown_mode(struct max5821_data *data,
else
outbuf[1] |= MAX5821_EXTENDED_POWER_UP;
- return i2c_master_send(data->client, outbuf, 2);
+ ret = i2c_master_send(data->client, outbuf, sizeof(outbuf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(outbuf))
+ return -EIO;
+
+ return 0;
}
static ssize_t max5821_write_dac_powerdown(struct iio_dev *indio_dev,
@@ -332,7 +335,7 @@ static int max5821_probe(struct i2c_client *client)
}
static const struct i2c_device_id max5821_id[] = {
- { "max5821", ID_MAX5821 },
+ { .name = "max5821" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max5821_id);
diff --git a/drivers/iio/dac/mcf54415_dac.c b/drivers/iio/dac/mcf54415_dac.c
new file mode 100644
index 000000000000..e2c12241a534
--- /dev/null
+++ b/drivers/iio/dac/mcf54415_dac.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * NXP mcf54415 DAC driver
+ *
+ * Copyright 2026 BayLibre - adureghello@baylibre.com
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include <linux/iio/iio.h>
+
+#define MCF54415_DAC_CR 0x00
+#define MCF54415_DAC_CR_PDN BIT(0)
+#define MCF54415_DAC_CR_HSLS BIT(6)
+#define MCF54415_DAC_CR_WMLVL GENMASK(9, 8)
+#define MCF54415_DAC_CR_FILT BIT(12)
+
+#define MCF54415_DAC_DATA 0x02
+
+struct mcf54415_dac {
+ struct regmap *map;
+ struct clk *clk;
+};
+
+static const struct regmap_config mcf54415_dac_regmap_config = {
+ .reg_bits = 16,
+ .reg_stride = 2,
+ .val_bits = 16,
+ .max_register = 0x0c, /* DACX_FILTCNT, R.M. Table 30-2 */
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static int mcf54415_dac_init(struct mcf54415_dac *info)
+{
+ u16 val = MCF54415_DAC_CR_FILT | FIELD_PREP(MCF54415_DAC_CR_WMLVL, 1);
+ int ret;
+
+ /* Fixed defaults and enable DAC (bit 0 set to 0) */
+ ret = regmap_write(info->map, MCF54415_DAC_CR, val);
+ if (ret)
+ return ret;
+
+ /* DAC is ready after 12us, from RM table 40-3 */
+ fsleep(12);
+
+ return 0;
+}
+
+static void mcf54415_dac_exit(void *data)
+{
+ struct mcf54415_dac *info = data;
+
+ regmap_set_bits(info->map, MCF54415_DAC_CR, MCF54415_DAC_CR_PDN);
+}
+
+static const struct iio_chan_spec mcf54415_dac_iio_channel = {
+ .type = IIO_VOLTAGE,
+ .output = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+};
+
+static int mcf54415_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mcf54415_dac *info = iio_priv(indio_dev);
+ unsigned int reg;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = regmap_read(info->map, MCF54415_DAC_DATA, &reg);
+ if (ret)
+ return ret;
+ *val = reg & GENMASK(11, 0);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /* Reference voltage as per ColdFire datasheet is 3.3V */
+ *val = 3300 /* mV */;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcf54415_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct mcf54415_dac *info = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ /* Check based on RM 30.3.2 (DACn_DATA) reg. resolution */
+ if (val < 0 || val > 4095)
+ return -EINVAL;
+ return regmap_write(info->map, MCF54415_DAC_DATA, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info mcf54415_dac_iio_info = {
+ .read_raw = &mcf54415_read_raw,
+ .write_raw = &mcf54415_write_raw,
+};
+
+static int mcf54415_dac_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct mcf54415_dac *info;
+ void __iomem *regs;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ info = iio_priv(indio_dev);
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return dev_err_probe(dev, PTR_ERR(regs), "failed to get io regs\n");
+
+ info->map = devm_regmap_init_mmio(dev, regs, &mcf54415_dac_regmap_config);
+ if (IS_ERR(info->map))
+ return PTR_ERR(info->map);
+
+ info->clk = devm_clk_get_enabled(dev, "dac");
+ if (IS_ERR(info->clk))
+ return dev_err_probe(dev, PTR_ERR(info->clk), "failed getting clock\n");
+
+ indio_dev->name = "mcf54415";
+ indio_dev->info = &mcf54415_dac_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = &mcf54415_dac_iio_channel;
+ indio_dev->num_channels = 1;
+
+ ret = mcf54415_dac_init(info);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, mcf54415_dac_exit, info);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct platform_device_id mcf54415_dac_ids[] = {
+ { .name = "mcfdac" },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, mcf54415_dac_ids);
+
+static struct platform_driver mcf54415_dac_driver = {
+ .driver = {
+ .name = "mcf54415_dac",
+ },
+ .probe = mcf54415_dac_probe,
+ .id_table = mcf54415_dac_ids,
+};
+module_platform_driver(mcf54415_dac_driver);
+
+MODULE_AUTHOR("Angelo Dureghello <angelo@kernel-space.org>");
+MODULE_DESCRIPTION("NXP MCF54415 DAC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c
index 23b9e3a09ec8..3fa7acc69aeb 100644
--- a/drivers/iio/dac/mcp4725.c
+++ b/drivers/iio/dac/mcp4725.c
@@ -16,7 +16,6 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/iio/iio.h>
@@ -523,8 +522,8 @@ static const struct mcp4725_chip_info mcp4726 = {
};
static const struct i2c_device_id mcp4725_id[] = {
- { "mcp4725", (kernel_ulong_t)&mcp4725 },
- { "mcp4726", (kernel_ulong_t)&mcp4726 },
+ { .name = "mcp4725", .driver_data = (kernel_ulong_t)&mcp4725 },
+ { .name = "mcp4726", .driver_data = (kernel_ulong_t)&mcp4726 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp4725_id);
diff --git a/drivers/iio/dac/mcp4728.c b/drivers/iio/dac/mcp4728.c
index 4f30b99110b7..1fe184d49fc5 100644
--- a/drivers/iio/dac/mcp4728.c
+++ b/drivers/iio/dac/mcp4728.c
@@ -20,7 +20,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
@@ -572,7 +571,7 @@ static int mcp4728_probe(struct i2c_client *client)
}
static const struct i2c_device_id mcp4728_id[] = {
- { "mcp4728" },
+ { .name = "mcp4728" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp4728_id);
diff --git a/drivers/iio/dac/mcp47a1.c b/drivers/iio/dac/mcp47a1.c
new file mode 100644
index 000000000000..0bf994aa0e4f
--- /dev/null
+++ b/drivers/iio/dac/mcp47a1.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Microchip MCP47A1 DAC driver
+ *
+ * Copyright (c) 2026 Joshua Crofts <joshua.crofts1@gmail.com>
+ *
+ * Datasheet: https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/25154A.pdf
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+
+#define MCP47A1_CMD_CODE 0x00
+#define MCP47A1_MAX_STEPS 64
+
+struct mcp47a1_data {
+ struct i2c_client *client;
+ int vref_mV;
+};
+
+static const int mcp47a1_raw_avail[] = { 0, 1, MCP47A1_MAX_STEPS - 1 };
+
+static const struct iio_chan_spec mcp47a1_channel = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .output = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+};
+
+static int mcp47a1_write(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct mcp47a1_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (!in_range(val, 0, MCP47A1_MAX_STEPS))
+ return -EINVAL;
+
+ return i2c_smbus_write_byte_data(data->client, MCP47A1_CMD_CODE,
+ val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp47a1_read(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mcp47a1_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = i2c_smbus_read_byte_data(data->client, MCP47A1_CMD_CODE);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = data->vref_mV;
+ *val2 = MCP47A1_MAX_STEPS;
+
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp47a1_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_RAW:
+ *vals = mcp47a1_raw_avail;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_RANGE;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info mcp47a1_info = {
+ .write_raw = mcp47a1_write,
+ .read_raw = mcp47a1_read,
+ .read_avail = mcp47a1_read_avail,
+};
+
+static int mcp47a1_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct mcp47a1_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 = client;
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable regulator\n");
+
+ /* Delay after device exits reset state (see AC/DC characteristics) */
+ fsleep(20);
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "vref");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to read vref\n");
+
+ data->vref_mV = ret / (MICRO / MILLI);
+
+ indio_dev->name = "mcp47a1";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &mcp47a1_info;
+ indio_dev->channels = &mcp47a1_channel;
+ indio_dev->num_channels = 1;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id mcp47a1_of_match[] = {
+ { .compatible = "microchip,mcp47a1" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mcp47a1_of_match);
+
+static const struct i2c_device_id mcp47a1_id[] = {
+ { .name = "mcp47a1" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mcp47a1_id);
+
+static struct i2c_driver mcp47a1_driver = {
+ .driver = {
+ .name = "mcp47a1",
+ .of_match_table = mcp47a1_of_match,
+ },
+ .probe = mcp47a1_probe,
+ .id_table = mcp47a1_id,
+};
+module_i2c_driver(mcp47a1_driver);
+
+MODULE_AUTHOR("Joshua Crofts <joshua.crofts1@gmail.com>");
+MODULE_DESCRIPTION("Microchip MCP47A1 DAC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
index b218f0c3a0bd..8640b0ef4433 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -21,7 +21,6 @@
#include <linux/iio/sysfs.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -65,7 +64,7 @@
#define MCP47FEB02_MAX_SCALES_CH 3
#define MCP47FEB02_DAC_WIPER_UNLOCKED 0
#define MCP47FEB02_NORMAL_OPERATION 0
-#define MCP47FEB02_INTERNAL_BAND_GAP_mV 2440
+#define MCP47FEB02_INTERNAL_BAND_GAP_uV 2440000
#define NV_DAC_ADDR_OFFSET 0x10
enum mcp47feb02_vref_mode {
@@ -697,44 +696,40 @@ static const struct iio_chan_spec mcp47febxx_ch_template = {
};
static void mcp47feb02_init_scale(struct mcp47feb02_data *data, enum mcp47feb02_scale scale,
- int vref_mV, int scale_avail[])
+ int vref_uV, int scale_avail[])
{
u32 value_micro, value_int;
u64 tmp;
- /* vref_mV should not be negative */
- tmp = (u64)vref_mV * MICRO >> data->chip_features->resolution;
+ /* vref_uV should not be negative */
+ tmp = (u64)vref_uV * MILLI >> data->chip_features->resolution;
value_int = div_u64_rem(tmp, MICRO, &value_micro);
scale_avail[scale * 2] = value_int;
scale_avail[scale * 2 + 1] = value_micro;
}
-static int mcp47feb02_init_scales_avail(struct mcp47feb02_data *data, int vdd_mV,
- int vref_mV, int vref1_mV)
+static int mcp47feb02_init_scales_avail(struct mcp47feb02_data *data, int vdd_uV,
+ int vref_uV, int vref1_uV)
{
- struct device *dev = regmap_get_device(data->regmap);
int tmp_vref;
- mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_mV, data->scale);
+ mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_uV, data->scale);
if (data->use_vref)
- tmp_vref = vref_mV;
+ tmp_vref = vref_uV;
else
- tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_mV;
+ tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_uV;
mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X1, tmp_vref, data->scale);
mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X2, tmp_vref * 2, data->scale);
if (data->phys_channels >= 4) {
- mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_mV, data->scale_1);
-
- if (data->use_vref1 && vref1_mV <= 0)
- return dev_err_probe(dev, vref1_mV, "Invalid voltage for Vref1\n");
+ mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_uV, data->scale_1);
if (data->use_vref1)
- tmp_vref = vref1_mV;
+ tmp_vref = vref1_uV;
else
- tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_mV;
+ tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_uV;
mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X1,
tmp_vref, data->scale_1);
@@ -955,8 +950,6 @@ static int mcp47feb02_parse_fw(struct iio_dev *indio_dev,
u32 num_channels;
u8 chan_idx = 0;
- guard(mutex)(&data->lock);
-
num_channels = device_get_child_node_count(dev);
if (num_channels > chip_features->phys_channels)
return dev_err_probe(dev, -EINVAL, "More channels than the chip supports\n");
@@ -1080,8 +1073,8 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
return 0;
}
-static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_mV,
- int vref_mV, int vref1_mV)
+static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_uV,
+ int vref_uV, int vref1_uV)
{
unsigned int i;
@@ -1089,7 +1082,7 @@ static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_mV,
struct device *dev = regmap_get_device(data->regmap);
int ret;
- ret = mcp47feb02_init_scales_avail(data, vdd_mV, vref_mV, vref1_mV);
+ ret = mcp47feb02_init_scales_avail(data, vdd_uV, vref_uV, vref1_uV);
if (ret)
return dev_err_probe(dev, ret, "failed to init scales for ch %u\n", i);
}
@@ -1103,10 +1096,7 @@ static int mcp47feb02_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct mcp47feb02_data *data;
struct iio_dev *indio_dev;
- int vref1_mV = 0;
- int vref_mV = 0;
- int vdd_mV;
- int ret;
+ int vref1_uV, vref_uV, vdd_uV, ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
@@ -1143,33 +1133,42 @@ static int mcp47feb02_probe(struct i2c_client *client)
if (ret < 0)
return ret;
- vdd_mV = ret / MILLI;
+ vdd_uV = ret;
+
+ if (device_property_present(dev, "vref-supply")) {
+ vref_uV = devm_regulator_get_enable_read_voltage(dev, "vref");
+ if (vref_uV < 0)
+ return vref_uV;
+
+ if (vref_uV == 0)
+ return dev_err_probe(dev, -EINVAL, "Vref is 0 uV.\n");
- ret = devm_regulator_get_enable_read_voltage(dev, "vref");
- if (ret > 0) {
- vref_mV = ret / MILLI;
data->use_vref = true;
} else {
- dev_dbg(dev, "using internal band gap as voltage reference.\n");
- dev_dbg(dev, "Vref is unavailable.\n");
+ vref_uV = 0;
+ dev_dbg(dev, "Using internal band gap as voltage reference.\n");
}
- if (chip_features->have_ext_vref1) {
- ret = devm_regulator_get_enable_read_voltage(dev, "vref1");
- if (ret > 0) {
- vref1_mV = ret / MILLI;
- data->use_vref1 = true;
- } else {
- dev_dbg(dev, "using internal band gap as voltage reference 1.\n");
- dev_dbg(dev, "Vref1 is unavailable.\n");
- }
+ if (chip_features->have_ext_vref1 &&
+ device_property_present(dev, "vref1-supply")) {
+ vref1_uV = devm_regulator_get_enable_read_voltage(dev, "vref1");
+ if (vref1_uV < 0)
+ return vref1_uV;
+
+ if (vref1_uV == 0)
+ return dev_err_probe(dev, -EINVAL, "Vref1 is 0 uV.\n");
+
+ data->use_vref1 = true;
+ } else {
+ vref1_uV = 0;
+ dev_dbg(dev, "Using internal band gap as voltage reference 1.\n");
}
ret = mcp47feb02_init_ctrl_regs(data);
if (ret)
return dev_err_probe(dev, ret, "Error initialising vref register\n");
- ret = mcp47feb02_init_ch_scales(data, vdd_mV, vref_mV, vref1_mV);
+ ret = mcp47feb02_init_ch_scales(data, vdd_uV, vref_uV, vref1_uV);
if (ret)
return ret;
@@ -1177,30 +1176,30 @@ static int mcp47feb02_probe(struct i2c_client *client)
}
static const struct i2c_device_id mcp47feb02_id[] = {
- { "mcp47feb01", (kernel_ulong_t)&mcp47feb01_chip_features },
- { "mcp47feb02", (kernel_ulong_t)&mcp47feb02_chip_features },
- { "mcp47feb04", (kernel_ulong_t)&mcp47feb04_chip_features },
- { "mcp47feb08", (kernel_ulong_t)&mcp47feb08_chip_features },
- { "mcp47feb11", (kernel_ulong_t)&mcp47feb11_chip_features },
- { "mcp47feb12", (kernel_ulong_t)&mcp47feb12_chip_features },
- { "mcp47feb14", (kernel_ulong_t)&mcp47feb14_chip_features },
- { "mcp47feb18", (kernel_ulong_t)&mcp47feb18_chip_features },
- { "mcp47feb21", (kernel_ulong_t)&mcp47feb21_chip_features },
- { "mcp47feb22", (kernel_ulong_t)&mcp47feb22_chip_features },
- { "mcp47feb24", (kernel_ulong_t)&mcp47feb24_chip_features },
- { "mcp47feb28", (kernel_ulong_t)&mcp47feb28_chip_features },
- { "mcp47fvb01", (kernel_ulong_t)&mcp47fvb01_chip_features },
- { "mcp47fvb02", (kernel_ulong_t)&mcp47fvb02_chip_features },
- { "mcp47fvb04", (kernel_ulong_t)&mcp47fvb04_chip_features },
- { "mcp47fvb08", (kernel_ulong_t)&mcp47fvb08_chip_features },
- { "mcp47fvb11", (kernel_ulong_t)&mcp47fvb11_chip_features },
- { "mcp47fvb12", (kernel_ulong_t)&mcp47fvb12_chip_features },
- { "mcp47fvb14", (kernel_ulong_t)&mcp47fvb14_chip_features },
- { "mcp47fvb18", (kernel_ulong_t)&mcp47fvb18_chip_features },
- { "mcp47fvb21", (kernel_ulong_t)&mcp47fvb21_chip_features },
- { "mcp47fvb22", (kernel_ulong_t)&mcp47fvb22_chip_features },
- { "mcp47fvb24", (kernel_ulong_t)&mcp47fvb24_chip_features },
- { "mcp47fvb28", (kernel_ulong_t)&mcp47fvb28_chip_features },
+ { .name = "mcp47feb01", .driver_data = (kernel_ulong_t)&mcp47feb01_chip_features },
+ { .name = "mcp47feb02", .driver_data = (kernel_ulong_t)&mcp47feb02_chip_features },
+ { .name = "mcp47feb04", .driver_data = (kernel_ulong_t)&mcp47feb04_chip_features },
+ { .name = "mcp47feb08", .driver_data = (kernel_ulong_t)&mcp47feb08_chip_features },
+ { .name = "mcp47feb11", .driver_data = (kernel_ulong_t)&mcp47feb11_chip_features },
+ { .name = "mcp47feb12", .driver_data = (kernel_ulong_t)&mcp47feb12_chip_features },
+ { .name = "mcp47feb14", .driver_data = (kernel_ulong_t)&mcp47feb14_chip_features },
+ { .name = "mcp47feb18", .driver_data = (kernel_ulong_t)&mcp47feb18_chip_features },
+ { .name = "mcp47feb21", .driver_data = (kernel_ulong_t)&mcp47feb21_chip_features },
+ { .name = "mcp47feb22", .driver_data = (kernel_ulong_t)&mcp47feb22_chip_features },
+ { .name = "mcp47feb24", .driver_data = (kernel_ulong_t)&mcp47feb24_chip_features },
+ { .name = "mcp47feb28", .driver_data = (kernel_ulong_t)&mcp47feb28_chip_features },
+ { .name = "mcp47fvb01", .driver_data = (kernel_ulong_t)&mcp47fvb01_chip_features },
+ { .name = "mcp47fvb02", .driver_data = (kernel_ulong_t)&mcp47fvb02_chip_features },
+ { .name = "mcp47fvb04", .driver_data = (kernel_ulong_t)&mcp47fvb04_chip_features },
+ { .name = "mcp47fvb08", .driver_data = (kernel_ulong_t)&mcp47fvb08_chip_features },
+ { .name = "mcp47fvb11", .driver_data = (kernel_ulong_t)&mcp47fvb11_chip_features },
+ { .name = "mcp47fvb12", .driver_data = (kernel_ulong_t)&mcp47fvb12_chip_features },
+ { .name = "mcp47fvb14", .driver_data = (kernel_ulong_t)&mcp47fvb14_chip_features },
+ { .name = "mcp47fvb18", .driver_data = (kernel_ulong_t)&mcp47fvb18_chip_features },
+ { .name = "mcp47fvb21", .driver_data = (kernel_ulong_t)&mcp47fvb21_chip_features },
+ { .name = "mcp47fvb22", .driver_data = (kernel_ulong_t)&mcp47fvb22_chip_features },
+ { .name = "mcp47fvb24", .driver_data = (kernel_ulong_t)&mcp47fvb24_chip_features },
+ { .name = "mcp47fvb28", .driver_data = (kernel_ulong_t)&mcp47fvb28_chip_features },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp47feb02_id);
diff --git a/drivers/iio/dac/mcp4821.c b/drivers/iio/dac/mcp4821.c
index 748bdca9a964..8d8c00cd60e9 100644
--- a/drivers/iio/dac/mcp4821.c
+++ b/drivers/iio/dac/mcp4821.c
@@ -12,13 +12,12 @@
* MCP48x2: https://ww1.microchip.com/downloads/en/DeviceDoc/20002249B.pdf
*
* TODO:
- * - Configurable gain
* - Regulator control
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
+#include <linux/units.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
@@ -26,12 +25,32 @@
#include <linux/unaligned.h>
#define MCP4821_ACTIVE_MODE BIT(12)
+#define MCP4821_GAIN_ENABLE BIT(13)
#define MCP4802_SECOND_CHAN BIT(15)
-/* DAC uses an internal Voltage reference of 4.096V at a gain of 2x */
-#define MCP4821_2X_GAIN_VREF_MV 4096
+/* DAC uses an internal Voltage reference of 2.048V */
+#define MCP4821_VREF_MV 2048
-enum mcp4821_supported_drvice_ids {
+/*
+ * MCP48xx DAC output:
+ *
+ * Vout = (Vref * D / 2^N) * G
+ *
+ * where:
+ * - Vref = 2.048V (internal reference)
+ * - N = DAC resolution (12 bits for MCP4821)
+ * - G = gain selection:
+ * 1x when GA bit = 1
+ * 2x when GA bit = 0 (default)
+ *
+ * Therefore full-scale voltage is:
+ * - 1x gain: 2.048V
+ * - 2x gain: 4.096V
+ *
+ * Scale = Vfull-scale / 2^N
+ */
+
+enum mcp4821_supported_device_ids {
ID_MCP4801,
ID_MCP4802,
ID_MCP4811,
@@ -43,6 +62,8 @@ enum mcp4821_supported_drvice_ids {
struct mcp4821_state {
struct spi_device *spi;
u16 dac_value[2];
+ int gain;
+ int scale_avail[4];
};
struct mcp4821_chip_info {
@@ -57,6 +78,7 @@ struct mcp4821_chip_info {
.channel = (channel_id), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.realbits = (resolution), \
.shift = 12 - (resolution), \
@@ -115,15 +137,15 @@ static int mcp4821_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
- struct mcp4821_state *state;
+ struct mcp4821_state *state = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
- state = iio_priv(indio_dev);
*val = state->dac_value[chan->channel];
return IIO_VAL_INT;
+
case IIO_CHAN_INFO_SCALE:
- *val = MCP4821_2X_GAIN_VREF_MV;
+ *val = MCP4821_VREF_MV * state->gain;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
@@ -131,6 +153,17 @@ static int mcp4821_read_raw(struct iio_dev *indio_dev,
}
}
+static void mcp4821_calc_scale(int vref_mv, int resolution,
+ int *val, int *val2)
+{
+ s64 tmp;
+ int micro;
+
+ tmp = (s64)vref_mv * MICRO >> resolution;
+ *val = div_s64_rem(tmp, MICRO, &micro);
+ *val2 = micro;
+}
+
static int mcp4821_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
@@ -139,35 +172,85 @@ static int mcp4821_write_raw(struct iio_dev *indio_dev,
u16 write_val;
__be16 write_buffer;
int ret;
+ int v, v2;
- if (val2 != 0)
- return -EINVAL;
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
- if (val < 0 || val >= BIT(chan->scan_type.realbits))
- return -EINVAL;
+ if (val2 != 0)
+ return -EINVAL;
- if (mask != IIO_CHAN_INFO_RAW)
- return -EINVAL;
+ if (val < 0 || val >= BIT(chan->scan_type.realbits))
+ return -EINVAL;
- write_val = MCP4821_ACTIVE_MODE | val << chan->scan_type.shift;
- if (chan->channel)
- write_val |= MCP4802_SECOND_CHAN;
+ write_val = MCP4821_ACTIVE_MODE | val << chan->scan_type.shift;
+ if (chan->channel)
+ write_val |= MCP4802_SECOND_CHAN;
- write_buffer = cpu_to_be16(write_val);
- ret = spi_write(state->spi, &write_buffer, sizeof(write_buffer));
- if (ret) {
- dev_err(&state->spi->dev, "Failed to write to device: %d", ret);
- return ret;
+ /* GA bit = 1 -> 1x gain */
+ if (state->gain == 1)
+ write_val |= MCP4821_GAIN_ENABLE;
+
+ write_buffer = cpu_to_be16(write_val);
+ ret = spi_write(state->spi, &write_buffer, sizeof(write_buffer));
+ if (ret) {
+ dev_err(&state->spi->dev, "Failed to write to device: %d", ret);
+ return ret;
+ }
+
+ state->dac_value[chan->channel] = val;
+ return 0;
+
+ case IIO_CHAN_INFO_SCALE:
+ mcp4821_calc_scale(MCP4821_VREF_MV, chan->scan_type.realbits, &v, &v2);
+ if (val == v && val2 == v2) {
+ state->gain = 1;
+ return 0;
+ }
+
+ mcp4821_calc_scale(MCP4821_VREF_MV * 2,
+ chan->scan_type.realbits, &v, &v2);
+ if (val == v && val2 == v2) {
+ state->gain = 2;
+ return 0;
+ }
+ return -EINVAL;
+ default:
+ return -EINVAL;
}
+}
- state->dac_value[chan->channel] = val;
+static inline void mcp4821_init_avail_gain(struct mcp4821_state *state,
+ int resolution)
+{
+ state->scale_avail[0] = MCP4821_VREF_MV;
+ state->scale_avail[1] = resolution;
+ state->scale_avail[2] = MCP4821_VREF_MV * 2;
+ state->scale_avail[3] = resolution;
+}
+
+static int mcp4821_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
+{
+ struct mcp4821_state *state = iio_priv(indio_dev);
- return 0;
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = state->scale_avail;
+ *type = IIO_VAL_FRACTIONAL_LOG2;
+ *length = ARRAY_SIZE(state->scale_avail);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
}
static const struct iio_info mcp4821_info = {
.read_raw = &mcp4821_read_raw,
.write_raw = &mcp4821_write_raw,
+ .read_avail = &mcp4821_read_avail,
};
static int mcp4821_probe(struct spi_device *spi)
@@ -183,12 +266,15 @@ static int mcp4821_probe(struct spi_device *spi)
state = iio_priv(indio_dev);
state->spi = spi;
+ /* default gain is 2x */
+ state->gain = 2;
info = spi_get_device_match_data(spi);
indio_dev->name = info->name;
indio_dev->info = &mcp4821_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = info->channels;
indio_dev->num_channels = info->num_channels;
+ mcp4821_init_avail_gain(state, info->channels[0].scan_type.realbits);
return devm_iio_device_register(&spi->dev, indio_dev);
}
@@ -211,12 +297,12 @@ static const struct of_device_id mcp4821_of_table[] = {
MODULE_DEVICE_TABLE(of, mcp4821_of_table);
static const struct spi_device_id mcp4821_id_table[] = {
- { "mcp4801", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4801]},
- { "mcp4802", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4802]},
- { "mcp4811", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4811]},
- { "mcp4812", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4812]},
- { "mcp4821", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4821]},
- { "mcp4822", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4822]},
+ { .name = "mcp4801", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4801] },
+ { .name = "mcp4802", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4802] },
+ { .name = "mcp4811", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4811] },
+ { .name = "mcp4812", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4812] },
+ { .name = "mcp4821", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4821] },
+ { .name = "mcp4822", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4822] },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp4821_id_table);
diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c
index 74f338afcab9..15072a9081ff 100644
--- a/drivers/iio/dac/mcp4922.c
+++ b/drivers/iio/dac/mcp4922.c
@@ -157,10 +157,10 @@ static int mcp4922_probe(struct spi_device *spi)
static const struct spi_device_id mcp4922_id[] = {
- {"mcp4902", ID_MCP4902},
- {"mcp4912", ID_MCP4912},
- {"mcp4921", ID_MCP4921},
- {"mcp4922", ID_MCP4922},
+ { .name = "mcp4902", .driver_data = ID_MCP4902 },
+ { .name = "mcp4912", .driver_data = ID_MCP4912 },
+ { .name = "mcp4921", .driver_data = ID_MCP4921 },
+ { .name = "mcp4922", .driver_data = ID_MCP4922 },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp4922_id);
diff --git a/drivers/iio/dac/rohm-bd79703.c b/drivers/iio/dac/rohm-bd79703.c
index e91090e4a66d..6e2e7787f8a4 100644
--- a/drivers/iio/dac/rohm-bd79703.c
+++ b/drivers/iio/dac/rohm-bd79703.c
@@ -214,10 +214,10 @@ static int bd79703_probe(struct spi_device *spi)
}
static const struct spi_device_id bd79703_id[] = {
- { "bd79700", (kernel_ulong_t)&bd79700_chip_data },
- { "bd79701", (kernel_ulong_t)&bd79701_chip_data },
- { "bd79702", (kernel_ulong_t)&bd79702_chip_data },
- { "bd79703", (kernel_ulong_t)&bd79703_chip_data },
+ { .name = "bd79700", .driver_data = (kernel_ulong_t)&bd79700_chip_data },
+ { .name = "bd79701", .driver_data = (kernel_ulong_t)&bd79701_chip_data },
+ { .name = "bd79702", .driver_data = (kernel_ulong_t)&bd79702_chip_data },
+ { .name = "bd79703", .driver_data = (kernel_ulong_t)&bd79703_chip_data },
{ }
};
MODULE_DEVICE_TABLE(spi, bd79703_id);
diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c
index 8ef702917060..b5795c14f0fe 100644
--- a/drivers/iio/dac/stm32-dac-core.c
+++ b/drivers/iio/dac/stm32-dac-core.c
@@ -9,7 +9,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
index b860e18d52a1..99438f6d4700 100644
--- a/drivers/iio/dac/stm32-dac.c
+++ b/drivers/iio/dac/stm32-dac.c
@@ -13,7 +13,6 @@
#include <linux/kernel.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/iio/dac/ti-dac082s085.c b/drivers/iio/dac/ti-dac082s085.c
index 715870c8a9c4..afa7d9bad5de 100644
--- a/drivers/iio/dac/ti-dac082s085.c
+++ b/drivers/iio/dac/ti-dac082s085.c
@@ -14,7 +14,6 @@
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
@@ -335,12 +334,12 @@ static const struct of_device_id ti_dac_of_id[] = {
MODULE_DEVICE_TABLE(of, ti_dac_of_id);
static const struct spi_device_id ti_dac_spi_id[] = {
- { "dac082s085", dual_8bit },
- { "dac102s085", dual_10bit },
- { "dac122s085", dual_12bit },
- { "dac084s085", quad_8bit },
- { "dac104s085", quad_10bit },
- { "dac124s085", quad_12bit },
+ { .name = "dac082s085", .driver_data = dual_8bit },
+ { .name = "dac102s085", .driver_data = dual_10bit },
+ { .name = "dac122s085", .driver_data = dual_12bit },
+ { .name = "dac084s085", .driver_data = quad_8bit },
+ { .name = "dac104s085", .driver_data = quad_10bit },
+ { .name = "dac124s085", .driver_data = quad_12bit },
{ }
};
MODULE_DEVICE_TABLE(spi, ti_dac_spi_id);
diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c
index bdc3f94aef98..78fd5fa42db6 100644
--- a/drivers/iio/dac/ti-dac5571.c
+++ b/drivers/iio/dac/ti-dac5571.c
@@ -20,7 +20,6 @@
#include <linux/iio/iio.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
@@ -45,7 +44,6 @@ static const struct dac5571_spec dac5571_spec[] = {
struct dac5571_data {
struct i2c_client *client;
- int id;
struct mutex lock;
struct regulator *vref;
u16 val[4];
@@ -403,17 +401,17 @@ static const struct of_device_id dac5571_of_id[] = {
MODULE_DEVICE_TABLE(of, dac5571_of_id);
static const struct i2c_device_id dac5571_id[] = {
- {"dac081c081", (kernel_ulong_t)&dac5571_spec[single_8bit] },
- {"dac121c081", (kernel_ulong_t)&dac5571_spec[single_12bit] },
- {"dac5571", (kernel_ulong_t)&dac5571_spec[single_8bit] },
- {"dac6571", (kernel_ulong_t)&dac5571_spec[single_10bit] },
- {"dac7571", (kernel_ulong_t)&dac5571_spec[single_12bit] },
- {"dac5574", (kernel_ulong_t)&dac5571_spec[quad_8bit] },
- {"dac6574", (kernel_ulong_t)&dac5571_spec[quad_10bit] },
- {"dac7574", (kernel_ulong_t)&dac5571_spec[quad_12bit] },
- {"dac5573", (kernel_ulong_t)&dac5571_spec[quad_8bit] },
- {"dac6573", (kernel_ulong_t)&dac5571_spec[quad_10bit] },
- {"dac7573", (kernel_ulong_t)&dac5571_spec[quad_12bit] },
+ { .name = "dac081c081", .driver_data = (kernel_ulong_t)&dac5571_spec[single_8bit] },
+ { .name = "dac121c081", .driver_data = (kernel_ulong_t)&dac5571_spec[single_12bit] },
+ { .name = "dac5571", .driver_data = (kernel_ulong_t)&dac5571_spec[single_8bit] },
+ { .name = "dac6571", .driver_data = (kernel_ulong_t)&dac5571_spec[single_10bit] },
+ { .name = "dac7571", .driver_data = (kernel_ulong_t)&dac5571_spec[single_12bit] },
+ { .name = "dac5574", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_8bit] },
+ { .name = "dac6574", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_10bit] },
+ { .name = "dac7574", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_12bit] },
+ { .name = "dac5573", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_8bit] },
+ { .name = "dac6573", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_10bit] },
+ { .name = "dac7573", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_12bit] },
{ }
};
MODULE_DEVICE_TABLE(i2c, dac5571_id);
diff --git a/drivers/iio/dac/ti-dac7311.c b/drivers/iio/dac/ti-dac7311.c
index 5c1c5213962f..e5843bd35259 100644
--- a/drivers/iio/dac/ti-dac7311.c
+++ b/drivers/iio/dac/ti-dac7311.c
@@ -311,9 +311,9 @@ static const struct of_device_id ti_dac_of_id[] = {
MODULE_DEVICE_TABLE(of, ti_dac_of_id);
static const struct spi_device_id ti_dac_spi_id[] = {
- { "dac5311", ID_DAC5311 },
- { "dac6311", ID_DAC6311 },
- { "dac7311", ID_DAC7311 },
+ { .name = "dac5311", .driver_data = ID_DAC5311 },
+ { .name = "dac6311", .driver_data = ID_DAC6311 },
+ { .name = "dac7311", .driver_data = ID_DAC7311 },
{ }
};
MODULE_DEVICE_TABLE(spi, ti_dac_spi_id);
diff --git a/drivers/iio/dac/ti-dac7612.c b/drivers/iio/dac/ti-dac7612.c
index c308eca02b88..9065663cd609 100644
--- a/drivers/iio/dac/ti-dac7612.c
+++ b/drivers/iio/dac/ti-dac7612.c
@@ -165,7 +165,7 @@ static int dac7612_probe(struct spi_device *spi)
}
static const struct spi_device_id dac7612_id[] = {
- {"ti-dac7612"},
+ { .name = "ti-dac7612" },
{ }
};
MODULE_DEVICE_TABLE(spi, dac7612_id);
diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c
index 93639599b2b9..3aa22fecd308 100644
--- a/drivers/iio/dac/vf610_dac.c
+++ b/drivers/iio/dac/vf610_dac.c
@@ -10,7 +10,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
diff --git a/drivers/iio/filter/admv8818.c b/drivers/iio/filter/admv8818.c
index 19f823446cda..b88689e60cc8 100644
--- a/drivers/iio/filter/admv8818.c
+++ b/drivers/iio/filter/admv8818.c
@@ -11,7 +11,6 @@
#include <linux/device.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/property.h>
@@ -657,56 +656,49 @@ static void admv8818_clk_disable(void *data)
static int admv8818_init(struct admv8818_state *st)
{
int ret;
- struct spi_device *spi = st->spi;
+ struct device *dev = &st->spi->dev;
unsigned int chip_id;
ret = regmap_write(st->regmap, ADMV8818_REG_SPI_CONFIG_A,
ADMV8818_SOFTRESET_N_MSK | ADMV8818_SOFTRESET_MSK);
- if (ret) {
- dev_err(&spi->dev, "ADMV8818 Soft Reset failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "ADMV8818 Soft Reset failed.\n");
ret = regmap_write(st->regmap, ADMV8818_REG_SPI_CONFIG_A,
ADMV8818_SDOACTIVE_N_MSK | ADMV8818_SDOACTIVE_MSK);
- if (ret) {
- dev_err(&spi->dev, "ADMV8818 SDO Enable failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "ADMV8818 SDO Enable failed.\n");
ret = regmap_read(st->regmap, ADMV8818_REG_CHIPTYPE, &chip_id);
- if (ret) {
- dev_err(&spi->dev, "ADMV8818 Chip ID read failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "ADMV8818 Chip ID read failed.\n");
- if (chip_id != 0x1) {
- dev_err(&spi->dev, "ADMV8818 Invalid Chip ID.\n");
- return -EINVAL;
- }
+ if (chip_id != 0x1)
+ return dev_err_probe(dev, -EINVAL,
+ "ADMV8818 Invalid Chip ID.\n");
ret = regmap_update_bits(st->regmap, ADMV8818_REG_SPI_CONFIG_B,
ADMV8818_SINGLE_INSTRUCTION_MSK,
FIELD_PREP(ADMV8818_SINGLE_INSTRUCTION_MSK, 1));
- if (ret) {
- dev_err(&spi->dev, "ADMV8818 Single Instruction failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "ADMV8818 Single Instruction failed.\n");
if (st->clkin)
return admv8818_rfin_band_select(st);
- else
- return 0;
+
+ return 0;
}
static int admv8818_clk_setup(struct admv8818_state *st)
{
- struct spi_device *spi = st->spi;
+ struct device *dev = &st->spi->dev;
int ret;
- st->clkin = devm_clk_get_optional(&spi->dev, "rf_in");
+ st->clkin = devm_clk_get_optional(dev, "rf_in");
if (IS_ERR(st->clkin))
- return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
+ return dev_err_probe(dev, PTR_ERR(st->clkin),
"failed to get the input clock\n");
else if (!st->clkin)
return 0;
@@ -715,7 +707,7 @@ static int admv8818_clk_setup(struct admv8818_state *st)
if (ret)
return ret;
- ret = devm_add_action_or_reset(&spi->dev, admv8818_clk_disable, st);
+ ret = devm_add_action_or_reset(dev, admv8818_clk_disable, st);
if (ret)
return ret;
@@ -724,16 +716,16 @@ static int admv8818_clk_setup(struct admv8818_state *st)
if (ret < 0)
return ret;
- return devm_add_action_or_reset(&spi->dev, admv8818_clk_notifier_unreg, st);
+ return devm_add_action_or_reset(dev, admv8818_clk_notifier_unreg, st);
}
static int admv8818_read_properties(struct admv8818_state *st)
{
- struct spi_device *spi = st->spi;
+ struct device *dev = &st->spi->dev;
u32 mhz;
int ret;
- ret = device_property_read_u32(&spi->dev, "adi,lpf-margin-mhz", &mhz);
+ ret = device_property_read_u32(dev, "adi,lpf-margin-mhz", &mhz);
if (ret == 0)
st->lpf_margin_hz = (u64)mhz * HZ_PER_MHZ;
else if (ret == -EINVAL)
@@ -742,7 +734,7 @@ static int admv8818_read_properties(struct admv8818_state *st)
return ret;
- ret = device_property_read_u32(&spi->dev, "adi,hpf-margin-mhz", &mhz);
+ ret = device_property_read_u32(dev, "adi,hpf-margin-mhz", &mhz);
if (ret == 0)
st->hpf_margin_hz = (u64)mhz * HZ_PER_MHZ;
else if (ret == -EINVAL)
@@ -758,9 +750,10 @@ static int admv8818_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
struct regmap *regmap;
struct admv8818_state *st;
+ struct device *dev = &spi->dev;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -792,11 +785,11 @@ static int admv8818_probe(struct spi_device *spi)
if (ret)
return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id admv8818_id[] = {
- { "admv8818", 0 },
+ { .name = "admv8818" },
{ }
};
MODULE_DEVICE_TABLE(spi, admv8818_id);
diff --git a/drivers/iio/flow/Kconfig b/drivers/iio/flow/Kconfig
new file mode 100644
index 000000000000..e0e1a8e3654a
--- /dev/null
+++ b/drivers/iio/flow/Kconfig
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Liquid / gas flow sensor drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Flow sensors"
+
+config SENSIRION_SLF3S
+ tristate "Sensirion SLF3S liquid flow sensor"
+ depends on I2C
+ select CRC8
+ help
+ Say yes here to build support for the Sensirion SLF3S family of
+ digital liquid-flow sensors (SLF3S-0600F, SLF3S-1300F and
+ SLF3S-4000B). The driver reports the volumetric flow rate and the
+ embedded temperature reading via the standard IIO interface.
+
+ To compile this driver as a module, choose M here: the module
+ will be called slf3s.
+
+endmenu
diff --git a/drivers/iio/flow/Makefile b/drivers/iio/flow/Makefile
new file mode 100644
index 000000000000..3cf4ab95c69c
--- /dev/null
+++ b/drivers/iio/flow/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for industrial I/O flow sensor drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_SENSIRION_SLF3S) += slf3s.o
diff --git a/drivers/iio/flow/slf3s.c b/drivers/iio/flow/slf3s.c
new file mode 100644
index 000000000000..dfa7c1409045
--- /dev/null
+++ b/drivers/iio/flow/slf3s.c
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sensirion SLF3S liquid flow sensor driver.
+ *
+ * Supports the SLF3S-0600F, SLF3S-1300F and SLF3S-4000B liquid-flow
+ * sensors over I2C. Each measurement frame returns a 16-bit signed
+ * flow value, a 16-bit signed temperature value and a status word,
+ * each protected by a CRC-8 byte.
+ *
+ * The active calibration medium (water or isopropyl alcohol) is
+ * runtime-switchable via the in_volumeflow_medium sysfs attribute and
+ * defaults to water.
+ *
+ * Datasheet: https://sensirion.com/products/catalog/SLF3S-0600F/
+ *
+ * Copyright (C) 2026 CMBlu Energy GmbH
+ * Author: Wadim Mueller <wafgo01@gmail.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/math.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+
+#define SLF3S_CRC8_POLY 0x31
+#define SLF3S_CRC8_INIT 0xff
+
+#define SLF3S_PRODUCT_ID_LEN 18
+#define SLF3S_PRODUCT_FAMILY_BYTE 1
+#define SLF3S_PRODUCT_SUBTYPE_BYTE 3
+#define SLF3S_PRODUCT_FAMILY_ID 0x03
+
+/* Datasheet section 2.2: tPU = 25 ms max from power-on to first cmd. */
+#define SLF3S_POWER_UP_DELAY_US (25 * USEC_PER_MSEC)
+/* Datasheet section 2.2: tw = 60 ms typical until first valid sample. */
+#define SLF3S_MEAS_START_DELAY_US (60 * USEC_PER_MSEC)
+
+static const u8 slf3s_cmd_prep_pid[] = { 0x36, 0x7c };
+static const u8 slf3s_cmd_read_pid[] = { 0xe1, 0x02 };
+static const u8 slf3s_cmd_start_water[] = { 0x36, 0x08 };
+static const u8 slf3s_cmd_start_ipa[] = { 0x36, 0x15 };
+static const u8 slf3s_cmd_stop_meas[] = { 0x3f, 0xf9 };
+
+enum slf3s_medium {
+ SLF3S_MEDIUM_WATER,
+ SLF3S_MEDIUM_IPA,
+};
+
+static const char * const slf3s_medium_modes[] = {
+ [SLF3S_MEDIUM_WATER] = "water",
+ [SLF3S_MEDIUM_IPA] = "ipa",
+};
+
+enum slf3s_variant_id {
+ SLF3S_0600F,
+ SLF3S_1300F,
+ SLF3S_4000B,
+};
+
+/**
+ * struct slf3s_variant - per-variant calibration constants
+ * @sub_type: product-info sub-type byte returned by the sensor
+ * @name: name reported via @iio_dev.name
+ * @scale: flow scale in l/s per LSB
+ */
+struct slf3s_variant {
+ u8 sub_type;
+ const char *name;
+ struct s32_fract scale;
+};
+
+static const struct slf3s_variant slf3s_variants[] = {
+ [SLF3S_0600F] = {
+ .sub_type = 0x03,
+ .name = "slf3s-0600f",
+ .scale = { .numerator = 1, .denominator = 600 * MICRO },
+ },
+ [SLF3S_1300F] = {
+ .sub_type = 0x02,
+ .name = "slf3s-1300f",
+ .scale = { .numerator = 1, .denominator = 30 * MICRO },
+ },
+ [SLF3S_4000B] = {
+ .sub_type = 0x05,
+ .name = "slf3s-4000b",
+ .scale = { .numerator = 1, .denominator = 1920 * MILLI },
+ },
+};
+
+/**
+ * struct slf3s_data - per-device state
+ * @client: I2C client this instance is bound to
+ * @vdd: supply regulator, disabled while suspended
+ * @variant: pointer into @slf3s_variants for the detected device
+ * @medium: currently active calibration medium
+ * @lock: serialises the multi-step command/response exchanges
+ * @crc_table: pre-computed CRC-8 lookup table for SLF3S_CRC8_POLY
+ */
+struct slf3s_data {
+ struct i2c_client *client;
+ struct regulator *vdd;
+ const struct slf3s_variant *variant;
+ enum slf3s_medium medium;
+ struct mutex lock;
+ u8 crc_table[CRC8_TABLE_SIZE];
+};
+
+static int slf3s_send_cmd(struct i2c_client *client, const u8 *cmd)
+{
+ int ret;
+
+ ret = i2c_master_send(client, cmd, 2);
+ if (ret < 0)
+ return ret;
+ if (ret != 2)
+ return -EIO;
+
+ return 0;
+}
+
+/* Start continuous measurement and wait until the first sample is valid. */
+static int slf3s_start_meas(struct slf3s_data *sf, enum slf3s_medium medium)
+{
+ const u8 *cmd = (medium == SLF3S_MEDIUM_IPA) ? slf3s_cmd_start_ipa
+ : slf3s_cmd_start_water;
+ int ret;
+
+ ret = slf3s_send_cmd(sf->client, cmd);
+ if (ret)
+ return ret;
+
+ fsleep(SLF3S_MEAS_START_DELAY_US);
+
+ return 0;
+}
+
+static bool slf3s_crc_valid(const struct slf3s_data *sf, const u8 *block)
+{
+ return crc8(sf->crc_table, block, 2, SLF3S_CRC8_INIT) == block[2];
+}
+
+/*
+ * Read the product-info block and pick the matching variant. The
+ * sub-type byte returned by the sensor is the source of truth; a
+ * DT-supplied compatible only seeds an initial guess and is overridden
+ * on mismatch (with an informational message so misconfigured device
+ * trees are easy to spot).
+ *
+ * Bus / CRC failures are real errors and fail probe. An unknown
+ * sub-type byte falls back to the variant named in the device tree /
+ * I2C table, so a drop-in replacement part that lists one of the known
+ * compatibles keeps working on an older kernel that does not know its
+ * sub-type yet. Without any match data probe fails since no
+ * meaningful scale can be published.
+ */
+static int slf3s_detect_variant(struct slf3s_data *sf)
+{
+ struct i2c_client *client = sf->client;
+ u8 buf[SLF3S_PRODUCT_ID_LEN];
+ int ret;
+
+ ret = slf3s_send_cmd(client, slf3s_cmd_prep_pid);
+ if (ret)
+ return ret;
+
+ ret = slf3s_send_cmd(client, slf3s_cmd_read_pid);
+ if (ret)
+ return ret;
+
+ ret = i2c_master_recv(client, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(buf))
+ return -EIO;
+
+ for (unsigned int i = 0; i < SLF3S_PRODUCT_ID_LEN; i += 3) {
+ if (!slf3s_crc_valid(sf, &buf[i]))
+ return -EIO;
+ }
+
+ if (buf[SLF3S_PRODUCT_FAMILY_BYTE] != SLF3S_PRODUCT_FAMILY_ID)
+ dev_info(&client->dev,
+ "unexpected family byte 0x%02x (expected 0x%02x)\n",
+ buf[SLF3S_PRODUCT_FAMILY_BYTE],
+ SLF3S_PRODUCT_FAMILY_ID);
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(slf3s_variants); i++) {
+ if (buf[SLF3S_PRODUCT_SUBTYPE_BYTE] !=
+ slf3s_variants[i].sub_type)
+ continue;
+
+ if (sf->variant && sf->variant != &slf3s_variants[i])
+ dev_info(&client->dev,
+ "DT compatible says %s but sensor reports %s; using the latter\n",
+ sf->variant->name,
+ slf3s_variants[i].name);
+
+ sf->variant = &slf3s_variants[i];
+
+ return 0;
+ }
+
+ if (sf->variant) {
+ dev_warn(&client->dev,
+ "unknown SLF3S sub-type 0x%02x, assuming %s\n",
+ buf[SLF3S_PRODUCT_SUBTYPE_BYTE], sf->variant->name);
+ return 0;
+ }
+
+ dev_err(&client->dev, "unknown SLF3S sub-type 0x%02x\n",
+ buf[SLF3S_PRODUCT_SUBTYPE_BYTE]);
+
+ return -ENODEV;
+}
+
+static int slf3s_read_sample(struct slf3s_data *sf, int *flow, int *temp)
+{
+ /*
+ * A measurement frame is flow, temperature and a signaling-flags
+ * word, each followed by a CRC byte. Only flow and temperature are
+ * used, so the read is stopped after their two words (6 bytes).
+ */
+ u8 buf[6];
+ int ret;
+
+ ret = i2c_master_recv(sf->client, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(buf))
+ return -EIO;
+
+ for (unsigned int i = 0; i < sizeof(buf); i += 3) {
+ if (!slf3s_crc_valid(sf, &buf[i]))
+ return -EIO;
+ }
+
+ *flow = sign_extend32(get_unaligned_be16(&buf[0]), 15);
+ *temp = sign_extend32(get_unaligned_be16(&buf[3]), 15);
+
+ return 0;
+}
+
+static int slf3s_get_medium(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct slf3s_data *sf = iio_priv(indio_dev);
+
+ return sf->medium;
+}
+
+static int slf3s_set_medium(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, unsigned int mode)
+{
+ struct slf3s_data *sf = iio_priv(indio_dev);
+ int ret;
+
+ guard(mutex)(&sf->lock);
+
+ ret = slf3s_send_cmd(sf->client, slf3s_cmd_stop_meas);
+ if (ret)
+ return ret;
+
+ ret = slf3s_start_meas(sf, mode);
+ if (ret) {
+ /*
+ * Try to restart with the previous medium so the sensor is
+ * not left idle, which would fail all subsequent reads.
+ */
+ if (slf3s_start_meas(sf, sf->medium))
+ dev_warn(&sf->client->dev,
+ "failed to restart measurement, reads will fail until a medium is set\n");
+ return ret;
+ }
+
+ sf->medium = mode;
+
+ return 0;
+}
+
+static const struct iio_enum slf3s_medium_enum = {
+ .items = slf3s_medium_modes,
+ .num_items = ARRAY_SIZE(slf3s_medium_modes),
+ .get = slf3s_get_medium,
+ .set = slf3s_set_medium,
+};
+
+static const struct iio_chan_spec_ext_info slf3s_ext_info[] = {
+ IIO_ENUM("medium", IIO_SHARED_BY_TYPE, &slf3s_medium_enum),
+ IIO_ENUM_AVAILABLE("medium", IIO_SHARED_BY_TYPE, &slf3s_medium_enum),
+ { }
+};
+
+static const struct iio_chan_spec slf3s_channels[] = {
+ {
+ .type = IIO_VOLUMEFLOW,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .ext_info = slf3s_ext_info,
+ },
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+static int slf3s_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct slf3s_data *sf = iio_priv(indio_dev);
+ int flow, temp, ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ scoped_guard(mutex, &sf->lock)
+ ret = slf3s_read_sample(sf, &flow, &temp);
+ if (ret)
+ return ret;
+
+ *val = (chan->type == IIO_VOLUMEFLOW) ? flow : temp;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type == IIO_VOLUMEFLOW) {
+ /*
+ * The variant scale is the flow per LSB in l/s, but
+ * IIO reports volume flow in m^3/s (1 l = 1e-3 m^3).
+ * These values are tiny (~1.67e-12 m^3/s for the
+ * SLF3S-0600F), so emit a 64-bit fixed-point value with
+ * femto (1e-15) resolution to preserve precision.
+ * Converting l/s to m^3/s (/ MILLI) and scaling to femto
+ * (* FEMTO) leaves a net * (FEMTO / MILLI) factor.
+ */
+ const struct slf3s_variant *v = sf->variant;
+ s64 num = (s64)v->scale.numerator * (FEMTO / MILLI);
+ s64 scale = DIV_S64_ROUND_CLOSEST(num,
+ v->scale.denominator);
+
+ iio_val_s64_decompose(scale, val, val2);
+
+ return IIO_VAL_DECIMAL64_FEMTO;
+ }
+ /* Temperature LSB = 1/200 degC; IIO_TEMP wants milli-degC. */
+ *val = MILLIDEGREE_PER_DEGREE / 200;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info slf3s_info = {
+ .read_raw = slf3s_read_raw,
+};
+
+static void slf3s_stop_meas(void *data)
+{
+ struct slf3s_data *sf = data;
+
+ slf3s_send_cmd(sf->client, slf3s_cmd_stop_meas);
+}
+
+static void slf3s_disable_vdd(void *data)
+{
+ struct slf3s_data *sf = data;
+
+ regulator_disable(sf->vdd);
+}
+
+static int slf3s_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct iio_dev *indio_dev;
+ struct slf3s_data *sf;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*sf));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ sf = iio_priv(indio_dev);
+ sf->client = client;
+ i2c_set_clientdata(client, indio_dev);
+ sf->variant = i2c_get_match_data(client);
+ sf->medium = SLF3S_MEDIUM_WATER;
+ crc8_populate_msb(sf->crc_table, SLF3S_CRC8_POLY);
+
+ ret = devm_mutex_init(dev, &sf->lock);
+ if (ret)
+ return ret;
+
+ sf->vdd = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(sf->vdd))
+ return dev_err_probe(dev, PTR_ERR(sf->vdd),
+ "failed to get vdd supply\n");
+
+ ret = regulator_enable(sf->vdd);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable vdd supply\n");
+
+ ret = devm_add_action_or_reset(dev, slf3s_disable_vdd, sf);
+ if (ret)
+ return ret;
+
+ fsleep(SLF3S_POWER_UP_DELAY_US);
+
+ /*
+ * The sensor may still be in continuous measurement mode from a
+ * previous boot (warm reboot / kexec); in that case it would NACK
+ * the product-id command below. Stop it first and ignore the error
+ * if it was already idle.
+ */
+ slf3s_send_cmd(client, slf3s_cmd_stop_meas);
+
+ ret = slf3s_detect_variant(sf);
+ if (ret)
+ return dev_err_probe(dev, ret, "product info read failed\n");
+
+ ret = slf3s_start_meas(sf, sf->medium);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to start measurement\n");
+
+ ret = devm_add_action_or_reset(dev, slf3s_stop_meas, sf);
+ if (ret)
+ return ret;
+
+ indio_dev->name = sf->variant->name;
+ indio_dev->channels = slf3s_channels;
+ indio_dev->num_channels = ARRAY_SIZE(slf3s_channels);
+ indio_dev->info = &slf3s_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+/*
+ * The sensor has no low-power state of its own, so stop the measurement
+ * and cut the supply while suspended. Resume powers it back up, waits
+ * out the power-up time and restarts with the medium that was active
+ * before.
+ */
+static int slf3s_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct slf3s_data *sf = iio_priv(indio_dev);
+ int ret;
+
+ guard(mutex)(&sf->lock);
+
+ ret = slf3s_send_cmd(sf->client, slf3s_cmd_stop_meas);
+ if (ret)
+ return ret;
+
+ return regulator_disable(sf->vdd);
+}
+
+static int slf3s_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct slf3s_data *sf = iio_priv(indio_dev);
+ int ret;
+
+ guard(mutex)(&sf->lock);
+
+ ret = regulator_enable(sf->vdd);
+ if (ret)
+ return ret;
+
+ fsleep(SLF3S_POWER_UP_DELAY_US);
+
+ return slf3s_start_meas(sf, sf->medium);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(slf3s_pm_ops, slf3s_suspend, slf3s_resume);
+
+static const struct i2c_device_id slf3s_id[] = {
+ {
+ .name = "slf3s-0600f",
+ .driver_data = (kernel_ulong_t)&slf3s_variants[SLF3S_0600F],
+ },
+ {
+ .name = "slf3s-1300f",
+ .driver_data = (kernel_ulong_t)&slf3s_variants[SLF3S_1300F],
+ },
+ {
+ .name = "slf3s-4000b",
+ .driver_data = (kernel_ulong_t)&slf3s_variants[SLF3S_4000B],
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, slf3s_id);
+
+static const struct of_device_id slf3s_of_match[] = {
+ {
+ .compatible = "sensirion,slf3s-0600f",
+ .data = &slf3s_variants[SLF3S_0600F],
+ },
+ {
+ .compatible = "sensirion,slf3s-1300f",
+ .data = &slf3s_variants[SLF3S_1300F],
+ },
+ {
+ .compatible = "sensirion,slf3s-4000b",
+ .data = &slf3s_variants[SLF3S_4000B],
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, slf3s_of_match);
+
+static struct i2c_driver slf3s_driver = {
+ .driver = {
+ .name = "slf3s",
+ .of_match_table = slf3s_of_match,
+ .pm = pm_sleep_ptr(&slf3s_pm_ops),
+ },
+ .probe = slf3s_probe,
+ .id_table = slf3s_id,
+};
+module_i2c_driver(slf3s_driver);
+
+MODULE_AUTHOR("Wadim Mueller <wafgo01@gmail.com>");
+MODULE_DESCRIPTION("Sensirion SLF3S liquid flow sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig
index 583cbdf4e8cd..90c6304c4bcd 100644
--- a/drivers/iio/frequency/Kconfig
+++ b/drivers/iio/frequency/Kconfig
@@ -29,6 +29,16 @@ endmenu
menu "Phase-Locked Loop (PLL) frequency synthesizers"
+config ADF41513
+ tristate "Analog Devices ADF41513 PLL Frequency Synthesizer"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices ADF41513
+ 26.5 GHz Integer-N/Fractional-N PLL Frequency Synthesizer.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adf41513.
+
config ADF4350
tristate "Analog Devices ADF4350/ADF4351 Wideband Synthesizers"
depends on SPI
diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile
index 70d0e0b70e80..53b4d01414d8 100644
--- a/drivers/iio/frequency/Makefile
+++ b/drivers/iio/frequency/Makefile
@@ -5,6 +5,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD9523) += ad9523.o
+obj-$(CONFIG_ADF41513) += adf41513.o
obj-$(CONFIG_ADF4350) += adf4350.o
obj-$(CONFIG_ADF4371) += adf4371.o
obj-$(CONFIG_ADF4377) += adf4377.o
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index 63c485e9e44c..1e393f40a8c8 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -167,9 +167,9 @@
/* AD9523_CHANNEL_CLOCK_DIST */
#define AD9523_CLK_DIST_DIV_PHASE(x) (((x) & 0x3F) << 18)
-#define AD9523_CLK_DIST_DIV_PHASE_REV(x) ((ret >> 18) & 0x3F)
+#define AD9523_CLK_DIST_DIV_PHASE_REV(x) (((x) >> 18) & 0x3F)
#define AD9523_CLK_DIST_DIV(x) ((((x) - 1) & 0x3FF) << 8)
-#define AD9523_CLK_DIST_DIV_REV(x) (((ret >> 8) & 0x3FF) + 1)
+#define AD9523_CLK_DIST_DIV_REV(x) ((((x) >> 8) & 0x3FF) + 1)
#define AD9523_CLK_DIST_INV_DIV_OUTPUT_EN (1 << 7)
#define AD9523_CLK_DIST_IGNORE_SYNC_EN (1 << 6)
#define AD9523_CLK_DIST_PWR_DOWN_EN (1 << 5)
@@ -558,55 +558,35 @@ static ssize_t ad9523_show(struct device *dev,
return ret;
}
-static IIO_DEVICE_ATTR(pll1_locked, S_IRUGO,
- ad9523_show,
- NULL,
- AD9523_STAT_PLL1_LD);
-
-static IIO_DEVICE_ATTR(pll2_locked, S_IRUGO,
- ad9523_show,
- NULL,
- AD9523_STAT_PLL2_LD);
-
-static IIO_DEVICE_ATTR(pll1_reference_clk_a_present, S_IRUGO,
- ad9523_show,
- NULL,
- AD9523_STAT_REFA);
-
-static IIO_DEVICE_ATTR(pll1_reference_clk_b_present, S_IRUGO,
- ad9523_show,
- NULL,
- AD9523_STAT_REFB);
-
-static IIO_DEVICE_ATTR(pll1_reference_clk_test_present, S_IRUGO,
- ad9523_show,
- NULL,
- AD9523_STAT_REF_TEST);
-
-static IIO_DEVICE_ATTR(vcxo_clk_present, S_IRUGO,
- ad9523_show,
- NULL,
- AD9523_STAT_VCXO);
-
-static IIO_DEVICE_ATTR(pll2_feedback_clk_present, S_IRUGO,
- ad9523_show,
- NULL,
- AD9523_STAT_PLL2_FB_CLK);
-
-static IIO_DEVICE_ATTR(pll2_reference_clk_present, S_IRUGO,
- ad9523_show,
- NULL,
- AD9523_STAT_PLL2_REF_CLK);
-
-static IIO_DEVICE_ATTR(sync_dividers, S_IWUSR,
- NULL,
- ad9523_store,
- AD9523_SYNC);
-
-static IIO_DEVICE_ATTR(store_eeprom, S_IWUSR,
- NULL,
- ad9523_store,
- AD9523_EEPROM);
+static IIO_DEVICE_ATTR(pll1_locked, 0444, ad9523_show, NULL,
+ AD9523_STAT_PLL1_LD);
+
+static IIO_DEVICE_ATTR(pll2_locked, 0444, ad9523_show, NULL,
+ AD9523_STAT_PLL2_LD);
+
+static IIO_DEVICE_ATTR(pll1_reference_clk_a_present, 0444, ad9523_show, NULL,
+ AD9523_STAT_REFA);
+
+static IIO_DEVICE_ATTR(pll1_reference_clk_b_present, 0444, ad9523_show, NULL,
+ AD9523_STAT_REFB);
+
+static IIO_DEVICE_ATTR(pll1_reference_clk_test_present, 0444, ad9523_show, NULL,
+ AD9523_STAT_REF_TEST);
+
+static IIO_DEVICE_ATTR(vcxo_clk_present, 0444, ad9523_show, NULL,
+ AD9523_STAT_VCXO);
+
+static IIO_DEVICE_ATTR(pll2_feedback_clk_present, 0444, ad9523_show, NULL,
+ AD9523_STAT_PLL2_FB_CLK);
+
+static IIO_DEVICE_ATTR(pll2_reference_clk_present, 0444, ad9523_show, NULL,
+ AD9523_STAT_PLL2_REF_CLK);
+
+static IIO_DEVICE_ATTR(sync_dividers, 0200, NULL, ad9523_store,
+ AD9523_SYNC);
+
+static IIO_DEVICE_ATTR(store_eeprom, 0200, NULL, ad9523_store,
+ AD9523_EEPROM);
static struct attribute *ad9523_attributes[] = {
&iio_dev_attr_sync_dividers.dev_attr.attr,
@@ -797,8 +777,7 @@ static int ad9523_setup(struct iio_dev *indio_dev)
return ret;
ret = ad9523_write(indio_dev, AD9523_PLL1_CHARGE_PUMP_CTRL,
- AD9523_PLL1_CHARGE_PUMP_CURRENT_nA(pdata->
- pll1_charge_pump_current_nA) |
+ AD9523_PLL1_CHARGE_PUMP_CURRENT_nA(pdata->pll1_charge_pump_current_nA) |
AD9523_PLL1_CHARGE_PUMP_MODE_NORMAL |
AD9523_PLL1_BACKLASH_PW_MIN);
if (ret < 0)
@@ -842,8 +821,7 @@ static int ad9523_setup(struct iio_dev *indio_dev)
*/
ret = ad9523_write(indio_dev, AD9523_PLL2_CHARGE_PUMP,
- AD9523_PLL2_CHARGE_PUMP_CURRENT_nA(pdata->
- pll2_charge_pump_current_nA));
+ AD9523_PLL2_CHARGE_PUMP_CURRENT_nA(pdata->pll2_charge_pump_current_nA));
if (ret < 0)
return ret;
@@ -970,17 +948,17 @@ static int ad9523_setup(struct iio_dev *indio_dev)
static int ad9523_probe(struct spi_device *spi)
{
- struct ad9523_platform_data *pdata = dev_get_platdata(&spi->dev);
+ struct device *dev = &spi->dev;
+ struct ad9523_platform_data *pdata;
struct iio_dev *indio_dev;
struct ad9523_state *st;
int ret;
- if (!pdata) {
- dev_err(&spi->dev, "no platform data?\n");
- return -EINVAL;
- }
+ pdata = dev_get_platdata(dev);
+ if (!pdata)
+ return dev_err_probe(dev, -EINVAL, "no platform data?\n");
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -988,16 +966,16 @@ static int ad9523_probe(struct spi_device *spi)
mutex_init(&st->lock);
- ret = devm_regulator_get_enable(&spi->dev, "vcc");
+ ret = devm_regulator_get_enable(dev, "vcc");
if (ret)
return ret;
- st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
+ st->pwrdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
GPIOD_OUT_HIGH);
if (IS_ERR(st->pwrdown_gpio))
return PTR_ERR(st->pwrdown_gpio);
- st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
+ st->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(st->reset_gpio))
return PTR_ERR(st->reset_gpio);
@@ -1007,12 +985,11 @@ static int ad9523_probe(struct spi_device *spi)
gpiod_direction_output(st->reset_gpio, 1);
}
- st->sync_gpio = devm_gpiod_get_optional(&spi->dev, "sync",
+ st->sync_gpio = devm_gpiod_get_optional(dev, "sync",
GPIOD_OUT_HIGH);
if (IS_ERR(st->sync_gpio))
return PTR_ERR(st->sync_gpio);
- spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->pdata = pdata;
@@ -1027,11 +1004,11 @@ static int ad9523_probe(struct spi_device *spi)
if (ret < 0)
return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id ad9523_id[] = {
- {"ad9523-1", 9523},
+ { .name = "ad9523-1" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad9523_id);
diff --git a/drivers/iio/frequency/adf41513.c b/drivers/iio/frequency/adf41513.c
new file mode 100644
index 000000000000..c497027012ba
--- /dev/null
+++ b/drivers/iio/frequency/adf41513.c
@@ -0,0 +1,1246 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ADF41513 SPI PLL Frequency Synthesizer driver
+ *
+ * Copyright 2026 Analog Devices Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kstrtox.h>
+#include <linux/log2.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+#include <linux/time64.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+
+/* Registers */
+#define ADF41513_REG0 0
+#define ADF41513_REG1 1
+#define ADF41513_REG2 2
+#define ADF41513_REG3 3
+#define ADF41513_REG4 4
+#define ADF41513_REG5 5
+#define ADF41513_REG6 6
+#define ADF41513_REG7 7
+#define ADF41513_REG8 8
+#define ADF41513_REG9 9
+#define ADF41513_REG10 10
+#define ADF41513_REG11 11
+#define ADF41513_REG12 12
+#define ADF41513_REG13 13
+#define ADF41513_REG_NUM 14
+
+#define ADF41513_SYNC_REG0 BIT(ADF41513_REG0)
+#define ADF41513_SYNC_REG1 BIT(ADF41513_REG1)
+#define ADF41513_SYNC_REG2 BIT(ADF41513_REG2)
+#define ADF41513_SYNC_REG3 BIT(ADF41513_REG3)
+#define ADF41513_SYNC_REG4 BIT(ADF41513_REG4)
+#define ADF41513_SYNC_REG5 BIT(ADF41513_REG5)
+#define ADF41513_SYNC_REG6 BIT(ADF41513_REG6)
+#define ADF41513_SYNC_REG7 BIT(ADF41513_REG7)
+#define ADF41513_SYNC_REG9 BIT(ADF41513_REG9)
+#define ADF41513_SYNC_REG11 BIT(ADF41513_REG11)
+#define ADF41513_SYNC_REG12 BIT(ADF41513_REG12)
+#define ADF41513_SYNC_REG13 BIT(ADF41513_REG13)
+#define ADF41513_SYNC_DIFF 0
+#define ADF41513_SYNC_ALL GENMASK(ADF41513_REG13, ADF41513_REG0)
+
+/* REG0 Bit Definitions */
+#define ADF41513_REG0_CTRL_BITS_MSK GENMASK(3, 0)
+#define ADF41513_REG0_INT_MSK GENMASK(19, 4)
+#define ADF41513_REG0_VAR_MOD_MSK BIT(28)
+
+/* REG1 Bit Definitions */
+#define ADF41513_REG1_FRAC1_MSK GENMASK(28, 4)
+#define ADF41513_REG1_DITHER2_MSK BIT(31)
+
+/* REG2 Bit Definitions */
+#define ADF41513_REG2_PHASE_VAL_MSK GENMASK(15, 4)
+#define ADF41513_REG2_PHASE_ADJ_MSK BIT(31)
+
+/* REG3 Bit Definitions */
+#define ADF41513_REG3_FRAC2_MSK GENMASK(27, 4)
+
+/* REG4 Bit Definitions */
+#define ADF41513_REG4_MOD2_MSK GENMASK(27, 4)
+
+/* REG5 Bit Definitions */
+#define ADF41513_REG5_CLK1_DIV_MSK GENMASK(15, 4)
+#define ADF41513_REG5_R_CNT_MSK GENMASK(20, 16)
+#define ADF41513_REG5_REF_DOUBLER_MSK BIT(21)
+#define ADF41513_REG5_RDIV2_MSK BIT(22)
+#define ADF41513_REG5_PRESCALER_MSK BIT(23)
+#define ADF41513_REG5_LSB_P1_MSK BIT(24)
+#define ADF41513_REG5_CP_CURRENT_MSK GENMASK(28, 25)
+#define ADF41513_REG5_DLD_MODES_MSK GENMASK(31, 30)
+
+/* REG6 Bit Definitions */
+#define ADF41513_REG6_COUNTER_RESET_MSK BIT(4)
+#define ADF41513_REG6_CP_TRISTATE_MSK BIT(5)
+#define ADF41513_REG6_POWER_DOWN_MSK BIT(6)
+#define ADF41513_REG6_PD_POLARITY_MSK BIT(7)
+#define ADF41513_REG6_LDP_MSK GENMASK(9, 8)
+#define ADF41513_REG6_CP_TRISTATE_PD_ON_MSK BIT(16)
+#define ADF41513_REG6_SD_RESET_MSK BIT(17)
+#define ADF41513_REG6_LOL_ENABLE_MSK BIT(18)
+#define ADF41513_REG6_ABP_MSK BIT(19)
+#define ADF41513_REG6_INT_MODE_MSK BIT(20)
+#define ADF41513_REG6_BLEED_ENABLE_MSK BIT(22)
+#define ADF41513_REG6_BLEED_POLARITY_MSK BIT(23)
+#define ADF41513_REG6_BLEED_CURRENT_MSK GENMASK(31, 24)
+
+/* REG7 Bit Definitions */
+#define ADF41513_REG7_CLK2_DIV_MSK GENMASK(17, 6)
+#define ADF41513_REG7_CLK_DIV_MODE_MSK GENMASK(19, 18)
+#define ADF41513_REG7_PS_BIAS_MSK GENMASK(21, 20)
+#define ADF41513_REG7_N_DELAY_MSK GENMASK(23, 22)
+#define ADF41513_REG7_LD_CLK_SEL_MSK BIT(26)
+#define ADF41513_REG7_LD_COUNT_MSK GENMASK(29, 27)
+
+/* REG9 Bit Definitions */
+#define ADF41513_REG9_LD_BIAS_MSK GENMASK(31, 30)
+
+/* REG11 Bit Definitions */
+#define ADF41513_REG11_POWER_DOWN_SEL_MSK BIT(31)
+
+/* REG12 Bit Definitions */
+#define ADF41513_REG12_READBACK_SEL_MSK GENMASK(19, 14)
+#define ADF41513_REG12_LE_SELECT_MSK BIT(20)
+#define ADF41513_REG12_MASTER_RESET_MSK BIT(22)
+#define ADF41513_REG12_LOGIC_LEVEL_MSK BIT(27)
+#define ADF41513_REG12_MUXOUT_MSK GENMASK(31, 28)
+
+/* MUXOUT Selection */
+#define ADF41513_MUXOUT_TRISTATE 0x0
+#define ADF41513_MUXOUT_DVDD 0x1
+#define ADF41513_MUXOUT_DGND 0x2
+#define ADF41513_MUXOUT_R_DIV 0x3
+#define ADF41513_MUXOUT_N_DIV 0x4
+#define ADF41513_MUXOUT_DIG_LD 0x6
+#define ADF41513_MUXOUT_SDO 0x7
+#define ADF41513_MUXOUT_READBACK 0x8
+#define ADF41513_MUXOUT_CLK1_DIV 0xA
+#define ADF41513_MUXOUT_R_DIV2 0xD
+#define ADF41513_MUXOUT_N_DIV2 0xE
+
+/* DLD Mode Selection */
+#define ADF41513_DLD_TRISTATE 0x0
+#define ADF41513_DLD_DIG_LD 0x1
+#define ADF41513_DLD_LOW 0x2
+#define ADF41513_DLD_HIGH 0x3
+
+/* Prescaler Selection */
+#define ADF41513_PRESCALER_4_5 0
+#define ADF41513_PRESCALER_8_9 1
+#define ADF41513_PRESCALER_AUTO 2
+
+/* CLK Divider mode */
+#define ADF41513_CLK_DIV_MODE_OFF 0
+#define ADF41513_CLK_DIV_MODE_PHASE_RESYNC 2
+
+/* Specifications */
+#define ADF41510_MAX_RF_FREQ_HZ (10ULL * HZ_PER_GHZ)
+#define ADF41513_MIN_RF_FREQ_HZ (1ULL * HZ_PER_GHZ)
+#define ADF41513_MAX_RF_FREQ_HZ (26500ULL * HZ_PER_MHZ)
+
+#define ADF41513_MIN_REF_FREQ_HZ (10 * HZ_PER_MHZ)
+#define ADF41513_MAX_REF_FREQ_HZ (800 * HZ_PER_MHZ)
+#define ADF41513_MAX_REF_FREQ_DOUBLER_HZ (225 * HZ_PER_MHZ)
+
+#define ADF41513_MAX_PFD_FREQ_INT_N_UHZ (250ULL * MEGA * MICROHZ_PER_HZ)
+#define ADF41513_MAX_PFD_FREQ_FRAC_N_UHZ (125ULL * MEGA * MICROHZ_PER_HZ)
+#define ADF41513_MAX_FREQ_RESOLUTION_UHZ (100ULL * KILO * MICROHZ_PER_HZ)
+
+#define ADF41513_MIN_INT_4_5 20
+#define ADF41513_MAX_INT_4_5 511
+#define ADF41513_MIN_INT_8_9 64
+#define ADF41513_MAX_INT_8_9 1023
+
+#define ADF41513_MIN_INT_FRAC_4_5 23
+#define ADF41513_MIN_INT_FRAC_8_9 75
+
+#define ADF41513_MIN_R_CNT 1
+#define ADF41513_MAX_R_CNT 32
+
+#define ADF41513_MIN_R_SET 1800
+#define ADF41513_DEFAULT_R_SET 2700
+#define ADF41513_MAX_R_SET 10000
+
+#define ADF41513_MIN_CP_VOLTAGE_mV 810
+#define ADF41513_DEFAULT_CP_VOLTAGE_mV 6480
+#define ADF41513_MAX_CP_VOLTAGE_mV 12960
+
+#define ADF41513_MIN_CP_CURRENT_uA 81
+#define ADF41513_MAX_CP_CURRENT_uA 7200
+
+#define ADF41513_LD_COUNT_FAST_MIN 2
+#define ADF41513_LD_COUNT_FAST_LIMIT 64
+#define ADF41513_LD_COUNT_MIN 64
+#define ADF41513_LD_COUNT_MAX 8192
+
+#define ADF41513_FIXED_MODULUS BIT(25)
+#define ADF41513_MAX_MOD2 (BIT(24) - 1)
+#define ADF41513_MAX_PHASE_VAL (BIT(12) - 1)
+#define ADF41513_MAX_CLK_DIVIDER (BIT(12) - 1)
+
+#define ADF41513_HZ_DECIMAL_SCALE 6
+#define ADF41513_PS_BIAS_INIT 0x2
+#define ADF41513_MAX_PHASE_MICRORAD ((2 * 314159265UL) / 100)
+
+enum adf41513_pll_mode {
+ ADF41513_MODE_INVALID,
+ ADF41513_MODE_INTEGER_N,
+ ADF41513_MODE_FIXED_MODULUS,
+ ADF41513_MODE_VARIABLE_MODULUS,
+};
+
+struct adf41513_chip_info {
+ const char *name;
+ u64 max_rf_freq_hz;
+ bool has_prescaler_8_9;
+};
+
+struct adf41513_data {
+ u64 power_up_frequency_hz;
+ u64 freq_resolution_uhz;
+ u32 phase_resync_period_ns;
+ u32 charge_pump_voltage_mv;
+ u32 lock_detect_count;
+
+ u8 ref_div_factor;
+ bool ref_doubler_en;
+ bool ref_div2_en;
+ bool phase_detector_polarity;
+
+ bool logic_lvl_1v8_en;
+ bool le_sync_en;
+};
+
+struct adf41513_pll_settings {
+ enum adf41513_pll_mode mode;
+
+ /* reference path parameters */
+ u8 r_counter;
+ u8 ref_doubler;
+ u8 ref_div2;
+ u8 prescaler;
+
+ /* frequency parameters */
+ u64 target_frequency_uhz;
+ u64 actual_frequency_uhz;
+ u64 pfd_frequency_uhz;
+
+ /* pll parameters */
+ u32 frac1;
+ u32 frac2;
+ u32 mod2;
+ u16 int_val;
+};
+
+struct adf41513_state {
+ const struct adf41513_chip_info *chip_info;
+ struct spi_device *spi;
+ struct gpio_desc *lock_detect;
+ struct clk *ref_clk;
+ u32 ref_freq_hz;
+
+ /*
+ * Lock for accessing device registers. Some operations require
+ * multiple consecutive R/W operations, during which the device
+ * shouldn't be interrupted. The buffers are also shared across
+ * all operations so need to be protected on stand alone reads and
+ * writes.
+ */
+ struct mutex lock;
+
+ /* Cached register values */
+ u32 regs[ADF41513_REG_NUM];
+ u32 regs_hw[ADF41513_REG_NUM];
+
+ struct adf41513_data data;
+ struct adf41513_pll_settings settings;
+
+ bool powerdown;
+};
+
+static const u16 adf41513_ld_window_x10_ns[] = {
+ 9, 12, 16, 17, 21, 28, 29, 35, /* 0 - 7 */
+ 43, 47, 49, 52, 70, 79, 115, /* 8 - 14 */
+};
+
+static const u8 adf41513_ldp_bias[] = {
+ 0xC, 0xD, 0xE, 0x8, 0x9, 0x4, 0xA, 0x5, /* 0 - 7 */
+ 0x0, 0x6, 0xB, 0x1, 0x2, 0x7, 0x3, /* 8 - 14 */
+};
+
+static const char * const adf41513_power_supplies[] = {
+ "avdd1", "avdd2", "avdd3", "avdd4", "avdd5", "vp",
+};
+
+static int adf41513_sync_config(struct adf41513_state *st, u16 sync_mask)
+{
+ __be32 d32;
+ int ret;
+
+ /* write registers in reverse order (R13 to R0)*/
+ for (int i = ADF41513_REG13; i >= ADF41513_REG0; i--) {
+ if (st->regs_hw[i] == st->regs[i] && !(sync_mask & BIT(i)))
+ continue;
+
+ d32 = cpu_to_be32(st->regs[i] | i);
+ ret = spi_write_then_read(st->spi, &d32, sizeof(d32), NULL, 0);
+ if (ret < 0)
+ return ret;
+ st->regs_hw[i] = st->regs[i];
+ dev_dbg(&st->spi->dev, "REG%d <= 0x%08X\n", i, st->regs[i] | i);
+ }
+
+ return 0;
+}
+
+static u64 adf41513_pll_get_rate(struct adf41513_state *st)
+{
+ struct adf41513_pll_settings *cfg = &st->settings;
+
+ if (cfg->mode != ADF41513_MODE_INVALID)
+ return cfg->actual_frequency_uhz;
+
+ /* get pll settings from regs_hw */
+ cfg->int_val = FIELD_GET(ADF41513_REG0_INT_MSK, st->regs_hw[ADF41513_REG0]);
+ cfg->frac1 = FIELD_GET(ADF41513_REG1_FRAC1_MSK, st->regs_hw[ADF41513_REG1]);
+ cfg->frac2 = FIELD_GET(ADF41513_REG3_FRAC2_MSK, st->regs_hw[ADF41513_REG3]);
+ cfg->mod2 = FIELD_GET(ADF41513_REG4_MOD2_MSK, st->regs_hw[ADF41513_REG4]);
+ cfg->r_counter = FIELD_GET(ADF41513_REG5_R_CNT_MSK, st->regs_hw[ADF41513_REG5]);
+ cfg->ref_doubler = FIELD_GET(ADF41513_REG5_REF_DOUBLER_MSK, st->regs_hw[ADF41513_REG5]);
+ cfg->ref_div2 = FIELD_GET(ADF41513_REG5_RDIV2_MSK, st->regs_hw[ADF41513_REG5]);
+ cfg->prescaler = FIELD_GET(ADF41513_REG5_PRESCALER_MSK, st->regs_hw[ADF41513_REG5]);
+
+ if (!cfg->mod2)
+ cfg->mod2 = 1;
+ if (!cfg->r_counter)
+ cfg->r_counter = ADF41513_MAX_R_CNT;
+
+ /* calculate pfd frequency */
+ cfg->pfd_frequency_uhz = (u64)st->ref_freq_hz * MICRO;
+ if (cfg->ref_doubler)
+ cfg->pfd_frequency_uhz <<= 1;
+ if (cfg->ref_div2)
+ cfg->pfd_frequency_uhz >>= 1;
+ cfg->pfd_frequency_uhz = div_u64(cfg->pfd_frequency_uhz, cfg->r_counter);
+ cfg->actual_frequency_uhz = (u64)cfg->int_val * cfg->pfd_frequency_uhz;
+
+ /* check if int mode is selected */
+ if (FIELD_GET(ADF41513_REG6_INT_MODE_MSK, st->regs_hw[ADF41513_REG6])) {
+ cfg->mode = ADF41513_MODE_INTEGER_N;
+ } else {
+ cfg->actual_frequency_uhz += mul_u64_u32_div(cfg->pfd_frequency_uhz,
+ cfg->frac1,
+ ADF41513_FIXED_MODULUS);
+
+ /* check if variable modulus is selected */
+ if (FIELD_GET(ADF41513_REG0_VAR_MOD_MSK, st->regs_hw[ADF41513_REG0])) {
+ cfg->actual_frequency_uhz +=
+ mul_u64_u64_div_u64(cfg->frac2,
+ cfg->pfd_frequency_uhz,
+ (u64)cfg->mod2 * ADF41513_FIXED_MODULUS);
+
+ cfg->mode = ADF41513_MODE_VARIABLE_MODULUS;
+ } else {
+ /* LSB_P1 offset */
+ if (!FIELD_GET(ADF41513_REG5_LSB_P1_MSK, st->regs_hw[ADF41513_REG5]))
+ cfg->actual_frequency_uhz +=
+ div_u64(cfg->pfd_frequency_uhz,
+ 2 * ADF41513_FIXED_MODULUS);
+ cfg->mode = ADF41513_MODE_FIXED_MODULUS;
+ }
+ }
+
+ cfg->target_frequency_uhz = cfg->actual_frequency_uhz;
+
+ return cfg->actual_frequency_uhz;
+}
+
+static int adf41513_calc_pfd_frequency(struct adf41513_state *st,
+ struct adf41513_pll_settings *result,
+ u64 fpfd_limit_uhz)
+{
+ result->ref_div2 = st->data.ref_div2_en;
+ result->ref_doubler = st->data.ref_doubler_en;
+ result->r_counter = st->data.ref_div_factor - 1;
+
+ do {
+ result->r_counter++;
+ /* f_PFD = REF_IN × ((1 + D)/(R × (1 + T))) */
+ result->pfd_frequency_uhz = (u64)st->ref_freq_hz * MICRO;
+ if (result->ref_doubler)
+ result->pfd_frequency_uhz <<= 1;
+ if (result->ref_div2)
+ result->pfd_frequency_uhz >>= 1;
+ result->pfd_frequency_uhz = div_u64(result->pfd_frequency_uhz,
+ result->r_counter);
+ } while (result->pfd_frequency_uhz > fpfd_limit_uhz);
+
+ if (result->r_counter > ADF41513_MAX_R_CNT) {
+ dev_err(&st->spi->dev, "Cannot optimize PFD frequency\n");
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+static int adf41513_calc_integer_n(struct adf41513_state *st,
+ struct adf41513_pll_settings *result)
+{
+ u32 max_int = st->chip_info->has_prescaler_8_9 ?
+ ADF41513_MAX_INT_8_9 : ADF41513_MAX_INT_4_5;
+ u64 freq_error_uhz;
+ u32 int_val = div64_u64_rem(result->target_frequency_uhz, result->pfd_frequency_uhz,
+ &freq_error_uhz);
+
+ /* check if freq error is within a tolerance of 1/2 resolution */
+ if (freq_error_uhz > (result->pfd_frequency_uhz >> 1) && int_val < max_int) {
+ int_val++;
+ freq_error_uhz = result->pfd_frequency_uhz - freq_error_uhz;
+ }
+
+ if (freq_error_uhz > st->data.freq_resolution_uhz)
+ return -ERANGE;
+
+ /* set prescaler */
+ if (st->chip_info->has_prescaler_8_9 && int_val >= ADF41513_MIN_INT_8_9 &&
+ int_val <= ADF41513_MAX_INT_8_9)
+ result->prescaler = 1;
+ else if (int_val >= ADF41513_MIN_INT_4_5 && int_val <= ADF41513_MAX_INT_4_5)
+ result->prescaler = 0;
+ else
+ return -ERANGE;
+
+ result->actual_frequency_uhz = (u64)int_val * result->pfd_frequency_uhz;
+ result->mode = ADF41513_MODE_INTEGER_N;
+ result->int_val = int_val;
+ result->frac1 = 0;
+ result->frac2 = 0;
+ result->mod2 = 0;
+
+ return 0;
+}
+
+static int adf41513_calc_fixed_mod(struct adf41513_state *st,
+ struct adf41513_pll_settings *result)
+{
+ u64 resolution_uhz = div_u64(result->pfd_frequency_uhz, ADF41513_FIXED_MODULUS);
+ u64 target_frequency_uhz = result->target_frequency_uhz;
+ u64 freq_error_uhz;
+ u32 int_val, frac1;
+ bool lsb_p1_offset = !FIELD_GET(ADF41513_REG5_LSB_P1_MSK, st->regs[ADF41513_REG5]);
+
+ /* LSB_P1 adds a frequency offset of f_pfd/2^26 */
+ if (lsb_p1_offset)
+ target_frequency_uhz -= resolution_uhz >> 1;
+
+ int_val = div64_u64_rem(target_frequency_uhz, result->pfd_frequency_uhz,
+ &freq_error_uhz);
+
+ if (st->chip_info->has_prescaler_8_9 && int_val >= ADF41513_MIN_INT_FRAC_8_9 &&
+ int_val <= ADF41513_MAX_INT_8_9)
+ result->prescaler = 1;
+ else if (int_val >= ADF41513_MIN_INT_FRAC_4_5 && int_val <= ADF41513_MAX_INT_4_5)
+ result->prescaler = 0;
+ else
+ return -ERANGE;
+
+ /* compute frac1 and fixed modulus error */
+ frac1 = mul_u64_u64_div_u64(freq_error_uhz, ADF41513_FIXED_MODULUS,
+ result->pfd_frequency_uhz);
+ freq_error_uhz -= mul_u64_u32_div(result->pfd_frequency_uhz, frac1,
+ ADF41513_FIXED_MODULUS);
+
+ /* check if freq error is within a tolerance of 1/2 resolution */
+ if (freq_error_uhz > (resolution_uhz >> 1) && frac1 < (ADF41513_FIXED_MODULUS - 1)) {
+ frac1++;
+ freq_error_uhz = freq_error_uhz < resolution_uhz ?
+ resolution_uhz - freq_error_uhz : 0;
+ }
+
+ if (freq_error_uhz > st->data.freq_resolution_uhz)
+ return -ERANGE;
+
+ /* integer part */
+ result->actual_frequency_uhz = (u64)int_val * result->pfd_frequency_uhz;
+ /* fractional part */
+ if (lsb_p1_offset)
+ result->actual_frequency_uhz += (resolution_uhz >> 1);
+ result->actual_frequency_uhz += mul_u64_u32_div(result->pfd_frequency_uhz, frac1,
+ ADF41513_FIXED_MODULUS);
+ result->mode = ADF41513_MODE_FIXED_MODULUS;
+ result->int_val = int_val;
+ result->frac1 = frac1;
+ result->frac2 = 0;
+ result->mod2 = 0;
+
+ return 0;
+}
+
+static int adf41513_calc_variable_mod(struct adf41513_state *st,
+ struct adf41513_pll_settings *result)
+{
+ u64 freq_error_uhz, mod2;
+ u32 frac1, frac2;
+ u32 int_val = div64_u64_rem(result->target_frequency_uhz,
+ result->pfd_frequency_uhz, &freq_error_uhz);
+
+ if (st->chip_info->has_prescaler_8_9 && int_val >= ADF41513_MIN_INT_FRAC_8_9 &&
+ int_val <= ADF41513_MAX_INT_8_9)
+ result->prescaler = 1;
+ else if (int_val >= ADF41513_MIN_INT_FRAC_4_5 && int_val <= ADF41513_MAX_INT_4_5)
+ result->prescaler = 0;
+ else
+ return -ERANGE;
+
+ /* calculate required mod2 based on target resolution / 2 */
+ mod2 = DIV64_U64_ROUND_CLOSEST(result->pfd_frequency_uhz << 1,
+ st->data.freq_resolution_uhz * ADF41513_FIXED_MODULUS);
+ /* ensure mod2 is at least 2 for meaningful operation */
+ mod2 = clamp(mod2, 2, ADF41513_MAX_MOD2);
+
+ /* calculate frac1 and frac2 */
+ frac1 = mul_u64_u64_div_u64(freq_error_uhz, ADF41513_FIXED_MODULUS,
+ result->pfd_frequency_uhz);
+ frac2 = mul_u64_u64_div_u64(freq_error_uhz, mod2 * ADF41513_FIXED_MODULUS,
+ result->pfd_frequency_uhz) - mod2 * frac1;
+
+ /* integer part */
+ result->actual_frequency_uhz = (u64)int_val * result->pfd_frequency_uhz;
+ /* fractional part */
+ result->actual_frequency_uhz += mul_u64_u64_div_u64(mod2 * frac1 + frac2,
+ result->pfd_frequency_uhz,
+ mod2 * ADF41513_FIXED_MODULUS);
+ result->mode = ADF41513_MODE_VARIABLE_MODULUS;
+ result->int_val = int_val;
+ result->frac1 = frac1;
+ result->frac2 = frac2;
+ result->mod2 = mod2;
+
+ return 0;
+}
+
+static int adf41513_calc_pll_settings(struct adf41513_state *st,
+ struct adf41513_pll_settings *result,
+ u64 rf_out_uhz)
+{
+ u64 max_rf_freq_uhz = st->chip_info->max_rf_freq_hz * MICRO;
+ u64 min_rf_freq_uhz = ADF41513_MIN_RF_FREQ_HZ * MICRO;
+ u64 pfd_freq_limit_uhz;
+ int ret;
+
+ if (rf_out_uhz < min_rf_freq_uhz || rf_out_uhz > max_rf_freq_uhz) {
+ dev_err(&st->spi->dev, "RF frequency %llu uHz out of range [%llu, %llu] uHz\n",
+ rf_out_uhz, min_rf_freq_uhz, max_rf_freq_uhz);
+ return -EINVAL;
+ }
+
+ result->target_frequency_uhz = rf_out_uhz;
+
+ /* try integer-N first (best phase noise performance) */
+ pfd_freq_limit_uhz = min(div_u64(rf_out_uhz, ADF41513_MIN_INT_4_5),
+ ADF41513_MAX_PFD_FREQ_INT_N_UHZ);
+ ret = adf41513_calc_pfd_frequency(st, result, pfd_freq_limit_uhz);
+ if (ret)
+ return ret;
+
+ if (adf41513_calc_integer_n(st, result) == 0)
+ return 0;
+
+ /* try fractional-N: recompute pfd frequency if necessary */
+ pfd_freq_limit_uhz = min(div_u64(rf_out_uhz, ADF41513_MIN_INT_FRAC_4_5),
+ ADF41513_MAX_PFD_FREQ_FRAC_N_UHZ);
+ if (pfd_freq_limit_uhz < result->pfd_frequency_uhz) {
+ ret = adf41513_calc_pfd_frequency(st, result, pfd_freq_limit_uhz);
+ if (ret)
+ return ret;
+ }
+
+ /* fixed-modulus attempt */
+ if (adf41513_calc_fixed_mod(st, result) == 0)
+ return 0;
+
+ /* variable-modulus attempt */
+ ret = adf41513_calc_variable_mod(st, result);
+ if (ret) {
+ dev_err(&st->spi->dev,
+ "no valid PLL configuration found for %llu uHz\n",
+ rf_out_uhz);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void adf41513_set_bleed_val(struct adf41513_state *st)
+{
+ u32 bleed_value, cp_index;
+
+ if (!(st->regs[ADF41513_REG6] & ADF41513_REG6_BLEED_ENABLE_MSK))
+ return;
+
+ if (st->data.phase_detector_polarity)
+ bleed_value = 90;
+ else
+ bleed_value = 144;
+
+ cp_index = 1 + FIELD_GET(ADF41513_REG5_CP_CURRENT_MSK,
+ st->regs[ADF41513_REG5]);
+ bleed_value = div64_u64(st->settings.pfd_frequency_uhz * cp_index * bleed_value,
+ 1600ULL * MEGA * MICROHZ_PER_HZ);
+
+ FIELD_MODIFY(ADF41513_REG6_BLEED_CURRENT_MSK, &st->regs[ADF41513_REG6],
+ bleed_value);
+}
+
+static void adf41513_set_ld_window(struct adf41513_state *st)
+{
+ /*
+ * The ideal lock detector window size is halfway between the max
+ * window, set by the phase comparison period t_PFD = (1 / f_PFD),
+ * and the minimum is set by (I_BLEED/I_CP) × t_PFD
+ */
+ u16 ld_window_10x_ns = div64_u64(10ULL * NSEC_PER_SEC * MICROHZ_PER_HZ,
+ st->settings.pfd_frequency_uhz << 1);
+ u8 ld_idx, ldp, ld_bias;
+
+ if (st->settings.mode != ADF41513_MODE_INTEGER_N) {
+ /* account for bleed current (deduced from eq.6 and eq.7) */
+ if (st->data.phase_detector_polarity)
+ ld_window_10x_ns += 4;
+ else
+ ld_window_10x_ns += 6;
+ }
+
+ ld_idx = find_closest(ld_window_10x_ns, adf41513_ld_window_x10_ns,
+ ARRAY_SIZE(adf41513_ld_window_x10_ns));
+ ldp = (adf41513_ldp_bias[ld_idx] >> 2) & 0x3;
+ ld_bias = adf41513_ldp_bias[ld_idx] & 0x3;
+
+ FIELD_MODIFY(ADF41513_REG6_LDP_MSK, &st->regs[ADF41513_REG6], ldp);
+ FIELD_MODIFY(ADF41513_REG9_LD_BIAS_MSK, &st->regs[ADF41513_REG9], ld_bias);
+}
+
+static void adf41513_set_phase_resync(struct adf41513_state *st)
+{
+ u32 total_div, clk1_div, clk2_div;
+
+ if (!st->data.phase_resync_period_ns)
+ return;
+
+ /* assuming both clock dividers hold similar values */
+ total_div = mul_u64_u64_div_u64(st->settings.pfd_frequency_uhz,
+ st->data.phase_resync_period_ns,
+ 1ULL * MICROHZ_PER_HZ * NSEC_PER_SEC);
+ clk1_div = clamp(int_sqrt(total_div), 1,
+ ADF41513_MAX_CLK_DIVIDER);
+ clk2_div = clamp(DIV_ROUND_CLOSEST(total_div, clk1_div), 1,
+ ADF41513_MAX_CLK_DIVIDER);
+
+ FIELD_MODIFY(ADF41513_REG5_CLK1_DIV_MSK, &st->regs[ADF41513_REG5],
+ clk1_div);
+ FIELD_MODIFY(ADF41513_REG7_CLK2_DIV_MSK, &st->regs[ADF41513_REG7],
+ clk2_div);
+
+ /* enable phase resync */
+ FIELD_MODIFY(ADF41513_REG7_CLK_DIV_MODE_MSK, &st->regs[ADF41513_REG7],
+ ADF41513_CLK_DIV_MODE_PHASE_RESYNC);
+}
+
+static int adf41513_set_frequency(struct adf41513_state *st, u64 freq_uhz, u16 sync_mask)
+{
+ struct adf41513_pll_settings result;
+ bool pfd_change = false;
+ bool mode_change = false;
+ int ret;
+
+ ret = adf41513_calc_pll_settings(st, &result, freq_uhz);
+ if (ret < 0)
+ return ret;
+
+ /* apply computed results to pll settings */
+ pfd_change = st->settings.pfd_frequency_uhz != result.pfd_frequency_uhz;
+ mode_change = st->settings.mode != result.mode;
+ st->settings = result;
+
+ dev_dbg(&st->spi->dev,
+ "%s mode: int=%u, frac1=%u, frac2=%u, mod2=%u, fpdf=%llu Hz, prescaler=%s\n",
+ (result.mode == ADF41513_MODE_INTEGER_N) ? "integer-n" :
+ (result.mode == ADF41513_MODE_FIXED_MODULUS) ? "fixed-modulus" : "variable-modulus",
+ result.int_val, result.frac1, result.frac2, result.mod2,
+ div64_u64(result.pfd_frequency_uhz, MICRO),
+ result.prescaler ? "8/9" : "4/5");
+
+ st->regs[ADF41513_REG0] = FIELD_PREP(ADF41513_REG0_INT_MSK,
+ st->settings.int_val);
+ if (st->settings.mode == ADF41513_MODE_VARIABLE_MODULUS)
+ st->regs[ADF41513_REG0] |= ADF41513_REG0_VAR_MOD_MSK;
+
+ st->regs[ADF41513_REG1] = FIELD_PREP(ADF41513_REG1_FRAC1_MSK,
+ st->settings.frac1);
+ if (st->settings.mode != ADF41513_MODE_INTEGER_N)
+ st->regs[ADF41513_REG1] |= ADF41513_REG1_DITHER2_MSK;
+
+ st->regs[ADF41513_REG3] = FIELD_PREP(ADF41513_REG3_FRAC2_MSK,
+ st->settings.frac2);
+ FIELD_MODIFY(ADF41513_REG4_MOD2_MSK, &st->regs[ADF41513_REG4],
+ st->settings.mod2);
+ FIELD_MODIFY(ADF41513_REG5_R_CNT_MSK, &st->regs[ADF41513_REG5],
+ st->settings.r_counter % ADF41513_MAX_R_CNT);
+ FIELD_MODIFY(ADF41513_REG5_REF_DOUBLER_MSK, &st->regs[ADF41513_REG5],
+ st->settings.ref_doubler);
+ FIELD_MODIFY(ADF41513_REG5_RDIV2_MSK, &st->regs[ADF41513_REG5],
+ st->settings.ref_div2);
+ FIELD_MODIFY(ADF41513_REG5_PRESCALER_MSK, &st->regs[ADF41513_REG5],
+ st->settings.prescaler);
+
+ if (st->settings.mode == ADF41513_MODE_INTEGER_N) {
+ st->regs[ADF41513_REG6] |= ADF41513_REG6_INT_MODE_MSK;
+ st->regs[ADF41513_REG6] &= ~ADF41513_REG6_BLEED_ENABLE_MSK;
+ } else {
+ st->regs[ADF41513_REG6] &= ~ADF41513_REG6_INT_MODE_MSK;
+ st->regs[ADF41513_REG6] |= ADF41513_REG6_BLEED_ENABLE_MSK;
+ }
+
+ if (pfd_change)
+ adf41513_set_phase_resync(st);
+
+ if (pfd_change || mode_change) {
+ adf41513_set_bleed_val(st);
+ adf41513_set_ld_window(st);
+ }
+
+ return adf41513_sync_config(st, sync_mask | ADF41513_SYNC_REG0);
+}
+
+static int adf41513_suspend(struct adf41513_state *st)
+{
+ st->regs[ADF41513_REG6] |= FIELD_PREP(ADF41513_REG6_POWER_DOWN_MSK, 1);
+ st->regs[ADF41513_REG12] &= ~ADF41513_REG12_LE_SELECT_MSK;
+ return adf41513_sync_config(st, ADF41513_SYNC_DIFF);
+}
+
+static int adf41513_resume(struct adf41513_state *st)
+{
+ int ret;
+
+ st->regs[ADF41513_REG6] &= ~ADF41513_REG6_POWER_DOWN_MSK;
+ st->regs[ADF41513_REG12] &= ~ADF41513_REG12_LE_SELECT_MSK;
+ ret = adf41513_sync_config(st, ADF41513_SYNC_ALL);
+ if (ret)
+ return ret;
+
+ if (st->data.le_sync_en) {
+ st->regs[ADF41513_REG12] |= ADF41513_REG12_LE_SELECT_MSK;
+ ret = adf41513_sync_config(st, ADF41513_SYNC_DIFF);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static ssize_t adf41513_read_resolution(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ char *buf)
+{
+ struct adf41513_state *st = iio_priv(indio_dev);
+ int vals[2];
+
+ guard(mutex)(&st->lock);
+
+ iio_val_s64_decompose(st->data.freq_resolution_uhz, &vals[0], &vals[1]);
+ return iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(vals), vals);
+}
+
+static ssize_t adf41513_read_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ char *buf)
+{
+ struct adf41513_state *st = iio_priv(indio_dev);
+ u32 val;
+
+ guard(mutex)(&st->lock);
+
+ val = FIELD_GET(ADF41513_REG6_POWER_DOWN_MSK, st->regs_hw[ADF41513_REG6]);
+ return sysfs_emit(buf, "%u\n", val);
+}
+
+static ssize_t adf41513_write_resolution(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct adf41513_state *st = iio_priv(indio_dev);
+ u64 freq_uhz;
+ int ret;
+
+ ret = kstrtoudec64(buf, ADF41513_HZ_DECIMAL_SCALE, &freq_uhz);
+ if (ret)
+ return ret;
+
+ if (freq_uhz == 0 || freq_uhz > ADF41513_MAX_FREQ_RESOLUTION_UHZ)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+
+ st->data.freq_resolution_uhz = freq_uhz;
+ return len;
+}
+
+static ssize_t adf41513_write_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct adf41513_state *st = iio_priv(indio_dev);
+ bool val;
+ int ret;
+
+ ret = kstrtobool(buf, &val);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&st->lock);
+
+ if (val)
+ ret = adf41513_suspend(st);
+ else
+ ret = adf41513_resume(st);
+ if (ret)
+ return ret;
+
+ st->powerdown = val;
+ return len;
+}
+
+static const struct iio_chan_spec_ext_info adf41513_ext_info[] = {
+ {
+ .name = "frequency_resolution",
+ .read = adf41513_read_resolution,
+ .write = adf41513_write_resolution,
+ .shared = IIO_SEPARATE,
+ },
+ {
+ .name = "powerdown",
+ .read = adf41513_read_powerdown,
+ .write = adf41513_write_powerdown,
+ .shared = IIO_SEPARATE,
+ },
+ { }
+};
+
+static const struct iio_chan_spec adf41513_chan = {
+ .type = IIO_ALTVOLTAGE,
+ .indexed = 1,
+ .output = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY) |
+ BIT(IIO_CHAN_INFO_PHASE),
+ .ext_info = adf41513_ext_info,
+};
+
+static int adf41513_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct adf41513_state *st = iio_priv(indio_dev);
+ u64 tmp64;
+
+ guard(mutex)(&st->lock);
+
+ switch (info) {
+ case IIO_CHAN_INFO_FREQUENCY:
+ if (st->lock_detect &&
+ !gpiod_get_value_cansleep(st->lock_detect)) {
+ dev_dbg(&st->spi->dev, "PLL un-locked\n");
+ return -EBUSY;
+ }
+ tmp64 = adf41513_pll_get_rate(st);
+ iio_val_s64_decompose(tmp64, val, val2);
+ return IIO_VAL_DECIMAL64_MICRO;
+ case IIO_CHAN_INFO_PHASE:
+ tmp64 = FIELD_GET(ADF41513_REG2_PHASE_VAL_MSK,
+ st->regs_hw[ADF41513_REG2]);
+ tmp64 = (tmp64 * ADF41513_MAX_PHASE_MICRORAD) >> 12;
+ iio_val_s64_decompose(tmp64, val, val2);
+ return IIO_VAL_DECIMAL64_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adf41513_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
+{
+ struct adf41513_state *st = iio_priv(indio_dev);
+ u64 tmp64 = iio_val_s64_compose(val, val2);
+ u16 phase_val;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ switch (info) {
+ case IIO_CHAN_INFO_FREQUENCY:
+ return adf41513_set_frequency(st, tmp64, ADF41513_SYNC_DIFF);
+ case IIO_CHAN_INFO_PHASE:
+ if (tmp64 >= ADF41513_MAX_PHASE_MICRORAD)
+ return -EINVAL;
+
+ phase_val = DIV_U64_ROUND_CLOSEST(tmp64 << 12,
+ ADF41513_MAX_PHASE_MICRORAD);
+ phase_val = min(phase_val, ADF41513_MAX_PHASE_VAL);
+ st->regs[ADF41513_REG2] |= ADF41513_REG2_PHASE_ADJ_MSK;
+ FIELD_MODIFY(ADF41513_REG2_PHASE_VAL_MSK,
+ &st->regs[ADF41513_REG2], phase_val);
+ ret = adf41513_sync_config(st, ADF41513_SYNC_REG0);
+ /* clear phase adjust for the next sync */
+ st->regs[ADF41513_REG2] &= ~ADF41513_REG2_PHASE_ADJ_MSK;
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adf41513_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_FREQUENCY:
+ case IIO_CHAN_INFO_PHASE:
+ return IIO_VAL_DECIMAL64_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adf41513_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct adf41513_state *st = iio_priv(indio_dev);
+
+ if (reg > ADF41513_REG13)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+
+ if (!readval) {
+ if (reg <= ADF41513_REG6)
+ st->settings.mode = ADF41513_MODE_INVALID;
+ st->regs[reg] = writeval & ~0xF; /* Clear control bits */
+ return adf41513_sync_config(st, BIT(reg));
+ }
+
+ *readval = st->regs_hw[reg];
+ return 0;
+}
+
+static const struct iio_info adf41513_info = {
+ .read_raw = adf41513_read_raw,
+ .write_raw = adf41513_write_raw,
+ .write_raw_get_fmt = adf41513_write_raw_get_fmt,
+ .debugfs_reg_access = &adf41513_reg_access,
+};
+
+static int adf41513_parse_fw(struct adf41513_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ u32 tmp, cp_resistance, cp_current;
+ int ret;
+
+ tmp = ADF41510_MAX_RF_FREQ_HZ / MEGA;
+ device_property_read_u32(dev, "adi,power-up-frequency-mhz", &tmp);
+ st->data.power_up_frequency_hz = (u64)tmp * MEGA;
+ if (st->data.power_up_frequency_hz < ADF41513_MIN_RF_FREQ_HZ ||
+ st->data.power_up_frequency_hz > st->chip_info->max_rf_freq_hz)
+ return dev_err_probe(dev, -ERANGE,
+ "power-up frequency %llu Hz out of range\n",
+ st->data.power_up_frequency_hz);
+
+ tmp = ADF41513_MIN_R_CNT;
+ device_property_read_u32(dev, "adi,reference-div-factor", &tmp);
+ if (tmp < ADF41513_MIN_R_CNT || tmp > ADF41513_MAX_R_CNT)
+ return dev_err_probe(dev, -ERANGE,
+ "invalid reference div factor %u\n", tmp);
+ st->data.ref_div_factor = tmp;
+
+ st->data.ref_div2_en = device_property_read_bool(dev, "adi,reference-div2-enable");
+ st->data.ref_doubler_en = device_property_read_bool(dev, "adi,reference-doubler-enable");
+
+ if (st->data.ref_doubler_en &&
+ st->ref_freq_hz > ADF41513_MAX_REF_FREQ_DOUBLER_HZ) {
+ return dev_err_probe(dev, -ERANGE,
+ "Ref frequency not supported with doubler enabled\n");
+ }
+
+ cp_resistance = ADF41513_DEFAULT_R_SET;
+ device_property_read_u32(dev, "adi,charge-pump-resistor-ohms", &cp_resistance);
+ if (cp_resistance < ADF41513_MIN_R_SET || cp_resistance > ADF41513_MAX_R_SET)
+ return dev_err_probe(dev, -ERANGE, "R_SET %u Ohms out of range\n", cp_resistance);
+
+ st->data.charge_pump_voltage_mv = ADF41513_DEFAULT_CP_VOLTAGE_mV;
+ ret = device_property_read_u32(dev, "adi,charge-pump-current-microamp", &cp_current);
+ if (!ret) {
+ if (cp_current < ADF41513_MIN_CP_CURRENT_uA ||
+ cp_current > ADF41513_MAX_CP_CURRENT_uA)
+ return dev_err_probe(dev, -ERANGE,
+ "I_CP %u uA out of range\n", cp_current);
+
+ tmp = DIV_ROUND_CLOSEST(cp_current * cp_resistance, MILLI);
+ if (tmp < ADF41513_MIN_CP_VOLTAGE_mV || tmp > ADF41513_MAX_CP_VOLTAGE_mV)
+ return dev_err_probe(dev, -ERANGE, "I_CP %u uA (%u Ohms) out of range\n",
+ cp_current, cp_resistance);
+ st->data.charge_pump_voltage_mv = tmp;
+ }
+
+ st->data.phase_detector_polarity =
+ device_property_read_bool(dev, "adi,phase-detector-polarity-positive-enable");
+
+ st->data.phase_resync_period_ns = 0;
+ ret = device_property_read_u32(dev, "adi,phase-resync-period-ns", &tmp);
+ if (!ret)
+ st->data.phase_resync_period_ns = tmp;
+
+ st->data.logic_lvl_1v8_en = device_property_read_bool(dev, "adi,logic-level-1v8-enable");
+
+ tmp = ADF41513_LD_COUNT_MIN;
+ device_property_read_u32(dev, "adi,lock-detector-count", &tmp);
+ if (tmp < ADF41513_LD_COUNT_FAST_MIN || tmp > ADF41513_LD_COUNT_MAX ||
+ !is_power_of_2(tmp))
+ return dev_err_probe(dev, -ERANGE,
+ "invalid lock detect count: %u\n", tmp);
+ st->data.lock_detect_count = tmp;
+
+ /* load enable sync */
+ st->data.le_sync_en = device_property_read_bool(dev, "adi,le-sync-enable");
+ st->data.freq_resolution_uhz = MICROHZ_PER_HZ;
+
+ return 0;
+}
+
+static void adf41513_chip_disable(void *data)
+{
+ gpiod_set_value_cansleep(data, 0);
+}
+
+static void adf41513_close(void *data)
+{
+ adf41513_suspend(data);
+}
+
+static int adf41513_setup(struct device *dev, struct adf41513_state *st)
+{
+ u32 tmp;
+ int ret;
+
+ memset(st->regs_hw, 0xFF, sizeof(st->regs_hw));
+
+ /* assuming DLD pin is used for lock detection */
+ st->regs[ADF41513_REG5] = FIELD_PREP(ADF41513_REG5_DLD_MODES_MSK,
+ ADF41513_DLD_DIG_LD);
+
+ tmp = DIV_ROUND_CLOSEST(st->data.charge_pump_voltage_mv, ADF41513_MIN_CP_VOLTAGE_mV);
+ st->regs[ADF41513_REG5] |= FIELD_PREP(ADF41513_REG5_CP_CURRENT_MSK, tmp - 1);
+
+ st->regs[ADF41513_REG6] = ADF41513_REG6_ABP_MSK |
+ ADF41513_REG6_LOL_ENABLE_MSK |
+ ADF41513_REG6_SD_RESET_MSK;
+ if (st->data.phase_detector_polarity)
+ st->regs[ADF41513_REG6] |= ADF41513_REG6_PD_POLARITY_MSK;
+
+ st->regs[ADF41513_REG7] = FIELD_PREP(ADF41513_REG7_PS_BIAS_MSK,
+ ADF41513_PS_BIAS_INIT);
+ tmp = ilog2(st->data.lock_detect_count);
+ if (st->data.lock_detect_count < ADF41513_LD_COUNT_FAST_LIMIT) {
+ tmp -= const_ilog2(ADF41513_LD_COUNT_FAST_MIN);
+ st->regs[ADF41513_REG7] |= ADF41513_REG7_LD_CLK_SEL_MSK;
+ } else {
+ tmp -= const_ilog2(ADF41513_LD_COUNT_MIN);
+ }
+ st->regs[ADF41513_REG7] |= FIELD_PREP(ADF41513_REG7_LD_COUNT_MSK, tmp);
+
+ st->regs[ADF41513_REG11] = ADF41513_REG11_POWER_DOWN_SEL_MSK;
+ st->regs[ADF41513_REG12] = FIELD_PREP(ADF41513_REG12_LOGIC_LEVEL_MSK,
+ st->data.logic_lvl_1v8_en ? 0 : 1);
+
+ /* perform initialization sequence with power-up frequency */
+ ret = adf41513_set_frequency(st, st->data.power_up_frequency_hz * MICRO,
+ ADF41513_SYNC_ALL);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, adf41513_close, st);
+ if (ret)
+ return ret;
+
+ if (st->data.le_sync_en) {
+ st->regs[ADF41513_REG12] |= ADF41513_REG12_LE_SELECT_MSK;
+ ret = adf41513_sync_config(st, ADF41513_SYNC_DIFF);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int adf41513_pm_suspend(struct device *dev)
+{
+ struct adf41513_state *st = dev_get_drvdata(dev);
+
+ guard(mutex)(&st->lock);
+ return adf41513_suspend(st);
+}
+
+static int adf41513_pm_resume(struct device *dev)
+{
+ struct adf41513_state *st = dev_get_drvdata(dev);
+
+ guard(mutex)(&st->lock);
+ if (st->powerdown)
+ return 0; /* nothing to do */
+
+ return adf41513_resume(st);
+}
+
+static const struct adf41513_chip_info adf41510_chip_info = {
+ .name = "adf41510",
+ .max_rf_freq_hz = ADF41510_MAX_RF_FREQ_HZ,
+ .has_prescaler_8_9 = false,
+};
+
+static const struct adf41513_chip_info adf41513_chip_info = {
+ .name = "adf41513",
+ .max_rf_freq_hz = ADF41513_MAX_RF_FREQ_HZ,
+ .has_prescaler_8_9 = true,
+};
+
+static int adf41513_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct gpio_desc *chip_enable;
+ struct iio_dev *indio_dev;
+ struct adf41513_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return -EINVAL;
+
+ spi_set_drvdata(spi, st);
+
+ st->ref_clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(st->ref_clk))
+ return PTR_ERR(st->ref_clk);
+
+ st->ref_freq_hz = clk_get_rate(st->ref_clk);
+ if (st->ref_freq_hz < ADF41513_MIN_REF_FREQ_HZ ||
+ st->ref_freq_hz > ADF41513_MAX_REF_FREQ_HZ)
+ return dev_err_probe(dev, -ERANGE,
+ "reference frequency %u Hz out of range\n",
+ st->ref_freq_hz);
+
+ ret = adf41513_parse_fw(st);
+ if (ret)
+ return ret;
+
+ ret = devm_regulator_bulk_get_enable(dev,
+ ARRAY_SIZE(adf41513_power_supplies),
+ adf41513_power_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to get and enable regulators\n");
+
+ st->lock_detect = devm_gpiod_get_optional(dev, "lock-detect", GPIOD_IN);
+ if (IS_ERR(st->lock_detect))
+ return dev_err_probe(dev, PTR_ERR(st->lock_detect),
+ "fail to request lock detect GPIO\n");
+
+ chip_enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(chip_enable))
+ return dev_err_probe(dev, PTR_ERR(chip_enable),
+ "fail to request chip enable GPIO\n");
+
+ ret = devm_add_action_or_reset(dev, adf41513_chip_disable, chip_enable);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add disable action\n");
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ indio_dev->name = st->chip_info->name;
+ indio_dev->info = &adf41513_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = &adf41513_chan;
+ indio_dev->num_channels = 1;
+
+ ret = adf41513_setup(dev, st);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to setup device\n");
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct spi_device_id adf41513_id[] = {
+ { .name = "adf41510", .driver_data = (kernel_ulong_t)&adf41510_chip_info },
+ { .name = "adf41513", .driver_data = (kernel_ulong_t)&adf41513_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, adf41513_id);
+
+static const struct of_device_id adf41513_of_match[] = {
+ { .compatible = "adi,adf41510", .data = &adf41510_chip_info },
+ { .compatible = "adi,adf41513", .data = &adf41513_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adf41513_of_match);
+
+static DEFINE_SIMPLE_DEV_PM_OPS(adf41513_pm_ops, adf41513_pm_suspend, adf41513_pm_resume);
+
+static struct spi_driver adf41513_driver = {
+ .driver = {
+ .name = "adf41513",
+ .pm = pm_ptr(&adf41513_pm_ops),
+ .of_match_table = adf41513_of_match,
+ },
+ .probe = adf41513_probe,
+ .id_table = adf41513_id,
+};
+module_spi_driver(adf41513_driver);
+
+MODULE_AUTHOR("Rodrigo Alencar <rodrigo.alencar@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADF41513 PLL Frequency Synthesizer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index ed1741165f55..315317d6eec4 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -7,7 +7,6 @@
#include <linux/device.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/slab.h>
@@ -152,10 +151,10 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
st->r4_rf_div_sel = 0;
/*
- * !\TODO: The below computation is making sure we get a power of 2
- * shift (st->r4_rf_div_sel) so that freq becomes higher or equal to
- * ADF4350_MIN_VCO_FREQ. This might be simplified with fls()/fls_long()
- * and friends.
+ * NOTE: This iteratively shifts freq by a power of 2
+ * (st->r4_rf_div_sel) to meet or exceed ADF4350_MIN_VCO_FREQ.
+ * A constant-time approach using fls_long() was attempted but
+ * deemed more complex without meaningful benefit for init code.
*/
while (freq < ADF4350_MIN_VCO_FREQ) {
freq <<= 1;
@@ -607,7 +606,7 @@ static int adf4350_probe(struct spi_device *spi)
if (dev_fwnode(&spi->dev)) {
pdata = adf4350_parse_dt(&spi->dev);
if (pdata == NULL)
- return -EINVAL;
+ return -ENOMEM;
} else {
pdata = dev_get_platdata(&spi->dev);
}
@@ -692,8 +691,8 @@ static const struct of_device_id adf4350_of_match[] = {
MODULE_DEVICE_TABLE(of, adf4350_of_match);
static const struct spi_device_id adf4350_id[] = {
- {"adf4350", 4350},
- {"adf4351", 4351},
+ { .name = "adf4350", .driver_data = 4350 },
+ { .name = "adf4351", .driver_data = 4351 },
{ }
};
MODULE_DEVICE_TABLE(spi, adf4350_id);
diff --git a/drivers/iio/frequency/adf4371.c b/drivers/iio/frequency/adf4371.c
index d6dc7827fb41..e20ed718d01d 100644
--- a/drivers/iio/frequency/adf4371.c
+++ b/drivers/iio/frequency/adf4371.c
@@ -624,8 +624,8 @@ static int adf4371_probe(struct spi_device *spi)
}
static const struct spi_device_id adf4371_id_table[] = {
- { "adf4371", (kernel_ulong_t)&adf4371_chip_info },
- { "adf4372", (kernel_ulong_t)&adf4372_chip_info },
+ { .name = "adf4371", .driver_data = (kernel_ulong_t)&adf4371_chip_info },
+ { .name = "adf4372", .driver_data = (kernel_ulong_t)&adf4372_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, adf4371_id_table);
diff --git a/drivers/iio/frequency/adf4377.c b/drivers/iio/frequency/adf4377.c
index 8e2da218d48a..4dd19a9aa994 100644
--- a/drivers/iio/frequency/adf4377.c
+++ b/drivers/iio/frequency/adf4377.c
@@ -7,6 +7,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
@@ -518,14 +519,15 @@ static int adf4377_get_freq(struct adf4377_state *st, u64 *freq)
u64 clkin_freq;
int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
+
ret = regmap_read(st->regmap, 0x12, &ref_div_factor);
if (ret)
- goto exit;
+ return ret;
ret = regmap_bulk_read(st->regmap, 0x10, st->buf, sizeof(st->buf));
if (ret)
- goto exit;
+ return ret;
clkin_freq = clk_get_rate(st->clkin);
ref_div_factor = FIELD_GET(ADF4377_0012_R_DIV_MSK, ref_div_factor);
@@ -533,10 +535,8 @@ static int adf4377_get_freq(struct adf4377_state *st, u64 *freq)
get_unaligned_le16(&st->buf));
*freq = div_u64(clkin_freq, ref_div_factor) * n_int;
-exit:
- mutex_unlock(&st->lock);
- return ret;
+ return 0;
}
static int adf4377_set_freq(struct adf4377_state *st, u64 freq)
@@ -545,26 +545,24 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq)
u64 f_vco;
int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
- if (freq > ADF4377_MAX_CLKPN_FREQ || freq < ADF4377_MIN_CLKPN_FREQ) {
- ret = -EINVAL;
- goto exit;
- }
+ if (freq > ADF4377_MAX_CLKPN_FREQ || freq < ADF4377_MIN_CLKPN_FREQ)
+ return -EINVAL;
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;
+ return ret;
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;
+ return ret;
ret = regmap_update_bits(st->regmap, 0x2E, ADF4377_002E_EN_ADC_CNV_MSK |
ADF4377_002E_EN_ADC_MSK |
@@ -574,56 +572,56 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq)
FIELD_PREP(ADF4377_002E_ADC_A_CONV_MSK,
ADF4377_002E_ADC_A_CONV_VCO_CALIB));
if (ret)
- goto exit;
+ return ret;
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;
+ return ret;
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;
+ return ret;
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;
+ return ret;
ret = regmap_write(st->regmap, 0x27,
FIELD_PREP(ADF4377_0027_SYNTH_LOCK_TO_LSB_MSK,
st->synth_lock_timeout));
if (ret)
- goto exit;
+ return ret;
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;
+ return ret;
ret = regmap_write(st->regmap, 0x29,
FIELD_PREP(ADF4377_0029_VCO_ALC_TO_LSB_MSK,
st->vco_alc_timeout));
if (ret)
- goto exit;
+ return ret;
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;
+ return ret;
ret = regmap_write(st->regmap, 0x26,
FIELD_PREP(ADF4377_0026_VCO_BAND_DIV_MSK, st->vco_band_div));
if (ret)
- goto exit;
+ return ret;
ret = regmap_write(st->regmap, 0x2D,
FIELD_PREP(ADF4377_002D_ADC_CLK_DIV_MSK, st->adc_clk_div));
if (ret)
- goto exit;
+ return ret;
st->clkout_div_sel = 0;
@@ -641,24 +639,24 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq)
FIELD_PREP(ADF4377_0011_EN_RDBLR_MSK, 0) |
FIELD_PREP(ADF4377_0011_N_INT_MSB_MSK, st->n_int >> 8));
if (ret)
- goto exit;
+ return ret;
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;
+ return ret;
ret = regmap_write(st->regmap, 0x10,
FIELD_PREP(ADF4377_0010_N_INT_LSB_MSK, st->n_int));
if (ret)
- goto exit;
+ return ret;
ret = regmap_read_poll_timeout(st->regmap, 0x49, read_val,
!(read_val & (ADF4377_0049_FSM_BUSY_MSK)), 200, 200 * 100);
if (ret)
- goto exit;
+ return ret;
/* Disable EN_DNCLK, EN_DRCLK */
ret = regmap_update_bits(st->regmap, 0x1C, ADF4377_001C_EN_DNCLK_MSK |
@@ -666,26 +664,21 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq)
FIELD_PREP(ADF4377_001C_EN_DNCLK_MSK, 0) |
FIELD_PREP(ADF4377_001C_EN_DRCLK_MSK, 0));
if (ret)
- goto exit;
+ return ret;
/* 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;
+ return ret;
/* 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;
+ return 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));
}
static void adf4377_gpio_init(struct adf4377_state *st)
@@ -706,23 +699,20 @@ static void adf4377_gpio_init(struct adf4377_state *st)
static int adf4377_init(struct adf4377_state *st)
{
- struct spi_device *spi = st->spi;
+ struct device *dev = &st->spi->dev;
int ret;
adf4377_gpio_init(st);
ret = adf4377_soft_reset(st);
- if (ret) {
- dev_err(&spi->dev, "Failed to soft reset.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to soft reset.\n");
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;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to set default registers.\n");
ret = regmap_update_bits(st->regmap, 0x00,
ADF4377_0000_SDO_ACTIVE_MSK | ADF4377_0000_SDO_ACTIVE_R_MSK,
@@ -730,10 +720,9 @@ static int adf4377_init(struct adf4377_state *st)
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;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to set 4-Wire Operation.\n");
st->clkin_freq = clk_get_rate(st->clkin);
@@ -747,10 +736,9 @@ static int adf4377_init(struct adf4377_state *st)
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;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to set power down registers.\n");
/* Set Mux Output */
ret = regmap_update_bits(st->regmap, 0x1D,
@@ -882,35 +870,35 @@ static const struct iio_chan_spec adf4377_channels[] = {
static int adf4377_properties_parse(struct adf4377_state *st)
{
- struct spi_device *spi = st->spi;
+ struct device *dev = &st->spi->dev;
int ret;
- st->clkin = devm_clk_get_enabled(&spi->dev, "ref_in");
+ st->clkin = devm_clk_get_enabled(dev, "ref_in");
if (IS_ERR(st->clkin))
- return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
+ return dev_err_probe(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",
+ st->gpio_ce = devm_gpiod_get_optional(dev, "chip-enable",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_ce))
- return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_ce),
+ return dev_err_probe(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",
+ st->gpio_enclk1 = devm_gpiod_get_optional(dev, "clk1-enable",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_enclk1))
- return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_enclk1),
+ return dev_err_probe(dev, PTR_ERR(st->gpio_enclk1),
"failed to get the CE GPIO\n");
if (st->chip_info->has_gpio_enclk2) {
- st->gpio_enclk2 = devm_gpiod_get_optional(&st->spi->dev, "clk2-enable",
+ st->gpio_enclk2 = devm_gpiod_get_optional(dev, "clk2-enable",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_enclk2))
- return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_enclk2),
+ return dev_err_probe(dev, PTR_ERR(st->gpio_enclk2),
"failed to get the CE GPIO\n");
}
- ret = device_property_match_property_string(&spi->dev, "adi,muxout-select",
+ ret = device_property_match_property_string(dev, "adi,muxout-select",
adf4377_muxout_modes,
ARRAY_SIZE(adf4377_muxout_modes));
if (ret >= 0)
@@ -924,13 +912,11 @@ static int adf4377_properties_parse(struct adf4377_state *st)
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;
+ guard(mutex)(&st->lock);
+
+ return notifier_from_errno(adf4377_init(st));
}
return NOTIFY_OK;
@@ -1055,9 +1041,10 @@ static int adf4377_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
struct regmap *regmap;
struct adf4377_state *st;
+ struct device *dev = &spi->dev;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -1080,7 +1067,7 @@ static int adf4377_probe(struct spi_device *spi)
return ret;
st->nb.notifier_call = adf4377_freq_change;
- ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb);
+ ret = devm_clk_notifier_register(dev, st->clkin, &st->nb);
if (ret)
return ret;
@@ -1097,12 +1084,12 @@ static int adf4377_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adf4377_channels);
}
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id adf4377_id[] = {
- { "adf4377", (kernel_ulong_t)&adf4377_chip_info },
- { "adf4378", (kernel_ulong_t)&adf4378_chip_info },
+ { .name = "adf4377", .driver_data = (kernel_ulong_t)&adf4377_chip_info },
+ { .name = "adf4378", .driver_data = (kernel_ulong_t)&adf4378_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, adf4377_id);
diff --git a/drivers/iio/frequency/admfm2000.c b/drivers/iio/frequency/admfm2000.c
index b2263b9afeda..0405b53c5851 100644
--- a/drivers/iio/frequency/admfm2000.c
+++ b/drivers/iio/frequency/admfm2000.c
@@ -11,7 +11,6 @@
#include <linux/iio/iio.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c
index d8e8d541990f..c9baaab574e3 100644
--- a/drivers/iio/frequency/admv1013.c
+++ b/drivers/iio/frequency/admv1013.c
@@ -11,7 +11,6 @@
#include <linux/device.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/notifier.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
@@ -85,9 +84,9 @@ enum {
};
enum {
- ADMV1013_SE_MODE_POS = 6,
- ADMV1013_SE_MODE_NEG = 9,
- ADMV1013_SE_MODE_DIFF = 12
+ ADMV1013_SE_MODE_POS,
+ ADMV1013_SE_MODE_NEG,
+ ADMV1013_SE_MODE_DIFF,
};
struct admv1013_state {
@@ -441,7 +440,7 @@ static int admv1013_init(struct admv1013_state *st, int vcm_uv)
{
int ret;
unsigned int data;
- struct spi_device *spi = st->spi;
+ struct device *dev = &st->spi->dev;
/* Perform a software reset */
ret = __admv1013_spi_update_bits(st, ADMV1013_REG_SPI_CONTROL,
@@ -461,19 +460,30 @@ static int admv1013_init(struct admv1013_state *st, int vcm_uv)
return ret;
data = FIELD_GET(ADMV1013_CHIP_ID_MSK, data);
- if (data != ADMV1013_CHIP_ID) {
- dev_err(&spi->dev, "Invalid Chip ID.\n");
- return -EINVAL;
- }
+ if (data != ADMV1013_CHIP_ID)
+ return dev_err_probe(dev, -EINVAL, "Invalid Chip ID.\n");
ret = __admv1013_spi_write(st, ADMV1013_REG_VVA_TEMP_COMP, 0xE700);
if (ret)
return ret;
- data = FIELD_PREP(ADMV1013_QUAD_SE_MODE_MSK, st->quad_se_mode);
+ switch (st->quad_se_mode) {
+ case ADMV1013_SE_MODE_POS:
+ data = 6;
+ break;
+ case ADMV1013_SE_MODE_NEG:
+ data = 9;
+ break;
+ case ADMV1013_SE_MODE_DIFF:
+ data = 12;
+ break;
+ default:
+ return -EINVAL;
+ }
ret = __admv1013_spi_update_bits(st, ADMV1013_REG_QUAD,
- ADMV1013_QUAD_SE_MODE_MSK, data);
+ ADMV1013_QUAD_SE_MODE_MSK,
+ FIELD_PREP(ADMV1013_QUAD_SE_MODE_MSK, data));
if (ret)
return ret;
@@ -514,43 +524,39 @@ static void admv1013_powerdown(void *data)
admv1013_spi_update_bits(data, ADMV1013_REG_ENABLE, enable_reg_msk, enable_reg);
}
+static const char * const admv1013_input_modes[] = {
+ [ADMV1013_IQ_MODE] = "iq",
+ [ADMV1013_IF_MODE] = "if",
+};
+
+static const char * const admv1013_quad_se_modes[] = {
+ [ADMV1013_SE_MODE_POS] = "se-pos",
+ [ADMV1013_SE_MODE_NEG] = "se-neg",
+ [ADMV1013_SE_MODE_DIFF] = "diff",
+};
+
static int admv1013_properties_parse(struct admv1013_state *st)
{
int ret;
- const char *str;
- struct spi_device *spi = st->spi;
+ struct device *dev = &st->spi->dev;
- st->det_en = device_property_read_bool(&spi->dev, "adi,detector-enable");
+ st->det_en = device_property_read_bool(dev, "adi,detector-enable");
- ret = device_property_read_string(&spi->dev, "adi,input-mode", &str);
- if (ret)
- st->input_mode = ADMV1013_IQ_MODE;
+ ret = device_property_match_property_string(dev, "adi,input-mode",
+ admv1013_input_modes,
+ ARRAY_SIZE(admv1013_input_modes));
+ st->input_mode = ret >= 0 ? ret : ADMV1013_IQ_MODE;
- if (!strcmp(str, "iq"))
- st->input_mode = ADMV1013_IQ_MODE;
- else if (!strcmp(str, "if"))
- st->input_mode = ADMV1013_IF_MODE;
- else
- return -EINVAL;
+ ret = device_property_match_property_string(dev, "adi,quad-se-mode",
+ admv1013_quad_se_modes,
+ ARRAY_SIZE(admv1013_quad_se_modes));
+ st->quad_se_mode = ret >= 0 ? ret : ADMV1013_SE_MODE_DIFF;
- ret = device_property_read_string(&spi->dev, "adi,quad-se-mode", &str);
- if (ret)
- st->quad_se_mode = ADMV1013_SE_MODE_DIFF;
-
- if (!strcmp(str, "diff"))
- st->quad_se_mode = ADMV1013_SE_MODE_DIFF;
- else if (!strcmp(str, "se-pos"))
- st->quad_se_mode = ADMV1013_SE_MODE_POS;
- else if (!strcmp(str, "se-neg"))
- st->quad_se_mode = ADMV1013_SE_MODE_NEG;
- else
- return -EINVAL;
-
- ret = devm_regulator_bulk_get_enable(&st->spi->dev,
+ ret = devm_regulator_bulk_get_enable(dev,
ARRAY_SIZE(admv1013_vcc_regs),
admv1013_vcc_regs);
if (ret) {
- dev_err_probe(&spi->dev, ret,
+ dev_err_probe(dev, ret,
"Failed to request VCC regulators\n");
return ret;
}
@@ -562,9 +568,10 @@ static int admv1013_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct admv1013_state *st;
+ struct device *dev = &spi->dev;
int ret, vcm_uv;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -581,40 +588,38 @@ static int admv1013_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcm");
+ ret = devm_regulator_get_enable_read_voltage(dev, "vcm");
if (ret < 0)
- return dev_err_probe(&spi->dev, ret,
+ return dev_err_probe(dev, ret,
"failed to get the common-mode voltage\n");
vcm_uv = ret;
- st->clkin = devm_clk_get_enabled(&spi->dev, "lo_in");
+ st->clkin = devm_clk_get_enabled(dev, "lo_in");
if (IS_ERR(st->clkin))
- return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
+ return dev_err_probe(dev, PTR_ERR(st->clkin),
"failed to get the LO input clock\n");
st->nb.notifier_call = admv1013_freq_change;
- ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb);
+ ret = devm_clk_notifier_register(dev, st->clkin, &st->nb);
if (ret)
return ret;
mutex_init(&st->lock);
ret = admv1013_init(st, vcm_uv);
- if (ret) {
- dev_err(&spi->dev, "admv1013 init failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "admv1013 init failed\n");
- ret = devm_add_action_or_reset(&spi->dev, admv1013_powerdown, st);
+ ret = devm_add_action_or_reset(dev, admv1013_powerdown, st);
if (ret)
return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id admv1013_id[] = {
- { "admv1013", 0 },
+ { .name = "admv1013" },
{ }
};
MODULE_DEVICE_TABLE(spi, admv1013_id);
diff --git a/drivers/iio/frequency/admv1014.c b/drivers/iio/frequency/admv1014.c
index 7a8f92ec80a2..d1d528975229 100644
--- a/drivers/iio/frequency/admv1014.c
+++ b/drivers/iio/frequency/admv1014.c
@@ -12,7 +12,6 @@
#include <linux/device.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/notifier.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
@@ -610,15 +609,14 @@ static int admv1014_init(struct admv1014_state *st)
{
unsigned int chip_id, enable_reg, enable_reg_msk;
struct spi_device *spi = st->spi;
+ struct device *dev = &spi->dev;
int ret;
ret = regulator_bulk_enable(ADMV1014_NUM_REGULATORS, st->regulators);
- if (ret) {
- dev_err(&spi->dev, "Failed to enable regulators");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable regulators");
- ret = devm_add_action_or_reset(&spi->dev, admv1014_reg_disable, st->regulators);
+ ret = devm_add_action_or_reset(dev, admv1014_reg_disable, st->regulators);
if (ret)
return ret;
@@ -626,16 +624,16 @@ static int admv1014_init(struct admv1014_state *st)
if (ret)
return ret;
- ret = devm_add_action_or_reset(&spi->dev, admv1014_clk_disable, st->clkin);
+ ret = devm_add_action_or_reset(dev, admv1014_clk_disable, st->clkin);
if (ret)
return ret;
st->nb.notifier_call = admv1014_freq_change;
- ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb);
+ ret = devm_clk_notifier_register(dev, st->clkin, &st->nb);
if (ret)
return ret;
- ret = devm_add_action_or_reset(&spi->dev, admv1014_powerdown, st);
+ ret = devm_add_action_or_reset(dev, admv1014_powerdown, st);
if (ret)
return ret;
@@ -643,55 +641,47 @@ static int admv1014_init(struct admv1014_state *st)
ret = __admv1014_spi_update_bits(st, ADMV1014_REG_SPI_CONTROL,
ADMV1014_SPI_SOFT_RESET_MSK,
FIELD_PREP(ADMV1014_SPI_SOFT_RESET_MSK, 1));
- if (ret) {
- dev_err(&spi->dev, "ADMV1014 SPI software reset failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "ADMV1014 SPI software reset failed.\n");
ret = __admv1014_spi_update_bits(st, ADMV1014_REG_SPI_CONTROL,
ADMV1014_SPI_SOFT_RESET_MSK,
FIELD_PREP(ADMV1014_SPI_SOFT_RESET_MSK, 0));
- if (ret) {
- dev_err(&spi->dev, "ADMV1014 SPI software reset disable failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "ADMV1014 SPI software reset disable failed.\n");
ret = __admv1014_spi_write(st, ADMV1014_REG_VVA_TEMP_COMP, 0x727C);
- if (ret) {
- dev_err(&spi->dev, "Writing default Temperature Compensation value failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Writing default Temperature Compensation value failed.\n");
ret = __admv1014_spi_read(st, ADMV1014_REG_SPI_CONTROL, &chip_id);
if (ret)
return ret;
chip_id = FIELD_GET(ADMV1014_CHIP_ID_MSK, chip_id);
- if (chip_id != ADMV1014_CHIP_ID) {
- dev_err(&spi->dev, "Invalid Chip ID.\n");
- return -EINVAL;
- }
+ if (chip_id != ADMV1014_CHIP_ID)
+ return dev_err_probe(dev, -EINVAL, "Invalid Chip ID.\n");
ret = __admv1014_spi_update_bits(st, ADMV1014_REG_QUAD,
ADMV1014_QUAD_SE_MODE_MSK,
FIELD_PREP(ADMV1014_QUAD_SE_MODE_MSK,
st->quad_se_mode));
- if (ret) {
- dev_err(&spi->dev, "Writing Quad SE Mode failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Writing Quad SE Mode failed.\n");
ret = admv1014_update_quad_filters(st);
- if (ret) {
- dev_err(&spi->dev, "Update Quad Filters failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Update Quad Filters failed.\n");
ret = admv1014_update_vcm_settings(st);
- if (ret) {
- dev_err(&spi->dev, "Update VCM Settings failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Update VCM Settings failed.\n");
enable_reg_msk = ADMV1014_P1DB_COMPENSATION_MSK |
ADMV1014_IF_AMP_PD_MSK |
@@ -712,13 +702,14 @@ static int admv1014_properties_parse(struct admv1014_state *st)
{
unsigned int i;
struct spi_device *spi = st->spi;
+ struct device *dev = &spi->dev;
int ret;
- st->det_en = device_property_read_bool(&spi->dev, "adi,detector-enable");
+ st->det_en = device_property_read_bool(dev, "adi,detector-enable");
- st->p1db_comp = device_property_read_bool(&spi->dev, "adi,p1db-compensation-enable");
+ st->p1db_comp = device_property_read_bool(dev, "adi,p1db-compensation-enable");
- ret = device_property_match_property_string(&spi->dev, "adi,input-mode",
+ ret = device_property_match_property_string(dev, "adi,input-mode",
input_mode_names,
ARRAY_SIZE(input_mode_names));
if (ret >= 0)
@@ -726,7 +717,7 @@ static int admv1014_properties_parse(struct admv1014_state *st)
else
st->input_mode = ADMV1014_IQ_MODE;
- ret = device_property_match_property_string(&spi->dev, "adi,quad-se-mode",
+ ret = device_property_match_property_string(dev, "adi,quad-se-mode",
quad_se_mode_names,
ARRAY_SIZE(quad_se_mode_names));
if (ret >= 0)
@@ -737,16 +728,14 @@ static int admv1014_properties_parse(struct admv1014_state *st)
for (i = 0; i < ADMV1014_NUM_REGULATORS; ++i)
st->regulators[i].supply = admv1014_reg_name[i];
- ret = devm_regulator_bulk_get(&st->spi->dev, ADMV1014_NUM_REGULATORS,
+ ret = devm_regulator_bulk_get(dev, ADMV1014_NUM_REGULATORS,
st->regulators);
- if (ret) {
- dev_err(&spi->dev, "Failed to request regulators");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request regulators");
- st->clkin = devm_clk_get(&spi->dev, "lo_in");
+ st->clkin = devm_clk_get(dev, "lo_in");
if (IS_ERR(st->clkin))
- return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
+ return dev_err_probe(dev, PTR_ERR(st->clkin),
"failed to get the LO input clock\n");
return 0;
@@ -756,9 +745,10 @@ static int admv1014_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct admv1014_state *st;
+ struct device *dev = &spi->dev;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -787,11 +777,11 @@ static int admv1014_probe(struct spi_device *spi)
if (ret)
return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id admv1014_id[] = {
- { "admv1014", 0 },
+ { .name = "admv1014" },
{ }
};
MODULE_DEVICE_TABLE(spi, admv1014_id);
diff --git a/drivers/iio/frequency/admv4420.c b/drivers/iio/frequency/admv4420.c
index 3ae462b4f5c9..618511eddfb1 100644
--- a/drivers/iio/frequency/admv4420.c
+++ b/drivers/iio/frequency/admv4420.c
@@ -243,7 +243,7 @@ static int admv4420_calc_parameters(struct admv4420_state *st)
st->n_counter.n_counter = 1;
}
if (!sol_found)
- return -1;
+ return -EINVAL;
st->n_counter.int_val = div_u64_rem(st->n_counter.n_counter, 10, &st->n_counter.frac_val);
st->n_counter.mod_val = 10;
@@ -279,10 +279,9 @@ static int admv4420_setup(struct iio_dev *indio_dev)
if (ret)
return ret;
- if (val != ADMV4420_SCRATCH_PAD_VAL_1) {
- dev_err(dev, "Failed ADMV4420 to read/write scratchpad %x ", val);
- return -EIO;
- }
+ if (val != ADMV4420_SCRATCH_PAD_VAL_1)
+ return dev_err_probe(dev, -EIO,
+ "Failed ADMV4420 to read/write scratchpad %x\n", val);
ret = regmap_write(st->regmap,
ADMV4420_SCRATCHPAD,
@@ -294,10 +293,9 @@ static int admv4420_setup(struct iio_dev *indio_dev)
if (ret)
return ret;
- if (val != ADMV4420_SCRATCH_PAD_VAL_2) {
- dev_err(dev, "Failed to read/write scratchpad %x ", val);
- return -EIO;
- }
+ if (val != ADMV4420_SCRATCH_PAD_VAL_2)
+ return dev_err_probe(dev, -EIO,
+ "Failed to read/write scratchpad %x\n", val);
st->mux_sel = ADMV4420_LOCK_DTCT;
st->lo_freq_hz = ADMV4420_DEFAULT_LO_FREQ_HZ;
@@ -305,10 +303,10 @@ static int admv4420_setup(struct iio_dev *indio_dev)
admv4420_fw_parse(st);
ret = admv4420_calc_parameters(st);
- if (ret) {
- dev_err(dev, "Failed calc parameters for %lld ", st->vco_freq_hz);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed calc parameters for %llu\n",
+ st->vco_freq_hz);
ret = regmap_write(st->regmap, ADMV4420_R_DIV_L,
FIELD_GET(0xFF, st->ref_block.divider));
@@ -344,18 +342,19 @@ static int admv4420_setup(struct iio_dev *indio_dev)
static int admv4420_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
struct iio_dev *indio_dev;
struct admv4420_state *st;
struct regmap *regmap;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
regmap = devm_regmap_init_spi(spi, &admv4420_regmap_config);
if (IS_ERR(regmap))
- return dev_err_probe(&spi->dev, PTR_ERR(regmap),
+ return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to initializing spi regmap\n");
st = iio_priv(indio_dev);
@@ -368,12 +367,10 @@ static int admv4420_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(admv4420_channels);
ret = admv4420_setup(indio_dev);
- if (ret) {
- dev_err(&spi->dev, "Setup ADMV4420 failed (%d)\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Setup ADMV4420 failed\n");
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id admv4420_of_match[] = {
diff --git a/drivers/iio/frequency/adrf6780.c b/drivers/iio/frequency/adrf6780.c
index a7a21f929970..79a615062172 100644
--- a/drivers/iio/frequency/adrf6780.c
+++ b/drivers/iio/frequency/adrf6780.c
@@ -13,7 +13,6 @@
#include <linux/device.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/unaligned.h>
@@ -188,8 +187,11 @@ static int adrf6780_read_adc_raw(struct adrf6780_state *st, unsigned int *read_v
if (ret)
goto exit;
- /* Recommended delay for the ADC to be ready*/
- usleep_range(200, 250);
+ /*
+ * Per ADRF6780 datasheet (Rev. D, page 23, ADC section),
+ * wait approximately 200 us for the ADC to be ready.
+ */
+ fsleep(200);
ret = __adrf6780_spi_read(st, ADRF6780_REG_ADC_OUTPUT, read_val);
if (ret)
@@ -346,23 +348,21 @@ static const struct iio_chan_spec adrf6780_channels[] = {
static int adrf6780_reset(struct adrf6780_state *st)
{
int ret;
- struct spi_device *spi = st->spi;
+ struct device *dev = &st->spi->dev;
ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_CONTROL,
ADRF6780_SOFT_RESET_MSK,
FIELD_PREP(ADRF6780_SOFT_RESET_MSK, 1));
- if (ret) {
- dev_err(&spi->dev, "ADRF6780 SPI software reset failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "ADRF6780 SPI software reset failed.\n");
ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_CONTROL,
ADRF6780_SOFT_RESET_MSK,
FIELD_PREP(ADRF6780_SOFT_RESET_MSK, 0));
- if (ret) {
- dev_err(&spi->dev, "ADRF6780 SPI software reset disable failed.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "ADRF6780 SPI software reset disable failed.\n");
return 0;
}
@@ -371,7 +371,7 @@ static int adrf6780_init(struct adrf6780_state *st)
{
int ret;
unsigned int chip_id, enable_reg, enable_reg_msk;
- struct spi_device *spi = st->spi;
+ struct device *dev = &st->spi->dev;
/* Perform a software reset */
ret = adrf6780_reset(st);
@@ -383,10 +383,9 @@ static int adrf6780_init(struct adrf6780_state *st)
return ret;
chip_id = FIELD_GET(ADRF6780_CHIP_ID_MSK, chip_id);
- if (chip_id != ADRF6780_CHIP_ID) {
- dev_err(&spi->dev, "ADRF6780 Invalid Chip ID.\n");
- return -EINVAL;
- }
+ if (chip_id != ADRF6780_CHIP_ID)
+ return dev_err_probe(dev, -EINVAL,
+ "ADRF6780 Invalid Chip ID.\n");
enable_reg_msk = ADRF6780_VGA_BUFFER_EN_MSK |
ADRF6780_DETECTOR_EN_MSK |
@@ -426,18 +425,18 @@ static int adrf6780_init(struct adrf6780_state *st)
static void adrf6780_properties_parse(struct adrf6780_state *st)
{
- struct spi_device *spi = st->spi;
-
- st->vga_buff_en = device_property_read_bool(&spi->dev, "adi,vga-buff-en");
- st->lo_buff_en = device_property_read_bool(&spi->dev, "adi,lo-buff-en");
- st->if_mode_en = device_property_read_bool(&spi->dev, "adi,if-mode-en");
- st->iq_mode_en = device_property_read_bool(&spi->dev, "adi,iq-mode-en");
- st->lo_x2_en = device_property_read_bool(&spi->dev, "adi,lo-x2-en");
- st->lo_ppf_en = device_property_read_bool(&spi->dev, "adi,lo-ppf-en");
- st->lo_en = device_property_read_bool(&spi->dev, "adi,lo-en");
- st->uc_bias_en = device_property_read_bool(&spi->dev, "adi,uc-bias-en");
- st->lo_sideband = device_property_read_bool(&spi->dev, "adi,lo-sideband");
- st->vdet_out_en = device_property_read_bool(&spi->dev, "adi,vdet-out-en");
+ struct device *dev = &st->spi->dev;
+
+ st->vga_buff_en = device_property_read_bool(dev, "adi,vga-buff-en");
+ st->lo_buff_en = device_property_read_bool(dev, "adi,lo-buff-en");
+ st->if_mode_en = device_property_read_bool(dev, "adi,if-mode-en");
+ st->iq_mode_en = device_property_read_bool(dev, "adi,iq-mode-en");
+ st->lo_x2_en = device_property_read_bool(dev, "adi,lo-x2-en");
+ st->lo_ppf_en = device_property_read_bool(dev, "adi,lo-ppf-en");
+ st->lo_en = device_property_read_bool(dev, "adi,lo-en");
+ st->uc_bias_en = device_property_read_bool(dev, "adi,uc-bias-en");
+ st->lo_sideband = device_property_read_bool(dev, "adi,lo-sideband");
+ st->vdet_out_en = device_property_read_bool(dev, "adi,vdet-out-en");
}
static void adrf6780_powerdown(void *data)
@@ -450,9 +449,10 @@ static int adrf6780_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct adrf6780_state *st;
+ struct device *dev = &spi->dev;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -467,9 +467,9 @@ static int adrf6780_probe(struct spi_device *spi)
adrf6780_properties_parse(st);
- st->clkin = devm_clk_get_enabled(&spi->dev, "lo_in");
+ st->clkin = devm_clk_get_enabled(dev, "lo_in");
if (IS_ERR(st->clkin))
- return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
+ return dev_err_probe(dev, PTR_ERR(st->clkin),
"failed to get the LO input clock\n");
mutex_init(&st->lock);
@@ -478,15 +478,15 @@ static int adrf6780_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_add_action_or_reset(&spi->dev, adrf6780_powerdown, st);
+ ret = devm_add_action_or_reset(dev, adrf6780_powerdown, st);
if (ret)
return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id adrf6780_id[] = {
- { "adrf6780", 0 },
+ { .name = "adrf6780" },
{ }
};
MODULE_DEVICE_TABLE(spi, adrf6780_id);
diff --git a/drivers/iio/gyro/adis16080.c b/drivers/iio/gyro/adis16080.c
index 178bba95a709..0c8bc1e569fe 100644
--- a/drivers/iio/gyro/adis16080.c
+++ b/drivers/iio/gyro/adis16080.c
@@ -212,8 +212,8 @@ static int adis16080_probe(struct spi_device *spi)
}
static const struct spi_device_id adis16080_ids[] = {
- { "adis16080", ID_ADIS16080 },
- { "adis16100", ID_ADIS16100 },
+ { .name = "adis16080", .driver_data = ID_ADIS16080 },
+ { .name = "adis16100", .driver_data = ID_ADIS16100 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16080_ids);
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c
index 369c7428e1ef..ff335f81e9ae 100644
--- a/drivers/iio/gyro/adis16136.c
+++ b/drivers/iio/gyro/adis16136.c
@@ -563,10 +563,10 @@ static int adis16136_probe(struct spi_device *spi)
}
static const struct spi_device_id adis16136_ids[] = {
- { "adis16133", ID_ADIS16133 },
- { "adis16135", ID_ADIS16135 },
- { "adis16136", ID_ADIS16136 },
- { "adis16137", ID_ADIS16137 },
+ { .name = "adis16133", .driver_data = ID_ADIS16133 },
+ { .name = "adis16135", .driver_data = ID_ADIS16135 },
+ { .name = "adis16136", .driver_data = ID_ADIS16136 },
+ { .name = "adis16137", .driver_data = ID_ADIS16137 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16136_ids);
diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c
index 586e6cfa14a9..a79a8edf4c98 100644
--- a/drivers/iio/gyro/adis16260.c
+++ b/drivers/iio/gyro/adis16260.c
@@ -287,6 +287,9 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
addr = adis16260_addresses[chan->scan_index][1];
return adis_write_reg_16(adis, addr, val);
case IIO_CHAN_INFO_SAMP_FREQ:
+ if (val <= 0)
+ return -EINVAL;
+
if (spi_get_device_id(adis->spi)->driver_data)
t = 256 / val;
else
@@ -408,12 +411,12 @@ static int adis16260_probe(struct spi_device *spi)
* support for the on chip filtering.
*/
static const struct spi_device_id adis16260_id[] = {
- {"adis16260", ADIS16260},
- {"adis16265", ADIS16260},
- {"adis16266", ADIS16266},
- {"adis16250", ADIS16260},
- {"adis16255", ADIS16260},
- {"adis16251", ADIS16251},
+ { .name = "adis16260", .driver_data = ADIS16260 },
+ { .name = "adis16265", .driver_data = ADIS16260 },
+ { .name = "adis16266", .driver_data = ADIS16266 },
+ { .name = "adis16250", .driver_data = ADIS16260 },
+ { .name = "adis16255", .driver_data = ADIS16260 },
+ { .name = "adis16251", .driver_data = ADIS16251 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16260_id);
diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c
index 3efe385ebedc..563de2724396 100644
--- a/drivers/iio/gyro/adxrs290.c
+++ b/drivers/iio/gyro/adxrs290.c
@@ -8,6 +8,7 @@
#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
@@ -115,65 +116,53 @@ static const int adxrs290_hpf_3db_freq_hz_table[][2] = {
static int adxrs290_get_rate_data(struct iio_dev *indio_dev, const u8 cmd, int *val)
{
struct adxrs290_state *st = iio_priv(indio_dev);
- int ret = 0;
int temp;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
+
temp = spi_w8r16(st->spi, cmd);
- if (temp < 0) {
- ret = temp;
- goto err_unlock;
- }
+ if (temp < 0)
+ return temp;
*val = sign_extend32(temp, 15);
-err_unlock:
- mutex_unlock(&st->lock);
- return ret;
+ return 0;
}
static int adxrs290_get_temp_data(struct iio_dev *indio_dev, int *val)
{
const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_TEMP0);
struct adxrs290_state *st = iio_priv(indio_dev);
- int ret = 0;
int temp;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
+
temp = spi_w8r16(st->spi, cmd);
- if (temp < 0) {
- ret = temp;
- goto err_unlock;
- }
+ if (temp < 0)
+ return temp;
/* extract lower 12 bits temperature reading */
*val = sign_extend32(temp, 11);
-err_unlock:
- mutex_unlock(&st->lock);
- return ret;
+ return 0;
}
static int adxrs290_get_3db_freq(struct iio_dev *indio_dev, u8 *val, u8 *val2)
{
const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_FILTER);
struct adxrs290_state *st = iio_priv(indio_dev);
- int ret = 0;
short temp;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
+
temp = spi_w8r8(st->spi, cmd);
- if (temp < 0) {
- ret = temp;
- goto err_unlock;
- }
+ if (temp < 0)
+ return temp;
*val = FIELD_GET(ADXRS290_LPF_MASK, temp);
*val2 = FIELD_GET(ADXRS290_HPF_MASK, temp);
-err_unlock:
- mutex_unlock(&st->lock);
- return ret;
+ return 0;
}
static int adxrs290_spi_write_reg(struct spi_device *spi, const u8 reg,
@@ -220,11 +209,11 @@ static int adxrs290_set_mode(struct iio_dev *indio_dev, enum adxrs290_mode mode)
if (st->mode == mode)
return 0;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
ret = spi_w8r8(st->spi, ADXRS290_READ_REG(ADXRS290_REG_POWER_CTL));
if (ret < 0)
- goto out_unlock;
+ return ret;
val = ret;
@@ -236,21 +225,18 @@ static int adxrs290_set_mode(struct iio_dev *indio_dev, enum adxrs290_mode mode)
val |= ADXRS290_MEASUREMENT;
break;
default:
- ret = -EINVAL;
- goto out_unlock;
+ return -EINVAL;
}
ret = adxrs290_spi_write_reg(st->spi, ADXRS290_REG_POWER_CTL, val);
if (ret < 0) {
dev_err(&st->spi->dev, "unable to set mode: %d\n", ret);
- goto out_unlock;
+ return ret;
}
/* update cached mode */
st->mode = mode;
-out_unlock:
- mutex_unlock(&st->lock);
return ret;
}
@@ -506,19 +492,20 @@ static irqreturn_t adxrs290_trigger_handler(int irq, void *p)
u8 tx = ADXRS290_READ_REG(ADXRS290_REG_DATAX0);
int ret;
- mutex_lock(&st->lock);
+ do {
+ guard(mutex)(&st->lock);
- /* exercise a bulk data capture starting from reg DATAX0... */
- ret = spi_write_then_read(st->spi, &tx, sizeof(tx), st->buffer.channels,
- sizeof(st->buffer.channels));
- if (ret < 0)
- goto out_unlock_notify;
+ /* exercise a bulk data capture starting from reg DATAX0... */
+ ret = spi_write_then_read(st->spi, &tx, sizeof(tx),
+ st->buffer.channels,
+ sizeof(st->buffer.channels));
+ if (ret < 0)
+ break;
- iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer,
- pf->timestamp);
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer,
+ pf->timestamp);
+ } while (0);
-out_unlock_notify:
- mutex_unlock(&st->lock);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
@@ -598,9 +585,8 @@ static int adxrs290_probe_trigger(struct iio_dev *indio_dev)
ret = devm_request_irq(&st->spi->dev, st->spi->irq,
&iio_trigger_generic_data_rdy_poll,
IRQF_NO_THREAD, "adxrs290_irq", st->dready_trig);
- if (ret < 0)
- return dev_err_probe(&st->spi->dev, ret,
- "request irq %d failed\n", st->spi->irq);
+ if (ret)
+ return ret;
ret = devm_iio_trigger_register(&st->spi->dev, st->dready_trig);
if (ret) {
diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c
index a1d8d3cb301b..030d042cab8b 100644
--- a/drivers/iio/gyro/adxrs450.c
+++ b/drivers/iio/gyro/adxrs450.c
@@ -439,8 +439,8 @@ static int adxrs450_probe(struct spi_device *spi)
}
static const struct spi_device_id adxrs450_id[] = {
- {"adxrs450", ID_ADXRS450},
- {"adxrs453", ID_ADXRS453},
+ { .name = "adxrs450", .driver_data = ID_ADXRS450 },
+ { .name = "adxrs453", .driver_data = ID_ADXRS453 },
{ }
};
MODULE_DEVICE_TABLE(spi, adxrs450_id);
diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
index 38394b5f3275..d611341a0e2a 100644
--- a/drivers/iio/gyro/bmg160_core.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -201,6 +201,9 @@ static int bmg160_get_filter(struct bmg160_data *data, int *val)
break;
}
+ if (i == ARRAY_SIZE(bmg160_samp_freq_table))
+ return -EINVAL;
+
*val = bmg160_samp_freq_table[i].filter;
return ret ? ret : IIO_VAL_INT;
@@ -218,6 +221,9 @@ static int bmg160_set_filter(struct bmg160_data *data, int val)
break;
}
+ if (i == ARRAY_SIZE(bmg160_samp_freq_table))
+ return -EINVAL;
+
ret = regmap_write(data->regmap, BMG160_REG_PMU_BW,
bmg160_samp_freq_table[i].bw_bits);
if (ret < 0) {
@@ -258,8 +264,14 @@ static int bmg160_chip_init(struct bmg160_data *data)
if (ret < 0)
return ret;
- /* Wait upto 500 ms to be ready after changing mode */
- usleep_range(500, 1000);
+ /*
+ * Wait for the chip to be ready after switching to normal mode.
+ * The BMG160 datasheet (BST-BMG160-DS000-07 Rev. 1.0, May 2013)
+ * specifies a start-up / wake-up time (tsu, twusm) of 30 ms; use
+ * BMG160_MAX_STARTUP_TIME_MS (80 ms) as a safety margin, matching
+ * what bmg160_runtime_resume() already does.
+ */
+ msleep(BMG160_MAX_STARTUP_TIME_MS);
/* Set Bandwidth */
ret = bmg160_set_bw(data, BMG160_DEF_BW);
diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c
index 1fb8a7969c25..be3cfbd286aa 100644
--- a/drivers/iio/gyro/bmg160_i2c.c
+++ b/drivers/iio/gyro/bmg160_i2c.c
@@ -3,7 +3,6 @@
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include "bmg160.h"
@@ -47,9 +46,9 @@ static const struct acpi_device_id bmg160_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match);
static const struct i2c_device_id bmg160_i2c_id[] = {
- { "bmg160" },
- { "bmi055_gyro" },
- { "bmi088_gyro" },
+ { .name = "bmg160" },
+ { .name = "bmi055_gyro" },
+ { .name = "bmi088_gyro" },
{ }
};
diff --git a/drivers/iio/gyro/bmg160_spi.c b/drivers/iio/gyro/bmg160_spi.c
index 6aecc5eb8347..14ae1d03be3d 100644
--- a/drivers/iio/gyro/bmg160_spi.c
+++ b/drivers/iio/gyro/bmg160_spi.c
@@ -33,12 +33,11 @@ static void bmg160_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id bmg160_spi_id[] = {
- {"bmg160", 0},
- {"bmi055_gyro", 0},
- {"bmi088_gyro", 0},
+ { .name = "bmg160" },
+ { .name = "bmi055_gyro" },
+ { .name = "bmi088_gyro" },
{ }
};
-
MODULE_DEVICE_TABLE(spi, bmg160_spi_id);
static const struct of_device_id bmg160_of_match[] = {
diff --git a/drivers/iio/gyro/fxas21002c_i2c.c b/drivers/iio/gyro/fxas21002c_i2c.c
index 43c6b3079487..634f9019aa96 100644
--- a/drivers/iio/gyro/fxas21002c_i2c.c
+++ b/drivers/iio/gyro/fxas21002c_i2c.c
@@ -7,7 +7,6 @@
#include <linux/err.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -39,7 +38,7 @@ static void fxas21002c_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id fxas21002c_i2c_id[] = {
- { "fxas21002c" },
+ { .name = "fxas21002c" },
{ }
};
MODULE_DEVICE_TABLE(i2c, fxas21002c_i2c_id);
diff --git a/drivers/iio/gyro/fxas21002c_spi.c b/drivers/iio/gyro/fxas21002c_spi.c
index d62efe50b697..40b1e02b2a5c 100644
--- a/drivers/iio/gyro/fxas21002c_spi.c
+++ b/drivers/iio/gyro/fxas21002c_spi.c
@@ -6,7 +6,6 @@
*/
#include <linux/err.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -40,7 +39,7 @@ static void fxas21002c_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id fxas21002c_spi_id[] = {
- { "fxas21002c", 0 },
+ { .name = "fxas21002c" },
{ }
};
MODULE_DEVICE_TABLE(spi, fxas21002c_spi_id);
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index c43990c518f7..58250a972567 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -3,10 +3,10 @@
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*/
+#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
@@ -42,7 +42,7 @@ static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = {
HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS
};
-static const u32 gryo_3d_sensitivity_addresses[] = {
+static const u32 gyro_3d_sensitivity_addresses[] = {
HID_USAGE_SENSOR_DATA_ANGL_VELOCITY,
};
@@ -82,22 +82,10 @@ static const struct iio_chan_spec gyro_3d_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
};
-/* Adjust channel real bits based on report descriptor */
-static void gyro_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
- int channel, int size)
-{
- channels[channel].scan_type.sign = 's';
- /* Real storage bits will change based on the report desc. */
- channels[channel].scan_type.realbits = size * 8;
- /* Maximum size of a sample to capture is u32 */
- channels[channel].scan_type.storagebits = sizeof(u32) * 8;
-}
-
/* Channel read_raw handler */
static int gyro_3d_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
int report_id = -1;
@@ -122,8 +110,7 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev,
min < 0);
else {
*val = 0;
- hid_sensor_power_state(&gyro_state->common_attributes,
- false);
+ hid_sensor_power_state(&gyro_state->common_attributes, false);
return -EINVAL;
}
hid_sensor_power_state(&gyro_state->common_attributes, false);
@@ -156,10 +143,8 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int gyro_3d_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
int ret = 0;
@@ -187,8 +172,7 @@ static const struct iio_info gyro_3d_info = {
/* Callback handler to send event after all samples are received and captured */
static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
@@ -209,9 +193,9 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
@@ -244,29 +228,30 @@ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
static int gyro_3d_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
struct iio_chan_spec *channels,
- unsigned usage_id,
+ u32 usage_id,
struct gyro_3d_state *st)
{
int ret;
- int i;
- for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
+ for (unsigned int ch = CHANNEL_SCAN_INDEX_X; ch <= CHANNEL_SCAN_INDEX_Z; ch++) {
ret = sensor_hub_input_get_attribute_info(hsdev,
HID_INPUT_REPORT,
usage_id,
- HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + i,
- &st->gyro[CHANNEL_SCAN_INDEX_X + i]);
+ HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + ch,
+ &st->gyro[ch]);
if (ret < 0)
break;
- gyro_3d_adjust_channel_bit_mask(channels,
- CHANNEL_SCAN_INDEX_X + i,
- st->gyro[CHANNEL_SCAN_INDEX_X + i].size);
+ channels[ch].scan_type = (struct iio_scan_type) {
+ .format = 's',
+ .realbits = BYTES_TO_BITS(st->gyro[ch].size),
+ .storagebits = BITS_PER_TYPE(u32),
+ };
}
dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n",
- st->gyro[0].index,
- st->gyro[0].report_id,
- st->gyro[1].index, st->gyro[1].report_id,
- st->gyro[2].index, st->gyro[2].report_id);
+ st->gyro[0].index,
+ st->gyro[0].report_id,
+ st->gyro[1].index, st->gyro[1].report_id,
+ st->gyro[2].index, st->gyro[2].report_id);
st->scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_GYRO_3D,
@@ -297,8 +282,8 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
ret = hid_sensor_parse_common_attributes(hsdev,
HID_USAGE_SENSOR_GYRO_3D,
&gyro_state->common_attributes,
- gryo_3d_sensitivity_addresses,
- ARRAY_SIZE(gryo_3d_sensitivity_addresses));
+ gyro_3d_sensitivity_addresses,
+ ARRAY_SIZE(gyro_3d_sensitivity_addresses));
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
@@ -327,32 +312,32 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
atomic_set(&gyro_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &gyro_state->common_attributes);
+ &gyro_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
gyro_state->callbacks.send_event = gyro_3d_proc_event;
gyro_state->callbacks.capture_sample = gyro_3d_capture_sample;
gyro_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D,
- &gyro_state->callbacks);
+ &gyro_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
return ret;
@@ -365,8 +350,8 @@ static void hid_gyro_3d_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
}
diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c
index cf97adfa9727..87efa2c74ca4 100644
--- a/drivers/iio/gyro/itg3200_buffer.c
+++ b/drivers/iio/gyro/itg3200_buffer.c
@@ -34,7 +34,7 @@ static int itg3200_read_all_channels(struct i2c_client *i2c, __be16 *buf)
.addr = i2c->addr,
.flags = i2c->flags | I2C_M_RD,
.len = ITG3200_SCAN_ELEMENTS * sizeof(s16),
- .buf = (char *)&buf,
+ .buf = (char *)buf,
},
};
diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c
index bfe95ec1abda..6b13d54d9b01 100644
--- a/drivers/iio/gyro/itg3200_core.c
+++ b/drivers/iio/gyro/itg3200_core.c
@@ -389,7 +389,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(itg3200_pm_ops, itg3200_suspend,
itg3200_resume);
static const struct i2c_device_id itg3200_id[] = {
- { "itg3200" },
+ { .name = "itg3200" },
{ }
};
MODULE_DEVICE_TABLE(i2c, itg3200_id);
diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c
index 317e7b217ec6..07c0f9011c63 100644
--- a/drivers/iio/gyro/mpu3050-core.c
+++ b/drivers/iio/gyro/mpu3050-core.c
@@ -356,7 +356,7 @@ static int mpu3050_read_raw(struct iio_dev *indio_dev,
goto out_read_raw_unlock;
}
- *val = be16_to_cpu(raw_val);
+ *val = (s16)be16_to_cpu(raw_val);
ret = IIO_VAL_INT;
goto out_read_raw_unlock;
@@ -1129,11 +1129,16 @@ static int mpu3050_trigger_probe(struct iio_dev *indio_dev, int irq)
ret = iio_trigger_register(mpu3050->trig);
if (ret)
- return ret;
+ goto err_iio_trigger;
indio_dev->trig = iio_trigger_get(mpu3050->trig);
return 0;
+
+err_iio_trigger:
+ free_irq(mpu3050->irq, mpu3050->trig);
+
+ return ret;
}
int mpu3050_common_probe(struct device *dev,
@@ -1221,12 +1226,6 @@ int mpu3050_common_probe(struct device *dev,
goto err_power_down;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(dev, "device register failed\n");
- goto err_cleanup_buffer;
- }
-
dev_set_drvdata(dev, indio_dev);
/* Check if we have an assigned IRQ to use as trigger */
@@ -1249,9 +1248,20 @@ int mpu3050_common_probe(struct device *dev,
pm_runtime_use_autosuspend(dev);
pm_runtime_put(dev);
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(dev, "device register failed\n");
+ goto err_iio_device_register;
+ }
+
return 0;
-err_cleanup_buffer:
+err_iio_device_register:
+ pm_runtime_get_sync(dev);
+ pm_runtime_put_noidle(dev);
+ pm_runtime_disable(dev);
+ if (irq)
+ free_irq(mpu3050->irq, mpu3050->trig);
iio_triggered_buffer_cleanup(indio_dev);
err_power_down:
mpu3050_power_down(mpu3050);
@@ -1264,13 +1274,13 @@ void mpu3050_common_remove(struct device *dev)
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct mpu3050 *mpu3050 = iio_priv(indio_dev);
+ iio_device_unregister(indio_dev);
pm_runtime_get_sync(dev);
pm_runtime_put_noidle(dev);
pm_runtime_disable(dev);
- iio_triggered_buffer_cleanup(indio_dev);
if (mpu3050->irq)
- free_irq(mpu3050->irq, mpu3050);
- iio_device_unregister(indio_dev);
+ free_irq(mpu3050->irq, mpu3050->trig);
+ iio_triggered_buffer_cleanup(indio_dev);
mpu3050_power_down(mpu3050);
}
diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c
index 6549b22e643d..2a5bcec7272c 100644
--- a/drivers/iio/gyro/mpu3050-i2c.c
+++ b/drivers/iio/gyro/mpu3050-i2c.c
@@ -92,7 +92,7 @@ static void mpu3050_i2c_remove(struct i2c_client *client)
* supported by this driver
*/
static const struct i2c_device_id mpu3050_i2c_id[] = {
- { "mpu3050" },
+ { .name = "mpu3050" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mpu3050_i2c_id);
diff --git a/drivers/iio/gyro/ssp_gyro_sensor.c b/drivers/iio/gyro/ssp_gyro_sensor.c
index d9b41cf8d799..1acbbc1eeec3 100644
--- a/drivers/iio/gyro/ssp_gyro_sensor.c
+++ b/drivers/iio/gyro/ssp_gyro_sensor.c
@@ -76,7 +76,7 @@ static const struct iio_chan_spec ssp_gyro_channels[] = {
SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_X, SSP_CHANNEL_SCAN_INDEX_X),
SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Y, SSP_CHANNEL_SCAN_INDEX_Y),
SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Z, SSP_CHANNEL_SCAN_INDEX_Z),
- SSP_CHAN_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME),
+ IIO_CHAN_SOFT_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME),
};
static int ssp_process_gyro_data(struct iio_dev *indio_dev, void *buf,
diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
index aef5ec8f9dee..a587e9023ceb 100644
--- a/drivers/iio/gyro/st_gyro_i2c.c
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
@@ -93,15 +92,15 @@ static int st_gyro_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id st_gyro_id_table[] = {
- { L3G4200D_GYRO_DEV_NAME },
- { LSM330D_GYRO_DEV_NAME },
- { LSM330DL_GYRO_DEV_NAME },
- { LSM330DLC_GYRO_DEV_NAME },
- { L3GD20_GYRO_DEV_NAME },
- { L3GD20H_GYRO_DEV_NAME },
- { L3G4IS_GYRO_DEV_NAME },
- { LSM330_GYRO_DEV_NAME },
- { LSM9DS0_GYRO_DEV_NAME },
+ { .name = L3G4200D_GYRO_DEV_NAME },
+ { .name = LSM330D_GYRO_DEV_NAME },
+ { .name = LSM330DL_GYRO_DEV_NAME },
+ { .name = LSM330DLC_GYRO_DEV_NAME },
+ { .name = L3GD20_GYRO_DEV_NAME },
+ { .name = L3GD20H_GYRO_DEV_NAME },
+ { .name = L3G4IS_GYRO_DEV_NAME },
+ { .name = LSM330_GYRO_DEV_NAME },
+ { .name = LSM9DS0_GYRO_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, st_gyro_id_table);
diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
index f645da157372..c56331755b5c 100644
--- a/drivers/iio/gyro/st_gyro_spi.c
+++ b/drivers/iio/gyro/st_gyro_spi.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
@@ -98,15 +97,15 @@ static int st_gyro_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id st_gyro_id_table[] = {
- { L3G4200D_GYRO_DEV_NAME },
- { LSM330D_GYRO_DEV_NAME },
- { LSM330DL_GYRO_DEV_NAME },
- { LSM330DLC_GYRO_DEV_NAME },
- { L3GD20_GYRO_DEV_NAME },
- { L3GD20H_GYRO_DEV_NAME },
- { L3G4IS_GYRO_DEV_NAME },
- { LSM330_GYRO_DEV_NAME },
- { LSM9DS0_GYRO_DEV_NAME },
+ { .name = L3G4200D_GYRO_DEV_NAME },
+ { .name = LSM330D_GYRO_DEV_NAME },
+ { .name = LSM330DL_GYRO_DEV_NAME },
+ { .name = LSM330DLC_GYRO_DEV_NAME },
+ { .name = L3GD20_GYRO_DEV_NAME },
+ { .name = L3GD20H_GYRO_DEV_NAME },
+ { .name = L3G4IS_GYRO_DEV_NAME },
+ { .name = LSM330_GYRO_DEV_NAME },
+ { .name = LSM9DS0_GYRO_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(spi, st_gyro_id_table);
diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c
index d358f4d5e5da..2a648532242a 100644
--- a/drivers/iio/health/afe4403.c
+++ b/drivers/iio/health/afe4403.c
@@ -544,10 +544,8 @@ static int afe4403_probe(struct spi_device *spi)
iio_trigger_generic_data_rdy_poll,
IRQF_NO_THREAD, AFE4403_DRIVER_NAME,
afe->trig);
- if (ret) {
- dev_err(dev, "Unable to request IRQ\n");
+ if (ret)
return ret;
- }
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
@@ -568,7 +566,7 @@ static int afe4403_probe(struct spi_device *spi)
}
static const struct spi_device_id afe4403_ids[] = {
- { "afe4403", 0 },
+ { .name = "afe4403" },
{ }
};
MODULE_DEVICE_TABLE(spi, afe4403_ids);
diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c
index 032da52a96d0..22cd46eca217 100644
--- a/drivers/iio/health/afe4404.c
+++ b/drivers/iio/health/afe4404.c
@@ -551,10 +551,8 @@ static int afe4404_probe(struct i2c_client *client)
iio_trigger_generic_data_rdy_poll,
IRQF_NO_THREAD, AFE4404_DRIVER_NAME,
afe->trig);
- if (ret) {
- dev_err(dev, "Unable to request IRQ\n");
+ if (ret)
return ret;
- }
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
@@ -575,7 +573,7 @@ static int afe4404_probe(struct i2c_client *client)
}
static const struct i2c_device_id afe4404_ids[] = {
- { "afe4404" },
+ { .name = "afe4404" },
{ }
};
MODULE_DEVICE_TABLE(i2c, afe4404_ids);
diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c
index 7dfdb5eb305e..191540e10c20 100644
--- a/drivers/iio/health/max30100.c
+++ b/drivers/iio/health/max30100.c
@@ -489,10 +489,8 @@ static int max30100_probe(struct i2c_client *client)
NULL, max30100_interrupt_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"max30100_irq", indio_dev);
- if (ret) {
- dev_err(&client->dev, "request irq (%d) failed\n", client->irq);
+ if (ret)
return ret;
- }
return iio_device_register(indio_dev);
}
@@ -507,7 +505,7 @@ static void max30100_remove(struct i2c_client *client)
}
static const struct i2c_device_id max30100_id[] = {
- { "max30100" },
+ { .name = "max30100" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max30100_id);
diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 47da44efd68b..c37316c86f14 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -19,7 +19,6 @@
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
@@ -578,10 +577,8 @@ static int max30102_probe(struct i2c_client *client)
NULL, max30102_interrupt_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"max30102_irq", indio_dev);
- if (ret) {
- dev_err(&client->dev, "request irq (%d) failed\n", client->irq);
+ if (ret)
return ret;
- }
return iio_device_register(indio_dev);
}
@@ -596,9 +593,9 @@ static void max30102_remove(struct i2c_client *client)
}
static const struct i2c_device_id max30102_id[] = {
- { "max30101", max30105 },
- { "max30102", max30102 },
- { "max30105", max30105 },
+ { .name = "max30101", .driver_data = max30105 },
+ { .name = "max30102", .driver_data = max30102 },
+ { .name = "max30105", .driver_data = max30105 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max30102_id);
diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c
index 02ca23eb8991..f29baa251f9f 100644
--- a/drivers/iio/humidity/am2315.c
+++ b/drivers/iio/humidity/am2315.c
@@ -250,7 +250,7 @@ static int am2315_probe(struct i2c_client *client)
}
static const struct i2c_device_id am2315_i2c_id[] = {
- { "am2315" },
+ { .name = "am2315" },
{ }
};
MODULE_DEVICE_TABLE(i2c, am2315_i2c_id);
diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c
index 980cb946bbf7..7690df97fd6c 100644
--- a/drivers/iio/humidity/dht11.c
+++ b/drivers/iio/humidity/dht11.c
@@ -14,7 +14,6 @@
#include <linux/string_choices.h>
#include <linux/sysfs.h>
#include <linux/io.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/wait.h>
diff --git a/drivers/iio/humidity/ens210.c b/drivers/iio/humidity/ens210.c
index 77418d97f30d..81276195152b 100644
--- a/drivers/iio/humidity/ens210.c
+++ b/drivers/iio/humidity/ens210.c
@@ -18,7 +18,6 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -149,15 +148,16 @@ static int ens210_read_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case IIO_CHAN_INFO_RAW:
- scoped_guard(mutex, &data->lock) {
- ret = ens210_get_measurement(
- indio_dev, channel->type == IIO_TEMP, val);
- if (ret)
- return ret;
- return IIO_VAL_INT;
- }
- return -EINVAL; /* compiler warning workaround */
+ case IIO_CHAN_INFO_RAW: {
+ guard(mutex)(&data->lock);
+
+ ret = ens210_get_measurement(indio_dev, channel->type == IIO_TEMP,
+ val);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ }
case IIO_CHAN_INFO_SCALE:
if (channel->type == IIO_TEMP) {
*val = 15;
@@ -314,12 +314,12 @@ static const struct of_device_id ens210_of_match[] = {
MODULE_DEVICE_TABLE(of, ens210_of_match);
static const struct i2c_device_id ens210_id_table[] = {
- { "ens210", (kernel_ulong_t)&ens210_chip_info_data },
- { "ens210a", (kernel_ulong_t)&ens210a_chip_info_data },
- { "ens211", (kernel_ulong_t)&ens211_chip_info_data },
- { "ens212", (kernel_ulong_t)&ens212_chip_info_data },
- { "ens213a", (kernel_ulong_t)&ens213a_chip_info_data },
- { "ens215", (kernel_ulong_t)&ens215_chip_info_data },
+ { .name = "ens210", .driver_data = (kernel_ulong_t)&ens210_chip_info_data },
+ { .name = "ens210a", .driver_data = (kernel_ulong_t)&ens210a_chip_info_data },
+ { .name = "ens211", .driver_data = (kernel_ulong_t)&ens211_chip_info_data },
+ { .name = "ens212", .driver_data = (kernel_ulong_t)&ens212_chip_info_data },
+ { .name = "ens213a", .driver_data = (kernel_ulong_t)&ens213a_chip_info_data },
+ { .name = "ens215", .driver_data = (kernel_ulong_t)&ens215_chip_info_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, ens210_id_table);
diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c
index c2b36e682e06..bc452cc8fbcf 100644
--- a/drivers/iio/humidity/hdc100x.c
+++ b/drivers/iio/humidity/hdc100x.c
@@ -16,7 +16,6 @@
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/i2c.h>
@@ -380,12 +379,12 @@ static int hdc100x_probe(struct i2c_client *client)
}
static const struct i2c_device_id hdc100x_id[] = {
- { "hdc100x" },
- { "hdc1000" },
- { "hdc1008" },
- { "hdc1010" },
- { "hdc1050" },
- { "hdc1080" },
+ { .name = "hdc100x" },
+ { .name = "hdc1000" },
+ { .name = "hdc1008" },
+ { .name = "hdc1010" },
+ { .name = "hdc1050" },
+ { .name = "hdc1080" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hdc100x_id);
diff --git a/drivers/iio/humidity/hdc2010.c b/drivers/iio/humidity/hdc2010.c
index 894a8b4ab193..82d68987556d 100644
--- a/drivers/iio/humidity/hdc2010.c
+++ b/drivers/iio/humidity/hdc2010.c
@@ -44,7 +44,6 @@ struct hdc2010_data {
struct i2c_client *client;
struct mutex lock;
u8 measurement_config;
- u8 interrupt_config;
u8 drdy_config;
};
@@ -318,8 +317,8 @@ static void hdc2010_remove(struct i2c_client *client)
}
static const struct i2c_device_id hdc2010_id[] = {
- { "hdc2010" },
- { "hdc2080" },
+ { .name = "hdc2010" },
+ { .name = "hdc2080" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hdc2010_id);
diff --git a/drivers/iio/humidity/hdc3020.c b/drivers/iio/humidity/hdc3020.c
index 78b2c171c8da..75971c19624a 100644
--- a/drivers/iio/humidity/hdc3020.c
+++ b/drivers/iio/humidity/hdc3020.c
@@ -843,8 +843,7 @@ static int hdc3020_probe(struct i2c_client *client)
IRQF_ONESHOT, "hdc3020",
indio_dev);
if (ret)
- return dev_err_probe(&client->dev, ret,
- "Failed to request IRQ\n");
+ return ret;
}
ret = devm_iio_device_register(&data->client->dev, indio_dev);
@@ -873,9 +872,9 @@ static int hdc3020_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(hdc3020_pm_ops, hdc3020_suspend, hdc3020_resume);
static const struct i2c_device_id hdc3020_id[] = {
- { "hdc3020" },
- { "hdc3021" },
- { "hdc3022" },
+ { .name = "hdc3020" },
+ { .name = "hdc3021" },
+ { .name = "hdc3022" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hdc3020_id);
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index be2338d5f407..7cec81ff5685 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -8,7 +8,6 @@
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include "hid-sensor-trigger.h"
@@ -45,7 +44,7 @@ static const struct iio_chan_spec humidity_channels[] = {
/* Adjust channel real bits based on report descriptor */
static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels,
- int channel, int size)
+ int channel, int size)
{
channels[channel].scan_type.sign = 's';
/* Real storage bits will change based on the report desc. */
@@ -55,8 +54,8 @@ static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels,
}
static int humidity_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2, long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -101,8 +100,8 @@ static int humidity_read_raw(struct iio_dev *indio_dev,
}
static int humidity_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -127,7 +126,7 @@ static const struct iio_info humidity_info = {
/* Callback handler to send event after all samples are received and captured */
static int humidity_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned int usage_id, void *pdev)
+ u32 usage_id, void *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -141,8 +140,9 @@ static int humidity_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned int usage_id, size_t raw_len,
- char *raw_data, void *pdev)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -159,10 +159,10 @@ static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id */
static int humidity_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct iio_chan_spec *channels,
- unsigned int usage_id,
- struct hid_humidity_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ u32 usage_id,
+ struct hid_humidity_state *st)
{
int ret;
@@ -215,13 +215,13 @@ static int hid_humidity_probe(struct platform_device *pdev)
if (ret)
return ret;
- humid_chans = devm_kmemdup(&indio_dev->dev, humidity_channels,
- sizeof(humidity_channels), GFP_KERNEL);
+ humid_chans = devm_kmemdup(&pdev->dev, humidity_channels,
+ sizeof(humidity_channels), GFP_KERNEL);
if (!humid_chans)
return -ENOMEM;
ret = humidity_parse_report(pdev, hsdev, humid_chans,
- HID_USAGE_SENSOR_HUMIDITY, humid_st);
+ HID_USAGE_SENSOR_HUMIDITY, humid_st);
if (ret)
return ret;
@@ -234,7 +234,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
atomic_set(&humid_st->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &humid_st->common_attributes);
+ &humid_st->common_attributes);
if (ret)
return ret;
@@ -242,7 +242,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
humidity_callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY,
- &humidity_callbacks);
+ &humidity_callbacks);
if (ret)
goto error_remove_trigger;
diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c
index 4d03db19063e..df12c7a25b2e 100644
--- a/drivers/iio/humidity/hts221_buffer.c
+++ b/drivers/iio/humidity/hts221_buffer.c
@@ -122,11 +122,8 @@ int hts221_allocate_trigger(struct iio_dev *iio_dev)
hts221_trigger_handler_thread,
irq_type | IRQF_ONESHOT,
hw->name, hw);
- if (err) {
- dev_err(hw->dev, "failed to request trigger irq %d\n",
- hw->irq);
+ if (err)
return err;
- }
hw->trig = devm_iio_trigger_alloc(hw->dev, "%s-trigger",
iio_dev->name);
diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c
index cbaa7d1af6c4..40276abc5d2e 100644
--- a/drivers/iio/humidity/hts221_i2c.c
+++ b/drivers/iio/humidity/hts221_i2c.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@@ -53,7 +52,7 @@ static const struct of_device_id hts221_i2c_of_match[] = {
MODULE_DEVICE_TABLE(of, hts221_i2c_of_match);
static const struct i2c_device_id hts221_i2c_id_table[] = {
- { HTS221_DEV_NAME },
+ { .name = HTS221_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table);
diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c
index e6fef2acd523..f962842cc71d 100644
--- a/drivers/iio/humidity/hts221_spi.c
+++ b/drivers/iio/humidity/hts221_spi.c
@@ -47,7 +47,7 @@ static const struct of_device_id hts221_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, hts221_spi_of_match);
static const struct spi_device_id hts221_spi_id_table[] = {
- { HTS221_DEV_NAME },
+ { .name = HTS221_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(spi, hts221_spi_id_table);
diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
index 7f1775bd26fd..a9dbf08b4f1a 100644
--- a/drivers/iio/humidity/htu21.c
+++ b/drivers/iio/humidity/htu21.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -230,8 +229,8 @@ static int htu21_probe(struct i2c_client *client)
}
static const struct i2c_device_id htu21_id[] = {
- {"htu21", HTU21},
- {"ms8607-humidity", MS8607},
+ { .name = "htu21", .driver_data = HTU21 },
+ { .name = "ms8607-humidity", .driver_data = MS8607 },
{ }
};
MODULE_DEVICE_TABLE(i2c, htu21_id);
diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c
index 0797ece1fcba..0c11d0d3afe0 100644
--- a/drivers/iio/humidity/si7005.c
+++ b/drivers/iio/humidity/si7005.c
@@ -163,8 +163,8 @@ static int si7005_probe(struct i2c_client *client)
}
static const struct i2c_device_id si7005_id[] = {
- { "si7005" },
- { "th02" },
+ { .name = "si7005" },
+ { .name = "th02" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si7005_id);
diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c
index ff2dba50c0a5..e51dd7151e4a 100644
--- a/drivers/iio/humidity/si7020.c
+++ b/drivers/iio/humidity/si7020.c
@@ -20,7 +20,6 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/stat.h>
@@ -267,8 +266,8 @@ static int si7020_probe(struct i2c_client *client)
}
static const struct i2c_device_id si7020_id[] = {
- { "si7020" },
- { "th06" },
+ { .name = "si7020" },
+ { .name = "th06" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si7020_id);
diff --git a/drivers/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h
index e1a56824e07f..4698a857739f 100644
--- a/drivers/iio/iio_core_trigger.h
+++ b/drivers/iio/iio_core_trigger.h
@@ -56,4 +56,4 @@ static inline int iio_trigger_detach_poll_func(struct iio_trigger *trig,
return 0;
}
-#endif /* CONFIG_TRIGGER_CONSUMER */
+#endif /* CONFIG_IIO_TRIGGER */
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 7e0181c27bb6..8bab4616be20 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -109,6 +109,7 @@ config KMX61
be called kmx61.
source "drivers/iio/imu/inv_icm42600/Kconfig"
+source "drivers/iio/imu/inv_icm42607/Kconfig"
source "drivers/iio/imu/inv_icm45600/Kconfig"
source "drivers/iio/imu/inv_mpu6050/Kconfig"
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 13fb7846e9c9..3268dc2371ae 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
obj-y += inv_icm42600/
+obj-y += inv_icm42607/
obj-y += inv_icm45600/
obj-y += inv_mpu6050/
diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c
index 36323ad149e0..4842346f9f0c 100644
--- a/drivers/iio/imu/adis16400.c
+++ b/drivers/iio/imu/adis16400.c
@@ -1189,21 +1189,21 @@ static int adis16400_probe(struct spi_device *spi)
}
static const struct spi_device_id adis16400_id[] = {
- { "adis16300", (kernel_ulong_t)&adis16300_chip_info },
- { "adis16305", (kernel_ulong_t)&adis16300_chip_info },
- { "adis16334", (kernel_ulong_t)&adis16334_chip_info },
- { "adis16350", (kernel_ulong_t)&adis16350_chip_info },
- { "adis16354", (kernel_ulong_t)&adis16350_chip_info },
- { "adis16355", (kernel_ulong_t)&adis16350_chip_info },
- { "adis16360", (kernel_ulong_t)&adis16360_chip_info },
- { "adis16362", (kernel_ulong_t)&adis16362_chip_info },
- { "adis16364", (kernel_ulong_t)&adis16364_chip_info },
- { "adis16365", (kernel_ulong_t)&adis16360_chip_info },
- { "adis16367", (kernel_ulong_t)&adis16367_chip_info },
- { "adis16400", (kernel_ulong_t)&adis16400_chip_info },
- { "adis16405", (kernel_ulong_t)&adis16400_chip_info },
- { "adis16445", (kernel_ulong_t)&adis16445_chip_info },
- { "adis16448", (kernel_ulong_t)&adis16448_chip_info },
+ { .name = "adis16300", .driver_data = (kernel_ulong_t)&adis16300_chip_info },
+ { .name = "adis16305", .driver_data = (kernel_ulong_t)&adis16300_chip_info },
+ { .name = "adis16334", .driver_data = (kernel_ulong_t)&adis16334_chip_info },
+ { .name = "adis16350", .driver_data = (kernel_ulong_t)&adis16350_chip_info },
+ { .name = "adis16354", .driver_data = (kernel_ulong_t)&adis16350_chip_info },
+ { .name = "adis16355", .driver_data = (kernel_ulong_t)&adis16350_chip_info },
+ { .name = "adis16360", .driver_data = (kernel_ulong_t)&adis16360_chip_info },
+ { .name = "adis16362", .driver_data = (kernel_ulong_t)&adis16362_chip_info },
+ { .name = "adis16364", .driver_data = (kernel_ulong_t)&adis16364_chip_info },
+ { .name = "adis16365", .driver_data = (kernel_ulong_t)&adis16360_chip_info },
+ { .name = "adis16367", .driver_data = (kernel_ulong_t)&adis16367_chip_info },
+ { .name = "adis16400", .driver_data = (kernel_ulong_t)&adis16400_chip_info },
+ { .name = "adis16405", .driver_data = (kernel_ulong_t)&adis16400_chip_info },
+ { .name = "adis16445", .driver_data = (kernel_ulong_t)&adis16445_chip_info },
+ { .name = "adis16448", .driver_data = (kernel_ulong_t)&adis16448_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16400_id);
diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c
index ba1887d36577..cadf21c05bbf 100644
--- a/drivers/iio/imu/adis16460.c
+++ b/drivers/iio/imu/adis16460.c
@@ -394,7 +394,7 @@ static int adis16460_probe(struct spi_device *spi)
}
static const struct spi_device_id adis16460_ids[] = {
- { "adis16460", 0 },
+ { .name = "adis16460" },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16460_ids);
diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
index ab39bea1e729..5f21dceda8f7 100644
--- a/drivers/iio/imu/adis16475.c
+++ b/drivers/iio/imu/adis16475.c
@@ -20,7 +20,6 @@
#include <linux/lcm.h>
#include <linux/math.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
@@ -2062,33 +2061,33 @@ static const struct of_device_id adis16475_of_match[] = {
MODULE_DEVICE_TABLE(of, adis16475_of_match);
static const struct spi_device_id adis16475_ids[] = {
- { "adis16470", (kernel_ulong_t)&adis16475_chip_info[ADIS16470] },
- { "adis16475-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16475_1] },
- { "adis16475-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16475_2] },
- { "adis16475-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16475_3] },
- { "adis16477-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16477_1] },
- { "adis16477-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16477_2] },
- { "adis16477-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16477_3] },
- { "adis16465-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16465_1] },
- { "adis16465-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16465_2] },
- { "adis16465-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16465_3] },
- { "adis16467-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_1] },
- { "adis16467-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_2] },
- { "adis16467-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_3] },
- { "adis16500", (kernel_ulong_t)&adis16475_chip_info[ADIS16500] },
- { "adis16501", (kernel_ulong_t)&adis16475_chip_info[ADIS16501] },
- { "adis16505-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_1] },
- { "adis16505-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_2] },
- { "adis16505-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_3] },
- { "adis16507-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_1] },
- { "adis16507-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_2] },
- { "adis16507-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_3] },
- { "adis16575-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_2] },
- { "adis16575-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_3] },
- { "adis16576-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_2] },
- { "adis16576-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_3] },
- { "adis16577-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_2] },
- { "adis16577-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_3] },
+ { .name = "adis16470", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16470] },
+ { .name = "adis16475-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16475_1] },
+ { .name = "adis16475-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16475_2] },
+ { .name = "adis16475-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16475_3] },
+ { .name = "adis16477-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16477_1] },
+ { .name = "adis16477-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16477_2] },
+ { .name = "adis16477-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16477_3] },
+ { .name = "adis16465-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16465_1] },
+ { .name = "adis16465-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16465_2] },
+ { .name = "adis16465-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16465_3] },
+ { .name = "adis16467-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16467_1] },
+ { .name = "adis16467-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16467_2] },
+ { .name = "adis16467-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16467_3] },
+ { .name = "adis16500", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16500] },
+ { .name = "adis16501", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16501] },
+ { .name = "adis16505-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16505_1] },
+ { .name = "adis16505-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16505_2] },
+ { .name = "adis16505-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16505_3] },
+ { .name = "adis16507-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16507_1] },
+ { .name = "adis16507-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16507_2] },
+ { .name = "adis16507-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16507_3] },
+ { .name = "adis16575-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16575_2] },
+ { .name = "adis16575-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16575_3] },
+ { .name = "adis16576-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16576_2] },
+ { .name = "adis16576-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16576_3] },
+ { .name = "adis16577-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16577_2] },
+ { .name = "adis16577-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16577_3] },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16475_ids);
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index 543d5c4bfb11..5187566c1876 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -13,7 +13,6 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/lcm.h>
#include <linux/property.h>
@@ -111,7 +110,7 @@
#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20)
-/* Each filter coefficent bank spans two pages */
+/* Each filter coefficient bank spans two pages */
#define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \
ADIS16480_REG((page) + 1, (x) - 60 + 8))
#define ADIS16480_FIR_COEF_A(x) ADIS16480_FIR_COEF(0x05, (x))
@@ -1468,7 +1467,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
* We need to perform the padding to have the buffer
* elements naturally aligned in case there are any
* 32-bit storage size channels enabled which are added
- * in the buffer after the temprature data. In case
+ * in the buffer after the temperature data. In case
* there is no data being added after the temperature
* data, the padding is harmless.
*/
@@ -1807,26 +1806,26 @@ static int adis16480_probe(struct spi_device *spi)
}
static const struct spi_device_id adis16480_ids[] = {
- { "adis16375", ADIS16375 },
- { "adis16480", ADIS16480 },
- { "adis16485", ADIS16485 },
- { "adis16486", ADIS16486 },
- { "adis16487", ADIS16487 },
- { "adis16488", ADIS16488 },
- { "adis16489", ADIS16489 },
- { "adis16490", ADIS16490 },
- { "adis16495-1", ADIS16495_1 },
- { "adis16495-2", ADIS16495_2 },
- { "adis16495-3", ADIS16495_3 },
- { "adis16497-1", ADIS16497_1 },
- { "adis16497-2", ADIS16497_2 },
- { "adis16497-3", ADIS16497_3 },
- { "adis16545-1", ADIS16545_1 },
- { "adis16545-2", ADIS16545_2 },
- { "adis16545-3", ADIS16545_3 },
- { "adis16547-1", ADIS16547_1 },
- { "adis16547-2", ADIS16547_2 },
- { "adis16547-3", ADIS16547_3 },
+ { .name = "adis16375", .driver_data = ADIS16375 },
+ { .name = "adis16480", .driver_data = ADIS16480 },
+ { .name = "adis16485", .driver_data = ADIS16485 },
+ { .name = "adis16486", .driver_data = ADIS16486 },
+ { .name = "adis16487", .driver_data = ADIS16487 },
+ { .name = "adis16488", .driver_data = ADIS16488 },
+ { .name = "adis16489", .driver_data = ADIS16489 },
+ { .name = "adis16490", .driver_data = ADIS16490 },
+ { .name = "adis16495-1", .driver_data = ADIS16495_1 },
+ { .name = "adis16495-2", .driver_data = ADIS16495_2 },
+ { .name = "adis16495-3", .driver_data = ADIS16495_3 },
+ { .name = "adis16497-1", .driver_data = ADIS16497_1 },
+ { .name = "adis16497-2", .driver_data = ADIS16497_2 },
+ { .name = "adis16497-3", .driver_data = ADIS16497_3 },
+ { .name = "adis16545-1", .driver_data = ADIS16545_1 },
+ { .name = "adis16545-2", .driver_data = ADIS16545_2 },
+ { .name = "adis16545-3", .driver_data = ADIS16545_3 },
+ { .name = "adis16547-1", .driver_data = ADIS16547_1 },
+ { .name = "adis16547-2", .driver_data = ADIS16547_2 },
+ { .name = "adis16547-3", .driver_data = ADIS16547_3 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16480_ids);
diff --git a/drivers/iio/imu/adis16550.c b/drivers/iio/imu/adis16550.c
index 28f0dbd0226c..096a612865c4 100644
--- a/drivers/iio/imu/adis16550.c
+++ b/drivers/iio/imu/adis16550.c
@@ -18,7 +18,6 @@
#include <linux/lcm.h>
#include <linux/math.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/swab.h>
@@ -89,25 +88,7 @@ struct adis16550_sync {
u16 max_rate;
};
-struct adis16550_chip_info {
- const struct iio_chan_spec *channels;
- const struct adis16550_sync *sync_mode;
- char *name;
- u32 num_channels;
- u32 gyro_max_val;
- u32 gyro_max_scale;
- u32 accel_max_val;
- u32 accel_max_scale;
- u32 temp_scale;
- u32 deltang_max_val;
- u32 deltvel_max_val;
- u32 int_clk;
- u16 max_dec;
- u16 num_sync;
-};
-
struct adis16550 {
- const struct adis16550_chip_info *info;
struct adis adis;
unsigned long clk_freq_hz;
u32 sync_mode;
@@ -450,8 +431,8 @@ static int adis16550_set_freq_hz(struct adis16550 *st, u32 freq_hz)
* The optimal sample rate for the supported IMUs is between
* int_clk - 1000 and int_clk + 500.
*/
- u32 max_sample_rate = st->info->int_clk * 1000 + 500000;
- u32 min_sample_rate = st->info->int_clk * 1000 - 1000000;
+ u32 max_sample_rate = 4000 * 1000 + 500000;
+ u32 min_sample_rate = 4000 * 1000 - 1000000;
if (!freq_hz)
return -EINVAL;
@@ -484,7 +465,7 @@ static int adis16550_set_freq_hz(struct adis16550 *st, u32 freq_hz)
if (dec)
dec--;
- dec = min(dec, st->info->max_dec);
+ dec = min(dec, 4095);
return __adis_write_reg_16(&st->adis, ADIS16550_REG_DEC_RATE, dec);
}
@@ -592,30 +573,30 @@ static int adis16550_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
- *val = st->info->gyro_max_val;
- *val2 = st->info->gyro_max_scale;
+ *val = 1;
+ *val2 = IIO_RAD_TO_DEGREE(80 << 16);
return IIO_VAL_FRACTIONAL;
case IIO_ACCEL:
- *val = st->info->accel_max_val;
- *val2 = st->info->accel_max_scale;
+ *val = 1;
+ *val2 = IIO_M_S_2_TO_G(102400000);
return IIO_VAL_FRACTIONAL;
case IIO_TEMP:
- *val = st->info->temp_scale;
+ *val = 4;
return IIO_VAL_INT;
case IIO_DELTA_ANGL:
- *val = st->info->deltang_max_val;
+ *val = IIO_DEGREE_TO_RAD(720);
*val2 = 31;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_DELTA_VELOCITY:
- *val = st->info->deltvel_max_val;
+ *val = 125;
*val2 = 31;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
- /* temperature centered at 25°C */
- *val = DIV_ROUND_CLOSEST(25000, st->info->temp_scale);
+ /* temperature centered at 25°C divided by temp scale */
+ *val = 25000 / 4;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS:
ret = adis_read_reg_32(&st->adis,
@@ -643,12 +624,12 @@ static int adis16550_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
switch (chan->type) {
case IIO_ANGL_VEL:
- ret = adis16550_get_accl_filter_freq(st, val);
+ ret = adis16550_get_gyro_filter_freq(st, val);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_ACCEL:
- ret = adis16550_get_gyro_filter_freq(st, val);
+ ret = adis16550_get_accl_filter_freq(st, val);
if (ret)
return ret;
return IIO_VAL_INT;
@@ -681,9 +662,9 @@ static int adis16550_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
switch (chan->type) {
case IIO_ANGL_VEL:
- return adis16550_set_accl_filter_freq(st, val);
- case IIO_ACCEL:
return adis16550_set_gyro_filter_freq(st, val);
+ case IIO_ACCEL:
+ return adis16550_set_accl_filter_freq(st, val);
default:
return -EINVAL;
}
@@ -793,23 +774,6 @@ static const struct adis16550_sync adis16550_sync_modes[] = {
{ ADIS16550_SYNC_MODE_SCALED, 1, 128 },
};
-static const struct adis16550_chip_info adis16550_chip_info = {
- .num_channels = ARRAY_SIZE(adis16550_channels),
- .channels = adis16550_channels,
- .name = "adis16550",
- .gyro_max_val = 1,
- .gyro_max_scale = IIO_RAD_TO_DEGREE(80 << 16),
- .accel_max_val = 1,
- .accel_max_scale = IIO_M_S_2_TO_G(102400000),
- .temp_scale = 4,
- .deltang_max_val = IIO_DEGREE_TO_RAD(720),
- .deltvel_max_val = 125,
- .int_clk = 4000,
- .max_dec = 4095,
- .sync_mode = adis16550_sync_modes,
- .num_sync = ARRAY_SIZE(adis16550_sync_modes),
-};
-
static u32 adis16550_validate_crc(__be32 *buffer, const u8 n_elem)
{
int i;
@@ -836,7 +800,7 @@ static irqreturn_t adis16550_trigger_handler(int irq, void *p)
u16 dummy;
bool valid;
struct iio_poll_func *pf = p;
- __be32 data[ADIS16550_MAX_SCAN_DATA] __aligned(8);
+ __be32 data[ADIS16550_MAX_SCAN_DATA] __aligned(8) = { };
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16550 *st = iio_priv(indio_dev);
struct adis *adis = iio_device_get_drvdata(indio_dev);
@@ -918,21 +882,21 @@ static int adis16550_config_sync(struct adis16550 *st)
if (IS_ERR(clk))
return PTR_ERR(clk);
if (!clk) {
- st->clk_freq_hz = st->info->int_clk * 1000;
+ st->clk_freq_hz = 4000000;
return 0;
}
st->clk_freq_hz = clk_get_rate(clk);
- for (i = 0; i < st->info->num_sync; i++) {
- if (st->clk_freq_hz >= st->info->sync_mode[i].min_rate &&
- st->clk_freq_hz <= st->info->sync_mode[i].max_rate) {
- sync_mode_data = &st->info->sync_mode[i];
+ for (i = 0; i < ARRAY_SIZE(adis16550_sync_modes); i++) {
+ if (st->clk_freq_hz >= adis16550_sync_modes[i].min_rate &&
+ st->clk_freq_hz <= adis16550_sync_modes[i].max_rate) {
+ sync_mode_data = &adis16550_sync_modes[i];
break;
}
}
- if (i == st->info->num_sync)
+ if (i == ARRAY_SIZE(adis16550_sync_modes))
return dev_err_probe(dev, -EINVAL, "Clk rate: %lu not in a valid range",
st->clk_freq_hz);
@@ -943,7 +907,7 @@ static int adis16550_config_sync(struct adis16550 *st)
* of [3000 4500].
*/
- sync_scale = DIV_ROUND_CLOSEST(st->info->int_clk, st->clk_freq_hz);
+ sync_scale = DIV_ROUND_CLOSEST(4000, st->clk_freq_hz);
if (3000 > sync_scale || 4500 < sync_scale)
return dev_err_probe(dev, -EINVAL,
@@ -955,7 +919,7 @@ static int adis16550_config_sync(struct adis16550 *st)
if (ret)
return ret;
- st->clk_freq_hz = st->info->int_clk;
+ st->clk_freq_hz = 4000;
}
st->clk_freq_hz *= 1000;
@@ -1064,13 +1028,11 @@ static int adis16550_probe(struct spi_device *spi)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->info = spi_get_device_match_data(spi);
- if (!st->info)
- return -EINVAL;
+
adis = &st->adis;
- indio_dev->name = st->info->name;
- indio_dev->channels = st->info->channels;
- indio_dev->num_channels = st->info->num_channels;
+ indio_dev->name = "adis16550";
+ indio_dev->channels = adis16550_channels;
+ indio_dev->num_channels = ARRAY_SIZE(adis16550_channels);
indio_dev->available_scan_masks = adis16550_channel_masks;
indio_dev->info = &adis16550_info;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1117,13 +1079,13 @@ static int adis16550_probe(struct spi_device *spi)
}
static const struct spi_device_id adis16550_id[] = {
- { "adis16550", (kernel_ulong_t)&adis16550_chip_info},
+ { .name = "adis16550" },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16550_id);
static const struct of_device_id adis16550_of_match[] = {
- { .compatible = "adi,adis16550", .data = &adis16550_chip_info },
+ { .compatible = "adi,adis16550" },
{ }
};
MODULE_DEVICE_TABLE(of, adis16550_of_match);
diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c
index d76e13cbac68..3e6a7af6ab01 100644
--- a/drivers/iio/imu/adis_trigger.c
+++ b/drivers/iio/imu/adis_trigger.c
@@ -94,7 +94,7 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
else
ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
&iio_trigger_generic_data_rdy_poll,
- adis->irq_flag,
+ adis->irq_flag | IRQF_NO_THREAD,
indio_dev->name,
adis->trig);
if (ret)
diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c
index 5f47708b4c5d..1e73a7f1f017 100644
--- a/drivers/iio/imu/bmi160/bmi160_core.c
+++ b/drivers/iio/imu/bmi160/bmi160_core.c
@@ -5,7 +5,7 @@
* Copyright (c) 2016, Intel Corporation.
* Copyright (c) 2019, Martin Kelly.
*
- * IIO core driver for BMI160, with support for I2C/SPI busses
+ * IIO core driver for BMI160, with support for I2C/SPI buses
*
* TODO: magnetometer, hardware FIFO
*/
@@ -573,12 +573,16 @@ static int bmi160_config_pin(struct regmap *regmap, enum bmi160_int_pin pin,
int_out_ctrl_shift = BMI160_INT1_OUT_CTRL_SHIFT;
int_latch_mask = BMI160_INT1_LATCH_MASK;
int_map_mask = BMI160_INT1_MAP_DRDY_EN;
+ pin_name = "INT1";
break;
case BMI160_PIN_INT2:
int_out_ctrl_shift = BMI160_INT2_OUT_CTRL_SHIFT;
int_latch_mask = BMI160_INT2_LATCH_MASK;
int_map_mask = BMI160_INT2_MAP_DRDY_EN;
+ pin_name = "INT2";
break;
+ default:
+ return -EINVAL;
}
int_out_ctrl_mask = BMI160_INT_OUT_CTRL_MASK << int_out_ctrl_shift;
@@ -612,17 +616,8 @@ static int bmi160_config_pin(struct regmap *regmap, enum bmi160_int_pin pin,
ret = bmi160_write_conf_reg(regmap, BMI160_REG_INT_MAP,
int_map_mask, int_map_mask,
write_usleep);
- if (ret) {
- switch (pin) {
- case BMI160_PIN_INT1:
- pin_name = "INT1";
- break;
- case BMI160_PIN_INT2:
- pin_name = "INT2";
- break;
- }
+ if (ret)
dev_err(dev, "Failed to configure %s IRQ pin", pin_name);
- }
return ret;
}
@@ -793,7 +788,8 @@ int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type)
ret = devm_request_irq(&indio_dev->dev, irq,
&iio_trigger_generic_data_rdy_poll,
- irq_type, "bmi160", data->trig);
+ irq_type | IRQF_NO_THREAD,
+ "bmi160", data->trig);
if (ret)
return ret;
diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c
index 3e2758f4e0d3..3f3ee044a9cf 100644
--- a/drivers/iio/imu/bmi160/bmi160_i2c.c
+++ b/drivers/iio/imu/bmi160/bmi160_i2c.c
@@ -9,7 +9,6 @@
* - 0x69 if SDO is pulled to VDDIO
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/regmap.h>
@@ -38,8 +37,8 @@ static int bmi160_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bmi160_i2c_id[] = {
- { "bmi120" },
- { "bmi160" },
+ { .name = "bmi120" },
+ { .name = "bmi160" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id);
diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c
index 3581bd788483..107eb3374922 100644
--- a/drivers/iio/imu/bmi160/bmi160_spi.c
+++ b/drivers/iio/imu/bmi160/bmi160_spi.c
@@ -5,7 +5,6 @@
* Copyright (c) 2016, Intel Corporation.
*
*/
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/regmap.h>
@@ -35,8 +34,8 @@ static int bmi160_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id bmi160_spi_id[] = {
- {"bmi120", 0},
- {"bmi160", 0},
+ { .name = "bmi120" },
+ { .name = "bmi160" },
{ }
};
MODULE_DEVICE_TABLE(spi, bmi160_spi_id);
diff --git a/drivers/iio/imu/bmi270/bmi270_core.c b/drivers/iio/imu/bmi270/bmi270_core.c
index 2ad230788532..fbcf6bb87acc 100644
--- a/drivers/iio/imu/bmi270/bmi270_core.c
+++ b/drivers/iio/imu/bmi270/bmi270_core.c
@@ -1434,7 +1434,7 @@ static int bmi270_trigger_probe(struct bmi270_data *data,
bmi270_irq_thread_handler,
IRQF_ONESHOT, "bmi270-int", indio_dev);
if (ret)
- return dev_err_probe(data->dev, ret, "Failed to request IRQ\n");
+ return ret;
ret = devm_iio_trigger_register(data->dev, data->trig);
if (ret)
diff --git a/drivers/iio/imu/bmi270/bmi270_i2c.c b/drivers/iio/imu/bmi270/bmi270_i2c.c
index b92da4e0776f..7c035e82e6e9 100644
--- a/drivers/iio/imu/bmi270/bmi270_i2c.c
+++ b/drivers/iio/imu/bmi270/bmi270_i2c.c
@@ -3,7 +3,6 @@
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/pm.h>
#include <linux/regmap.h>
@@ -33,8 +32,8 @@ static int bmi270_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bmi270_i2c_id[] = {
- { "bmi260", (kernel_ulong_t)&bmi260_chip_info },
- { "bmi270", (kernel_ulong_t)&bmi270_chip_info },
+ { .name = "bmi260", .driver_data = (kernel_ulong_t)&bmi260_chip_info },
+ { .name = "bmi270", .driver_data = (kernel_ulong_t)&bmi270_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, bmi270_i2c_id);
diff --git a/drivers/iio/imu/bmi270/bmi270_spi.c b/drivers/iio/imu/bmi270/bmi270_spi.c
index 80c9fa1d685a..759b56b59e54 100644
--- a/drivers/iio/imu/bmi270/bmi270_spi.c
+++ b/drivers/iio/imu/bmi270/bmi270_spi.c
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
#include <linux/iio/iio.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/regmap.h>
@@ -66,8 +65,8 @@ static int bmi270_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id bmi270_spi_id[] = {
- { "bmi260", (kernel_ulong_t)&bmi260_chip_info },
- { "bmi270", (kernel_ulong_t)&bmi270_chip_info },
+ { .name = "bmi260", .driver_data = (kernel_ulong_t)&bmi260_chip_info },
+ { .name = "bmi270", .driver_data = (kernel_ulong_t)&bmi270_chip_info },
{ }
};
@@ -76,6 +75,7 @@ static const struct of_device_id bmi270_of_match[] = {
{ .compatible = "bosch,bmi270", .data = &bmi270_chip_info },
{ }
};
+MODULE_DEVICE_TABLE(of, bmi270_of_match);
static struct spi_driver bmi270_spi_driver = {
.driver = {
diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c
index 6bcb9a436581..ebeb1b10c38c 100644
--- a/drivers/iio/imu/bmi323/bmi323_core.c
+++ b/drivers/iio/imu/bmi323/bmi323_core.c
@@ -156,7 +156,6 @@ struct bmi323_data {
struct iio_mount_matrix orientation;
enum bmi323_irq_pin irq_pin;
struct iio_trigger *trig;
- bool drdy_trigger_enabled;
enum bmi323_state state;
s64 fifo_tstamp, old_fifo_tstamp;
u32 odrns[BMI323_SENSORS_CNT];
@@ -1129,7 +1128,7 @@ static int bmi323_set_watermark(struct iio_dev *indio_dev, unsigned int val)
{
struct bmi323_data *data = iio_priv(indio_dev);
- val = min(val, (u32)BMI323_FIFO_FULL_IN_FRAMES);
+ val = min(val, BMI323_FIFO_FULL_IN_FRAMES);
guard(mutex)(&data->mutex);
data->watermark = val;
@@ -1947,7 +1946,7 @@ static int bmi323_trigger_probe(struct bmi323_data *data,
bmi323_irq_thread_handler,
IRQF_ONESHOT, "bmi323-int", indio_dev);
if (ret)
- return dev_err_probe(data->dev, ret, "Failed to request IRQ\n");
+ return ret;
ret = devm_iio_trigger_register(data->dev, data->trig);
if (ret)
diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c
index 8457fe304db8..e835b91ea6b4 100644
--- a/drivers/iio/imu/bmi323/bmi323_i2c.c
+++ b/drivers/iio/imu/bmi323/bmi323_i2c.c
@@ -6,7 +6,6 @@
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -114,7 +113,7 @@ static const struct acpi_device_id bmi323_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, bmi323_acpi_match);
static const struct i2c_device_id bmi323_i2c_ids[] = {
- { "bmi323" },
+ { .name = "bmi323" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bmi323_i2c_ids);
diff --git a/drivers/iio/imu/bmi323/bmi323_spi.c b/drivers/iio/imu/bmi323/bmi323_spi.c
index fd56ab620750..ed0235cc40da 100644
--- a/drivers/iio/imu/bmi323/bmi323_spi.c
+++ b/drivers/iio/imu/bmi323/bmi323_spi.c
@@ -5,7 +5,6 @@
* Copyright (C) 2023, Jagath Jog J <jagathjog1996@gmail.com>
*/
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -65,7 +64,7 @@ static int bmi323_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id bmi323_spi_ids[] = {
- { "bmi323" },
+ { .name = "bmi323" },
{ }
};
MODULE_DEVICE_TABLE(spi, bmi323_spi_ids);
diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c
index 303bc308f80a..d0101607a9b3 100644
--- a/drivers/iio/imu/bno055/bno055.c
+++ b/drivers/iio/imu/bno055/bno055.c
@@ -64,7 +64,7 @@
#define BNO055_GRAVITY_DATA_X_LSB_REG 0x2E
#define BNO055_GRAVITY_DATA_Y_LSB_REG 0x30
#define BNO055_GRAVITY_DATA_Z_LSB_REG 0x32
-#define BNO055_SCAN_CH_COUNT ((BNO055_GRAVITY_DATA_Z_LSB_REG - BNO055_ACC_DATA_X_LSB_REG) / 2)
+#define BNO055_SCAN_CH_COUNT ((BNO055_GRAVITY_DATA_Z_LSB_REG - BNO055_ACC_DATA_X_LSB_REG) / 2 + 1)
#define BNO055_TEMP_REG 0x34
#define BNO055_CALIB_STAT_REG 0x35
#define BNO055_CALIB_STAT_MAGN_SHIFT 0
@@ -210,9 +210,30 @@ struct bno055_priv {
u8 uid[BNO055_UID_LEN];
struct gpio_desc *reset_gpio;
bool sw_reset;
- struct {
- __le16 chans[BNO055_SCAN_CH_COUNT];
- aligned_s64 timestamp;
+ union {
+ IIO_DECLARE_BUFFER_WITH_TS(__le16, chans, BNO055_SCAN_CH_COUNT);
+ /*
+ * This struct is not used, but it is here to ensure proper size
+ * and alignment of the scan buffer above (because of the extra
+ * requirements of the quaternion field). Technically it is not
+ * needed in this case, because other fields just happen to make
+ * things correctly aligned already. But it is better to be
+ * explicit about the requirements anyway. The actual contents
+ * of the scan buffer will vary depending on which channels are
+ * enabled.
+ */
+ struct {
+ __le16 acc[3];
+ __le16 magn[3];
+ __le16 gyr[3];
+ __le16 yaw;
+ __le16 pitch;
+ __le16 roll;
+ IIO_DECLARE_QUATERNION(__le16, quaternion);
+ __le16 lia[3];
+ __le16 gravity[3];
+ aligned_s64 timestamp;
+ };
} buf;
struct dentry *debugfs;
};
diff --git a/drivers/iio/imu/bno055/bno055_i2c.c b/drivers/iio/imu/bno055/bno055_i2c.c
index f49d0905ee33..7117ec682365 100644
--- a/drivers/iio/imu/bno055/bno055_i2c.c
+++ b/drivers/iio/imu/bno055/bno055_i2c.c
@@ -8,7 +8,6 @@
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -30,7 +29,7 @@ static int bno055_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bno055_i2c_id[] = {
- { "bno055" },
+ { .name = "bno055" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bno055_i2c_id);
diff --git a/drivers/iio/imu/bno055/bno055_ser_core.c b/drivers/iio/imu/bno055/bno055_ser_core.c
index 48669dabb37b..01f05feaae0a 100644
--- a/drivers/iio/imu/bno055/bno055_ser_core.c
+++ b/drivers/iio/imu/bno055/bno055_ser_core.c
@@ -19,7 +19,6 @@
#include <linux/errno.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
@@ -288,7 +287,7 @@ static int bno055_ser_write_reg(void *context, const void *_data, size_t count)
struct bno055_ser_priv *priv = context;
if (count < 2) {
- dev_err(&priv->serdev->dev, "Invalid write count %zu", count);
+ dev_err(&priv->serdev->dev, "Invalid write count %zu\n", count);
return -EINVAL;
}
@@ -306,7 +305,7 @@ static int bno055_ser_read_reg(void *context,
struct bno055_ser_priv *priv = context;
if (val_size > 128) {
- dev_err(&priv->serdev->dev, "Invalid read valsize %zu", val_size);
+ dev_err(&priv->serdev->dev, "Invalid read valsize %zu\n", val_size);
return -EINVAL;
}
diff --git a/drivers/iio/imu/fxos8700_core.c b/drivers/iio/imu/fxos8700_core.c
index 281ebfd9c15a..9d2eb6fbab4a 100644
--- a/drivers/iio/imu/fxos8700_core.c
+++ b/drivers/iio/imu/fxos8700_core.c
@@ -2,7 +2,7 @@
/*
* FXOS8700 - NXP IMU (accelerometer plus magnetometer)
*
- * IIO core driver for FXOS8700, with support for I2C/SPI busses
+ * IIO core driver for FXOS8700, with support for I2C/SPI buses
*
* TODO: Buffer, trigger, and IRQ support
*/
diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c
index 2cc4a27a4527..ba47e9260928 100644
--- a/drivers/iio/imu/fxos8700_i2c.c
+++ b/drivers/iio/imu/fxos8700_i2c.c
@@ -12,7 +12,6 @@
*/
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include "fxos8700.h"
@@ -36,7 +35,7 @@ static int fxos8700_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id fxos8700_i2c_id[] = {
- { "fxos8700" },
+ { .name = "fxos8700" },
{ }
};
MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id);
diff --git a/drivers/iio/imu/fxos8700_spi.c b/drivers/iio/imu/fxos8700_spi.c
index 6b0dc7a776b9..56ad0c5914d9 100644
--- a/drivers/iio/imu/fxos8700_spi.c
+++ b/drivers/iio/imu/fxos8700_spi.c
@@ -3,7 +3,6 @@
* FXOS8700 - NXP IMU, SPI bits
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -24,7 +23,7 @@ static int fxos8700_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id fxos8700_spi_id[] = {
- {"fxos8700", 0},
+ { .name = "fxos8700" },
{ }
};
MODULE_DEVICE_TABLE(spi, fxos8700_spi_id);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
index c8b48a5c5ed0..b55d993f0264 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -6,13 +6,15 @@
#ifndef INV_ICM42600_H_
#define INV_ICM42600_H_
-#include <linux/bits.h>
#include <linux/bitfield.h>
-#include <linux/regmap.h>
+#include <linux/bits.h>
#include <linux/mutex.h>
-#include <linux/regulator/consumer.h>
#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
#include <linux/iio/iio.h>
+
#include <linux/iio/common/inv_sensors_timestamp.h>
#include "inv_icm42600_buffer.h"
@@ -354,6 +356,8 @@ struct inv_icm42600_sensor_state {
cpu_to_le16((_wm) & GENMASK(11, 0))
/* FIFO is 2048 bytes, let 12 samples for reading latency */
#define INV_ICM42600_FIFO_WATERMARK_MAX (2048 - 12 * 16)
+/* INV_ICM42600_FIFO_WATERMARK_MAX / 8 = 232 */
+#define INV_ICM42600_FIFO_WATERMARK_MAX_SAMPLES 232
#define INV_ICM42600_REG_INT_CONFIG1 0x0064
#define INV_ICM42600_INT_CONFIG1_TPULSE_DURATION BIT(6)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index 0ab6eddf0543..4b0e3cd8a506 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -3,25 +3,26 @@
* Copyright (C) 2020 Invensense, Inc.
*/
-#include <linux/kernel.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
-#include <linux/delay.h>
-#include <linux/math64.h>
-#include <linux/minmax.h>
#include <linux/units.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/common/inv_sensors_timestamp.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/common/inv_sensors_timestamp.h>
+
#include "inv_icm42600.h"
-#include "inv_icm42600_temp.h"
#include "inv_icm42600_buffer.h"
+#include "inv_icm42600_temp.h"
#define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \
{ \
@@ -1170,10 +1171,10 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
accel_st->filter = INV_ICM42600_FILTER_AVG_16X;
/*
- * clock period is 32kHz (31250ns)
+ * clock period is 8kHz (125000ns)
* jitter is +/- 2% (20 per mille)
*/
- ts_chip.clock_period = 31250;
+ ts_chip.clock_period = 125000;
ts_chip.jitter = 20;
ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
inv_sensors_timestamp_init(&accel_st->ts, &ts_chip);
@@ -1186,8 +1187,9 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_accel_channels);
indio_dev->available_scan_masks = inv_icm42600_accel_scan_masks;
- ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
- &inv_icm42600_buffer_ops);
+ ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
+ &inv_icm42600_buffer_ops,
+ inv_icm42600_buffer_attrs);
if (ret)
return ERR_PTR(ret);
@@ -1211,7 +1213,7 @@ int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev)
ssize_t i, size;
unsigned int no;
const void *accel, *gyro, *timestamp;
- const int8_t *temp;
+ const s8 *temp;
unsigned int odr;
int64_t ts_val;
/* buffer is copied to userspace, zeroing it to avoid any data leak */
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
index 68a395758031..998d312f7bde 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
@@ -3,17 +3,20 @@
* Copyright (C) 2020 Invensense, Inc.
*/
-#include <linux/kernel.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/kernel.h>
#include <linux/minmax.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
-#include <linux/delay.h>
+#include <linux/stringify.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/common/inv_sensors_timestamp.h>
#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include <linux/iio/common/inv_sensors_timestamp.h>
#include "inv_icm42600.h"
#include "inv_icm42600_buffer.h"
@@ -186,7 +189,7 @@ static unsigned int inv_icm42600_wm_truncate(unsigned int watermark,
* smallest latency but this is not as simple as choosing the smallest watermark
* value. Latency depends on watermark and ODR. It requires several steps:
* 1) compute gyro and accel latencies and choose the smallest value.
- * 2) adapt the choosen latency so that it is a multiple of both gyro and accel
+ * 2) adapt the chosen latency so that it is a multiple of both gyro and accel
* ones. Otherwise it is possible that you don't meet a requirement. (for
* example with gyro @100Hz wm 4 and accel @100Hz with wm 6, choosing the
* value of 4 will not meet accel latency requirement because 6 is not a
@@ -248,6 +251,7 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st)
/* compute watermark value in bytes */
wm_size = watermark * packet_size;
+ st->fifo.watermark.value = watermark;
/* changing FIFO watermark requires to turn off watermark interrupt */
ret = regmap_update_bits_check(st->map, INV_ICM42600_REG_INT_SOURCE0,
@@ -437,6 +441,40 @@ const struct iio_buffer_setup_ops inv_icm42600_buffer_ops = {
.postdisable = inv_icm42600_buffer_postdisable,
};
+static ssize_t hwfifo_watermark_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ unsigned int wm;
+
+ guard(mutex)(&st->lock);
+
+ if (indio_dev == st->indio_accel)
+ wm = st->fifo.watermark.eff_accel;
+ else if (indio_dev == st->indio_gyro)
+ wm = st->fifo.watermark.eff_gyro;
+ else
+ return -EINVAL;
+
+ return sysfs_emit(buf, "%u\n", wm);
+}
+
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1");
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max,
+ __stringify(INV_ICM42600_FIFO_WATERMARK_MAX_SAMPLES));
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0);
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_enabled, "1");
+
+const struct iio_dev_attr *inv_icm42600_buffer_attrs[] = {
+ &iio_dev_attr_hwfifo_watermark_min,
+ &iio_dev_attr_hwfifo_watermark_max,
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
+ NULL
+};
+
int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
unsigned int max)
{
@@ -454,11 +492,10 @@ int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
st->fifo.nb.accel = 0;
st->fifo.nb.total = 0;
- /* compute maximum FIFO read size */
+ /* compute maximum FIFO read size (watermark for max = 0 interrupt case) */
if (max == 0)
- max_count = sizeof(st->fifo.data);
- else
- max_count = max * inv_icm42600_get_packet_size(st->fifo.en);
+ max = st->fifo.watermark.value;
+ max_count = max * inv_icm42600_get_packet_size(st->fifo.en);
/* read FIFO count value */
raw_fifo_count = (__be16 *)st->buffer;
@@ -574,6 +611,7 @@ int inv_icm42600_buffer_init(struct inv_icm42600_state *st)
st->fifo.watermark.eff_gyro = 1;
st->fifo.watermark.eff_accel = 1;
+ st->fifo.watermark.value = 1;
/*
* Default FIFO configuration (bits 7 to 5)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
index ffca4da1e249..e37ee3416337 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
@@ -6,8 +6,8 @@
#ifndef INV_ICM42600_BUFFER_H_
#define INV_ICM42600_BUFFER_H_
-#include <linux/kernel.h>
#include <linux/bits.h>
+#include <linux/kernel.h>
struct inv_icm42600_state;
@@ -34,6 +34,7 @@ struct inv_icm42600_fifo {
unsigned int accel;
unsigned int eff_gyro;
unsigned int eff_accel;
+ unsigned int value;
} watermark;
size_t count;
struct {
@@ -79,6 +80,7 @@ ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel,
const void **timestamp, unsigned int *odr);
extern const struct iio_buffer_setup_ops inv_icm42600_buffer_ops;
+extern const struct iio_dev_attr *inv_icm42600_buffer_attrs[];
int inv_icm42600_buffer_init(struct inv_icm42600_state *st);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index 76eb22488e5f..dc97d8a274e3 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -3,18 +3,18 @@
* Copyright (C) 2020 Invensense, Inc.
*/
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/mutex.h>
+#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/regulator/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
index 11339ddf1da3..253bf571439d 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
@@ -3,22 +3,23 @@
* Copyright (C) 2020 Invensense, Inc.
*/
-#include <linux/kernel.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
-#include <linux/delay.h>
-#include <linux/math64.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/common/inv_sensors_timestamp.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/common/inv_sensors_timestamp.h>
+
#include "inv_icm42600.h"
-#include "inv_icm42600_temp.h"
#include "inv_icm42600_buffer.h"
+#include "inv_icm42600_temp.h"
#define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info) \
{ \
@@ -755,10 +756,10 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
}
/*
- * clock period is 32kHz (31250ns)
+ * clock period is 8kHz (125000ns)
* jitter is +/- 2% (20 per mille)
*/
- ts_chip.clock_period = 31250;
+ ts_chip.clock_period = 125000;
ts_chip.jitter = 20;
ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
inv_sensors_timestamp_init(&gyro_st->ts, &ts_chip);
@@ -772,8 +773,9 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
indio_dev->available_scan_masks = inv_icm42600_gyro_scan_masks;
indio_dev->setup_ops = &inv_icm42600_buffer_ops;
- ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
- &inv_icm42600_buffer_ops);
+ ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
+ &inv_icm42600_buffer_ops,
+ inv_icm42600_buffer_attrs);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
index 7e4d3ea68721..28552d2db91d 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
@@ -3,13 +3,12 @@
* Copyright (C) 2020 InvenSense, Inc.
*/
-#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
-#include <linux/regmap.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/property.h>
+#include <linux/regmap.h>
#include "inv_icm42600.h"
@@ -75,13 +74,13 @@ static int inv_icm42600_probe(struct i2c_client *client)
* supported by this driver
*/
static const struct i2c_device_id inv_icm42600_id[] = {
- { "icm42600", INV_CHIP_ICM42600 },
- { "icm42602", INV_CHIP_ICM42602 },
- { "icm42605", INV_CHIP_ICM42605 },
- { "icm42686", INV_CHIP_ICM42686 },
- { "icm42622", INV_CHIP_ICM42622 },
- { "icm42688", INV_CHIP_ICM42688 },
- { "icm42631", INV_CHIP_ICM42631 },
+ { .name = "icm42600", .driver_data = INV_CHIP_ICM42600 },
+ { .name = "icm42602", .driver_data = INV_CHIP_ICM42602 },
+ { .name = "icm42605", .driver_data = INV_CHIP_ICM42605 },
+ { .name = "icm42686", .driver_data = INV_CHIP_ICM42686 },
+ { .name = "icm42622", .driver_data = INV_CHIP_ICM42622 },
+ { .name = "icm42688", .driver_data = INV_CHIP_ICM42688 },
+ { .name = "icm42631", .driver_data = INV_CHIP_ICM42631 },
{ }
};
MODULE_DEVICE_TABLE(i2c, inv_icm42600_id);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
index 13e2e7d38638..faf743bc6444 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
@@ -3,13 +3,12 @@
* Copyright (C) 2020 InvenSense, Inc.
*/
-#include <linux/kernel.h>
#include <linux/device.h>
+#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/spi/spi.h>
-#include <linux/regmap.h>
#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
#include "inv_icm42600.h"
@@ -72,13 +71,13 @@ static int inv_icm42600_probe(struct spi_device *spi)
* supported by this driver
*/
static const struct spi_device_id inv_icm42600_id[] = {
- { "icm42600", INV_CHIP_ICM42600 },
- { "icm42602", INV_CHIP_ICM42602 },
- { "icm42605", INV_CHIP_ICM42605 },
- { "icm42686", INV_CHIP_ICM42686 },
- { "icm42622", INV_CHIP_ICM42622 },
- { "icm42688", INV_CHIP_ICM42688 },
- { "icm42631", INV_CHIP_ICM42631 },
+ { .name = "icm42600", .driver_data = INV_CHIP_ICM42600 },
+ { .name = "icm42602", .driver_data = INV_CHIP_ICM42602 },
+ { .name = "icm42605", .driver_data = INV_CHIP_ICM42605 },
+ { .name = "icm42686", .driver_data = INV_CHIP_ICM42686 },
+ { .name = "icm42622", .driver_data = INV_CHIP_ICM42622 },
+ { .name = "icm42688", .driver_data = INV_CHIP_ICM42688 },
+ { .name = "icm42631", .driver_data = INV_CHIP_ICM42631 },
{ }
};
MODULE_DEVICE_TABLE(spi, inv_icm42600_id);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
index 727b03d541a5..7f80bda471c3 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
@@ -3,11 +3,12 @@
* Copyright (C) 2020 Invensense, Inc.
*/
-#include <linux/kernel.h>
#include <linux/device.h>
+#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+
#include <linux/iio/iio.h>
#include "inv_icm42600.h"
diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig
new file mode 100644
index 000000000000..23f461f57afc
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Kconfig
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+config INV_ICM42607
+ tristate
+ select IIO_BUFFER
+ select IIO_INV_SENSORS_TIMESTAMP
+
+config INV_ICM42607_I2C
+ tristate "InvenSense ICM-42607 I2C driver"
+ depends on I2C
+ select INV_ICM42607
+ select REGMAP_I2C
+ help
+ This driver supports the InvenSense ICM-42607 motion tracking
+ device over I2C.
+
+ This driver can be built as a module. The module will be called
+ inv-icm42607-i2c.
+
+config INV_ICM42607_SPI
+ tristate "InvenSense ICM-42607 SPI driver"
+ depends on SPI_MASTER
+ select INV_ICM42607
+ select REGMAP_SPI
+ help
+ This driver supports the InvenSense ICM-42607 motion tracking
+ device over SPI.
+
+ This driver can be built as a module. The module will be called
+ inv-icm42607-spi.
diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
new file mode 100644
index 000000000000..7b907e019601
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
+inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_gyro.o
+inv-icm42607-y += inv_icm42607_accel.o
+inv-icm42607-y += inv_icm42607_temp.o
+
+obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
+inv-icm42607-i2c-y += inv_icm42607_i2c.o
+
+obj-$(CONFIG_INV_ICM42607_SPI) += inv-icm42607-spi.o
+inv-icm42607-spi-y += inv_icm42607_spi.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
new file mode 100644
index 000000000000..4d51b0da1aa1
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -0,0 +1,421 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_H_
+#define INV_ICM42607_H_
+
+#include <linux/bits.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <asm/byteorder.h>
+
+/*
+ * Serial bus slew rates. Rates are expressed as range between the two
+ * values with the midpoint as the typical rate. For the final value of
+ * 2ns, 2ns is considered the max value with no expressed minimum or
+ * typical value.
+ */
+enum inv_icm42607_slew_rate {
+ INV_ICM42607_SLEW_RATE_20_60NS = 0,
+ INV_ICM42607_SLEW_RATE_12_36NS = 1,
+ INV_ICM42607_SLEW_RATE_6_19NS = 2,
+ INV_ICM42607_SLEW_RATE_4_14NS = 3,
+ INV_ICM42607_SLEW_RATE_2_6NS = 4,
+ INV_ICM42607_SLEW_RATE_2NS = 5,
+ INV_ICM42607_SLEW_RATE_NB
+};
+
+enum inv_icm42607_sensor_mode {
+ INV_ICM42607_SENSOR_MODE_OFF = 0,
+ INV_ICM42607_SENSOR_MODE_STANDBY = 1,
+ INV_ICM42607_SENSOR_MODE_LOW_POWER = 2,
+ INV_ICM42607_SENSOR_MODE_LOW_NOISE = 3,
+ INV_ICM42607_SENSOR_MODE_NB
+};
+
+/* gyroscope fullscale values */
+enum inv_icm42607_gyro_fs {
+ INV_ICM42607_GYRO_FS_2000DPS = 0,
+ INV_ICM42607_GYRO_FS_1000DPS = 1,
+ INV_ICM42607_GYRO_FS_500DPS = 2,
+ INV_ICM42607_GYRO_FS_250DPS = 3,
+ INV_ICM42607_GYRO_FS_NB
+};
+
+/* accelerometer fullscale values */
+enum inv_icm42607_accel_fs {
+ INV_ICM42607_ACCEL_FS_16G = 0,
+ INV_ICM42607_ACCEL_FS_8G = 1,
+ INV_ICM42607_ACCEL_FS_4G = 2,
+ INV_ICM42607_ACCEL_FS_2G = 3,
+ INV_ICM42607_ACCEL_FS_NB
+};
+
+/* ODR values - Note Gyro does not support ODR less than 12.5Hz */
+enum inv_icm42607_odr {
+ INV_ICM42607_ODR_1600HZ = 5,
+ INV_ICM42607_ODR_800HZ = 6,
+ INV_ICM42607_ODR_400HZ = 7,
+ INV_ICM42607_ODR_200HZ = 8,
+ INV_ICM42607_ODR_100HZ = 9,
+ INV_ICM42607_ODR_50HZ = 10,
+ INV_ICM42607_ODR_25HZ = 11,
+ INV_ICM42607_ODR_12_5HZ = 12,
+ INV_ICM42607_ODR_6_25HZ_LP = 13,
+ INV_ICM42607_ODR_3_125HZ_LP = 14,
+ INV_ICM42607_ODR_1_5625HZ_LP = 15,
+ INV_ICM42607_ODR_NB
+};
+
+/* Low-Noise mode sensor data filter (bandwidth) */
+enum inv_icm42607_filter_bw {
+ INV_ICM42607_FILTER_BYPASS = 0,
+ INV_ICM42607_FILTER_BW_180HZ = 1,
+ INV_ICM42607_FILTER_BW_121HZ = 2,
+ INV_ICM42607_FILTER_BW_73HZ = 3,
+ INV_ICM42607_FILTER_BW_53HZ = 4,
+ INV_ICM42607_FILTER_BW_34HZ = 5,
+ INV_ICM42607_FILTER_BW_25HZ = 6,
+ INV_ICM42607_FILTER_BW_16HZ = 7,
+ INV_ICM42607_FILTER_BW_NB
+};
+
+/* Low-Power mode sensor data filter (averaging) */
+enum inv_icm42607_filter_avg {
+ INV_ICM42607_FILTER_AVG_2X = 0,
+ INV_ICM42607_FILTER_AVG_4X = 1,
+ INV_ICM42607_FILTER_AVG_8X = 2,
+ INV_ICM42607_FILTER_AVG_16X = 3,
+ INV_ICM42607_FILTER_AVG_32X = 4,
+ INV_ICM42607_FILTER_AVG_64X = 5,
+ /* values 6 and 7 also correspond to 64x. */
+};
+
+/* Temperature sensor data filter (bandwidth) */
+enum inv_icm42607_temp_filter_bw {
+ INV_ICM42607_TEMP_FILTER_BYPASS = 0,
+ INV_ICM42607_TEMP_FILTER_BW_180HZ = 1,
+ INV_ICM42607_TEMP_FILTER_BW_72HZ = 2,
+ INV_ICM42607_TEMP_FILTER_BW_34HZ = 3,
+ INV_ICM42607_TEMP_FILTER_BW_16HZ = 4,
+ INV_ICM42607_TEMP_FILTER_BW_8HZ = 5,
+ INV_ICM42607_TEMP_FILTER_BW_4HZ = 6,
+ /* value 7 also corresponds to 4Hz */
+};
+
+/* Signed so that negative values can signify an invalid condition. */
+struct inv_icm42607_sensor_conf {
+ int mode;
+ int fs;
+ int odr;
+ int filter;
+};
+#define INV_ICM42607_SENSOR_CONF_INIT { -1, -1, -1, -1 }
+
+struct inv_icm42607_conf {
+ struct inv_icm42607_sensor_conf gyro;
+ struct inv_icm42607_sensor_conf accel;
+ ktime_t gyro_stop; /* earliest time to stop the gyro */
+};
+
+struct inv_icm42607_hw {
+ const char *name;
+ const struct inv_icm42607_conf *conf;
+ u8 whoami;
+};
+
+/**
+ * struct inv_icm42607_state - driver state variables
+ * @hw: Hardware specific data.
+ * @lock: lock for serializing multiple registers access.
+ * @map: regmap pointer.
+ * @indio_accel: accelerometer IIO device.
+ * @indio_gyro: gyroscope IIO device.
+ * @vddio_supply: I/O voltage regulator for the chip.
+ * @vddio_en: I/O voltage status for runtime PM.
+ * @conf: chip sensors configurations.
+ * @orientation: sensor chip orientation relative to main hardware.
+ */
+struct inv_icm42607_state {
+ const struct inv_icm42607_hw *hw;
+ struct mutex lock;
+ struct regmap *map;
+ struct iio_dev *indio_accel;
+ struct iio_dev *indio_gyro;
+ struct regulator *vddio_supply;
+ bool vddio_en;
+ struct inv_icm42607_conf conf;
+ struct iio_mount_matrix orientation;
+};
+
+/**
+ * struct inv_icm42607_sensor_state - sensor state variables
+ * @power_mode: sensor requested power mode (for common frequencies)
+ * @filter: sensor filter.
+ */
+struct inv_icm42607_sensor_state {
+ enum inv_icm42607_sensor_mode power_mode;
+ int filter;
+};
+
+/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
+
+/* Register Map for User Bank 0 */
+#define INV_ICM42607_REG_MCLK_RDY 0x00
+
+#define INV_ICM42607_REG_DEVICE_CONFIG 0x01
+#define INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE BIT(2)
+#define INV_ICM42607_DEVICE_CONFIG_SPI_MODE BIT(0)
+
+#define INV_ICM42607_REG_SIGNAL_PATH_RESET 0x02
+#define INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET BIT(4)
+#define INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH BIT(2)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG1 0x03
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG2 0x04
+#define INV_ICM42607_DRIVE_CONFIG2_I2C_MASK GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG2_ALL_MASK GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG3 0x05
+#define INV_ICM42607_DRIVE_CONFIG3_SPI_MASK GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_CONFIG 0x06
+#define INV_ICM42607_INT_CONFIG_INT2_LATCHED BIT(5)
+#define INV_ICM42607_INT_CONFIG_INT2_PUSH_PULL BIT(4)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_HIGH BIT(3)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_LOW 0x00
+#define INV_ICM42607_INT_CONFIG_INT1_LATCHED BIT(2)
+#define INV_ICM42607_INT_CONFIG_INT1_PUSH_PULL BIT(1)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_HIGH BIT(0)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_LOW 0x00
+
+/* all sensor data are 16 bits (2 registers wide) in big-endian */
+#define INV_ICM42607_REG_TEMP_DATA1 0x09
+#define INV_ICM42607_REG_TEMP_DATA0 0x0A
+#define INV_ICM42607_REG_ACCEL_DATA_X1 0x0B
+#define INV_ICM42607_REG_ACCEL_DATA_X0 0x0C
+#define INV_ICM42607_REG_ACCEL_DATA_Y1 0x0D
+#define INV_ICM42607_REG_ACCEL_DATA_Y0 0x0E
+#define INV_ICM42607_REG_ACCEL_DATA_Z1 0x0F
+#define INV_ICM42607_REG_ACCEL_DATA_Z0 0x10
+#define INV_ICM42607_REG_GYRO_DATA_X1 0x11
+#define INV_ICM42607_REG_GYRO_DATA_X0 0x12
+#define INV_ICM42607_REG_GYRO_DATA_Y1 0x13
+#define INV_ICM42607_REG_GYRO_DATA_Y0 0x14
+#define INV_ICM42607_REG_GYRO_DATA_Z1 0x15
+#define INV_ICM42607_REG_GYRO_DATA_Z0 0x16
+#define INV_ICM42607_DATA_INVALID -32768
+
+#define INV_ICM42607_REG_TMST_FSYNCH 0x17
+#define INV_ICM42607_REG_TMST_FSYNCL 0x18
+
+/* APEX Data Registers */
+#define INV_ICM42607_REG_APEX_DATA0 0x31
+#define INV_ICM42607_REG_APEX_DATA1 0x32
+#define INV_ICM42607_REG_APEX_DATA2 0x33
+#define INV_ICM42607_REG_APEX_DATA3 0x34
+#define INV_ICM42607_REG_APEX_DATA4 0x1D
+#define INV_ICM42607_REG_APEX_DATA5 0x1E
+
+#define INV_ICM42607_REG_PWR_MGMT0 0x1F
+#define INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL BIT(7)
+#define INV_ICM42607_PWR_MGMT0_IDLE BIT(4)
+#define INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK GENMASK(3, 2)
+#define INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK GENMASK(1, 0)
+
+#define INV_ICM42607_REG_GYRO_CONFIG0 0x20
+#define INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK GENMASK(6, 5)
+#define INV_ICM42607_GYRO_CONFIG0_ODR_MASK GENMASK(3, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG0 0x21
+#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK GENMASK(6, 5)
+#define INV_ICM42607_ACCEL_CONFIG0_ODR_MASK GENMASK(3, 0)
+
+#define INV_ICM42607_REG_TEMP_CONFIG0 0x22
+#define INV_ICM42607_TEMP_CONFIG0_FILTER_MASK GENMASK(6, 4)
+
+#define INV_ICM42607_REG_GYRO_CONFIG1 0x23
+#define INV_ICM42607_GYRO_CONFIG1_FILTER_MASK GENMASK(2, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG1 0x24
+#define INV_ICM42607_ACCEL_CONFIG1_AVG_MASK GENMASK(6, 4)
+#define INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK GENMASK(2, 0)
+
+#define INV_ICM42607_REG_APEX_CONFIG0 0x25
+#define INV_ICM42607_APEX_CONFIG0_DMP_POWER_SAVE_EN BIT(3)
+#define INV_ICM42607_APEX_CONFIG0_DMP_INIT_EN BIT(2)
+#define INV_ICM42607_APEX_CONFIG0_DMP_MEM_RESET_EN BIT(0)
+
+#define INV_ICM42607_REG_APEX_CONFIG1 0x26
+#define INV_ICM42607_APEX_CONFIG1_SMD_ENABLE BIT(6)
+#define INV_ICM42607_APEX_CONFIG1_FF_ENABLE BIT(5)
+#define INV_ICM42607_APEX_CONFIG1_TILT_ENABLE BIT(4)
+#define INV_ICM42607_APEX_CONFIG1_PED_ENABLE BIT(3)
+#define INV_ICM42607_APEX_CONFIG1_DMP_ODR_MASK GENMASK(1, 0)
+
+#define INV_ICM42607_REG_WOM_CONFIG 0x27
+#define INV_ICM42607_WOM_CONFIG_INT_DUR_MASK GENMASK(4, 3)
+#define INV_ICM42607_WOM_CONFIG_INT_MODE BIT(2)
+#define INV_ICM42607_WOM_CONFIG_MODE BIT(1)
+#define INV_ICM42607_WOM_CONFIG_EN BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG1 0x28
+#define INV_ICM42607_FIFO_CONFIG1_MODE BIT(1)
+#define INV_ICM42607_FIFO_CONFIG1_BYPASS BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG2 0x29
+#define INV_ICM42607_REG_FIFO_CONFIG3 0x2A
+#define INV_ICM42607_FIFO_WATERMARK_VAL(_wm) \
+ cpu_to_le16((_wm) & GENMASK(11, 0))
+/* FIFO is 2048 bytes, let 12 samples for reading latency */
+#define INV_ICM42607_FIFO_WATERMARK_MAX (2048 - 12 * 16)
+#define INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE 8
+#define INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE 16
+
+#define INV_ICM42607_REG_INT_SOURCE0 0x2B
+#define INV_ICM42607_INT_SOURCE0_ST_INT1_EN BIT(7)
+#define INV_ICM42607_INT_SOURCE0_FSYNC_INT1_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE0_PLL_RDY_INT1_EN BIT(5)
+#define INV_ICM42607_INT_SOURCE0_RESET_DONE_INT1_EN BIT(4)
+#define INV_ICM42607_INT_SOURCE0_DRDY_INT1_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE0_FIFO_FULL_INT1_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE0_AGC_RDY_INT1_EN BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE1 0x2C
+#define INV_ICM42607_INT_SOURCE1_I3C_ERROR_INT1_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE1_SMD_INT1_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE1_WOM_INT1_EN GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_SOURCE3 0x2D
+#define INV_ICM42607_INT_SOURCE3_ST_INT2_EN BIT(7)
+#define INV_ICM42607_INT_SOURCE3_FSYNC_INT2_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE3_PLL_RDY_INT2_EN BIT(5)
+#define INV_ICM42607_INT_SOURCE3_RESET_DONE_INT2_EN BIT(4)
+#define INV_ICM42607_INT_SOURCE3_DRDY_INT2_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE3_FIFO_THS_INT2_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE3_FIFO_FULL_INT2_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE3_AGC_RDY_INT2_EN BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE4 0x2E
+#define INV_ICM42607_INT_SOURCE4_I3C_ERROR_INT2_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE4_SMD_INT2_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE4_WOM_Z_INT2_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE4_WOM_Y_INT2_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE4_WOM_X_INT2_EN BIT(0)
+
+#define INV_ICM42607_REG_FIFO_LOST_PKT0 0x2F
+#define INV_ICM42607_REG_FIFO_LOST_PKT1 0x30
+
+#define INV_ICM42607_REG_INTF_CONFIG0 0x35
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_FORMAT BIT(6)
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN BIT(5)
+#define INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN BIT(4)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS 2
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS 3
+
+#define INV_ICM42607_REG_INTF_CONFIG1 0x36
+#define INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN BIT(3)
+#define INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN BIT(2)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_INT 0
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL 1
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_OFF 2
+
+#define INV_ICM42607_REG_INT_STATUS_DRDY 0x39
+#define INV_ICM42607_INT_STATUS_DRDY_DATA_RDY BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS 0x3A
+#define INV_ICM42607_INT_STATUS_ST BIT(7)
+#define INV_ICM42607_INT_STATUS_FSYNC BIT(6)
+#define INV_ICM42607_INT_STATUS_PLL_RDY BIT(5)
+#define INV_ICM42607_INT_STATUS_RESET_DONE BIT(4)
+#define INV_ICM42607_INT_STATUS_FIFO_THS BIT(2)
+#define INV_ICM42607_INT_STATUS_FIFO_FULL BIT(1)
+#define INV_ICM42607_INT_STATUS_AGC_RDY BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS2 0x3B
+#define INV_ICM42607_INT_STATUS2_SMD BIT(3)
+#define INV_ICM42607_INT_STATUS2_WOM_INT GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_STATUS3 0x3C
+#define INV_ICM42607_INT_STATUS3_STEP_DET BIT(5)
+#define INV_ICM42607_INT_STATUS3_STEP_CNT_OVF BIT(4)
+#define INV_ICM42607_INT_STATUS3_TILT_DET BIT(3)
+#define INV_ICM42607_INT_STATUS3_FF_DET BIT(2)
+
+/*
+ * FIFO access registers
+ * FIFO count is 16 bits (2 registers) big-endian
+ * FIFO data is a continuous read register to read FIFO content
+ */
+#define INV_ICM42607_REG_FIFO_COUNTH 0x3D
+#define INV_ICM42607_REG_FIFO_COUNTL 0x3E
+#define INV_ICM42607_REG_FIFO_DATA 0x3F
+
+#define INV_ICM42607_REG_WHOAMI 0x75
+#define INV_ICM42607P_WHOAMI 0x60
+#define INV_ICM42607_WHOAMI 0x67
+
+/*
+ * Timings as listed in section 3 of datasheet, all values listed in datasheet
+ * in ms except temp startup time... setting all values in us and using
+ * USEC_PER_MSEC to convert from values displayed in datasheet.
+ */
+#define INV_ICM42607_POWER_UP_TIME_US (100 * USEC_PER_MSEC)
+#define INV_ICM42607_RESET_TIME_US (1 * USEC_PER_MSEC)
+#define INV_ICM42607_ACCEL_STARTUP_TIME_US (10 * USEC_PER_MSEC)
+#define INV_ICM42607_GYRO_STARTUP_TIME_US (30 * USEC_PER_MSEC)
+#define INV_ICM42607_GYRO_STOP_TIME_US (45 * USEC_PER_MSEC)
+#define INV_ICM42607_TEMP_STARTUP_TIME_US 77
+
+/*
+ * Suspend delay assumed from other icm42600 series device, not
+ * documented in datasheet.
+ */
+#define INV_ICM42607_SUSPEND_DELAY_MS (2 * MSEC_PER_SEC)
+
+typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
+
+extern const struct regmap_config inv_icm42607_regmap_config;
+extern const struct inv_icm42607_hw inv_icm42607_hw_data;
+extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
+extern const struct dev_pm_ops inv_icm42607_pm_ops;
+
+const struct iio_mount_matrix *
+inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan);
+
+int inv_icm42607_get_pwr_mgmt0(struct inv_icm42607_state *st,
+ enum inv_icm42607_sensor_mode *gyro,
+ enum inv_icm42607_sensor_mode *accel);
+
+int inv_icm42607_set_sensor_conf(struct inv_icm42607_state *st,
+ struct inv_icm42607_sensor_conf *conf,
+ enum iio_chan_type chan_type);
+
+int inv_icm42607_read_sensor(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ s16 *val);
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+ const struct inv_icm42607_hw *hw,
+ inv_icm42607_bus_setup bus_setup);
+
+struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st);
+
+struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
new file mode 100644
index 000000000000..0b3f035c2da0
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/device/devres.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+#define INV_ICM42607_ACCEL_CHAN(_modifier, _index, _ext_info) \
+{ \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = _modifier, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ }, \
+ .ext_info = _ext_info, \
+}
+
+enum inv_icm42607_accel_scan {
+ INV_ICM42607_ACCEL_SCAN_X,
+ INV_ICM42607_ACCEL_SCAN_Y,
+ INV_ICM42607_ACCEL_SCAN_Z,
+ INV_ICM42607_ACCEL_SCAN_TEMP,
+};
+
+static const struct iio_chan_spec_ext_info inv_icm42607_accel_ext_infos[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix),
+ { }
+};
+
+static const struct iio_chan_spec inv_icm42607_accel_channels[] = {
+ INV_ICM42607_ACCEL_CHAN(IIO_MOD_X, INV_ICM42607_ACCEL_SCAN_X,
+ inv_icm42607_accel_ext_infos),
+ INV_ICM42607_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42607_ACCEL_SCAN_Y,
+ inv_icm42607_accel_ext_infos),
+ INV_ICM42607_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42607_ACCEL_SCAN_Z,
+ inv_icm42607_accel_ext_infos),
+ INV_ICM42607_TEMP_CHAN(INV_ICM42607_ACCEL_SCAN_TEMP),
+};
+
+static const int inv_icm42607_accel_scale_nano[][2] = {
+ [INV_ICM42607_ACCEL_FS_16G] = { 0, 4788403 },
+ [INV_ICM42607_ACCEL_FS_8G] = { 0, 2394202 },
+ [INV_ICM42607_ACCEL_FS_4G] = { 0, 1197101 },
+ [INV_ICM42607_ACCEL_FS_2G] = { 0, 598550 },
+};
+
+static int inv_icm42607_accel_read_scale(struct iio_dev *indio_dev,
+ int *val, int *val2)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ unsigned int idx;
+
+ guard(mutex)(&st->lock);
+
+ idx = st->conf.accel.fs;
+
+ *val = inv_icm42607_accel_scale_nano[idx][0];
+ *val2 = inv_icm42607_accel_scale_nano[idx][1];
+ return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int inv_icm42607_accel_write_scale(struct iio_dev *indio_dev,
+ int val, int val2)
+{
+ struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ size_t scales_len = ARRAY_SIZE(inv_icm42607_accel_scale_nano);
+ struct device *dev = regmap_get_device(st->map);
+ unsigned int idx;
+ int ret;
+
+ for (idx = 0; idx < scales_len; idx++) {
+ if (val == inv_icm42607_accel_scale_nano[idx][0] &&
+ val2 == inv_icm42607_accel_scale_nano[idx][1])
+ break;
+ }
+ if (idx == scales_len)
+ return -EINVAL;
+
+ conf.fs = idx;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&st->lock);
+
+ return inv_icm42607_set_sensor_conf(st, &conf, IIO_ACCEL);
+}
+
+/* IIO format int + micro , values 0-4 reserved. */
+static const int inv_icm42607_accel_odr[][2] = {
+ [INV_ICM42607_ODR_1600HZ] = { 1600, 0 },
+ [INV_ICM42607_ODR_800HZ] = { 800, 0 },
+ [INV_ICM42607_ODR_400HZ] = { 400, 0 },
+ [INV_ICM42607_ODR_200HZ] = { 200, 0 },
+ [INV_ICM42607_ODR_100HZ] = { 100, 0 },
+ [INV_ICM42607_ODR_50HZ] = { 50, 0 },
+ [INV_ICM42607_ODR_25HZ] = { 25, 0 },
+ [INV_ICM42607_ODR_12_5HZ] = { 12, 500000 },
+ [INV_ICM42607_ODR_6_25HZ_LP] = { 6, 250000 },
+ [INV_ICM42607_ODR_3_125HZ_LP] = { 3, 125000 },
+ [INV_ICM42607_ODR_1_5625HZ_LP] = { 1, 562500 },
+};
+
+static int inv_icm42607_accel_read_odr(struct inv_icm42607_state *st,
+ int *val, int *val2)
+{
+ unsigned int odr;
+ unsigned int i;
+
+ guard(mutex)(&st->lock);
+
+ odr = st->conf.accel.odr;
+
+ for (i = INV_ICM42607_ODR_1600HZ; i < ARRAY_SIZE(inv_icm42607_accel_odr); i++) {
+ if (i == odr)
+ break;
+ }
+ if (i == ARRAY_SIZE(inv_icm42607_accel_odr))
+ return -EINVAL;
+
+ *val = inv_icm42607_accel_odr[i][0];
+ *val2 = inv_icm42607_accel_odr[i][1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int inv_icm42607_accel_write_odr(struct iio_dev *indio_dev,
+ int val, int val2)
+{
+ struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ struct device *dev = regmap_get_device(st->map);
+ unsigned int idx;
+ int ret;
+
+ for (idx = INV_ICM42607_ODR_1600HZ;
+ idx < ARRAY_SIZE(inv_icm42607_accel_odr); idx++) {
+ if (val == inv_icm42607_accel_odr[idx][0] &&
+ val2 == inv_icm42607_accel_odr[idx][1])
+ break;
+ }
+ if (idx == ARRAY_SIZE(inv_icm42607_accel_odr))
+ return -EINVAL;
+
+ conf.odr = idx;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&st->lock);
+
+ return inv_icm42607_set_sensor_conf(st, &conf, IIO_ACCEL);
+}
+
+static int inv_icm42607_accel_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ s16 data;
+ int ret;
+
+ switch (chan->type) {
+ case IIO_ACCEL:
+ break;
+ case IIO_TEMP:
+ if (mask != IIO_CHAN_INFO_SAMP_FREQ)
+ return inv_icm42607_temp_read_raw(indio_dev, chan,
+ val, val2, mask);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = inv_icm42607_read_sensor(indio_dev, chan, &data);
+ if (ret)
+ return ret;
+ *val = data;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ return inv_icm42607_accel_read_scale(indio_dev, val, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return inv_icm42607_accel_read_odr(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int inv_icm42607_accel_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_SCALE:
+ if (chan->type != IIO_ACCEL)
+ return -EINVAL;
+ *vals = (const int *)inv_icm42607_accel_scale_nano;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ *length = ARRAY_SIZE(inv_icm42607_accel_scale_nano) * 2;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = (const int *)inv_icm42607_accel_odr[INV_ICM42607_ODR_1600HZ];
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *length = (ARRAY_SIZE(inv_icm42607_accel_odr) -
+ INV_ICM42607_ODR_1600HZ) * 2;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int inv_icm42607_accel_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type != IIO_ACCEL)
+ return -EINVAL;
+ ret = inv_icm42607_accel_write_scale(indio_dev, val, val2);
+ return ret;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return inv_icm42607_accel_write_odr(indio_dev, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int inv_icm42607_accel_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type != IIO_ACCEL)
+ return -EINVAL;
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info inv_icm42607_accel_info = {
+ .read_raw = inv_icm42607_accel_read_raw,
+ .read_avail = inv_icm42607_accel_read_avail,
+ .write_raw = inv_icm42607_accel_write_raw,
+ .write_raw_get_fmt = inv_icm42607_accel_write_raw_get_fmt,
+};
+
+struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st)
+{
+ struct device *dev = regmap_get_device(st->map);
+ struct inv_icm42607_sensor_state *accel_st;
+ struct iio_dev *indio_dev;
+ const char *name;
+ int ret;
+
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->hw->name);
+ if (!name)
+ return ERR_PTR(-ENOMEM);
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st));
+ if (!indio_dev)
+ return ERR_PTR(-ENOMEM);
+
+ accel_st = iio_priv(indio_dev);
+ accel_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+ accel_st->filter = INV_ICM42607_FILTER_BW_73HZ;
+
+ indio_dev->name = name;
+ indio_dev->info = &inv_icm42607_accel_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = inv_icm42607_accel_channels;
+ indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_accel_channels);
+ iio_device_set_drvdata(indio_dev, st);
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return indio_dev;
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
new file mode 100644
index 000000000000..190e998f7b8e
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -0,0 +1,702 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/ktime.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/timekeeping.h>
+#include <linux/types.h>
+
+#include <asm/byteorder.h>
+
+#include "inv_icm42607.h"
+
+static bool inv_icm42607_is_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case INV_ICM42607_REG_MCLK_RDY ... INV_ICM42607_REG_INT_CONFIG:
+ case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_TMST_FSYNCL:
+ case INV_ICM42607_REG_APEX_DATA4 ... INV_ICM42607_REG_INTF_CONFIG1:
+ case INV_ICM42607_REG_INT_STATUS_DRDY ... INV_ICM42607_REG_FIFO_DATA:
+ case INV_ICM42607_REG_WHOAMI:
+ return true;
+ }
+
+ return false;
+}
+
+static bool inv_icm42607_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case INV_ICM42607_REG_DEVICE_CONFIG ... INV_ICM42607_REG_INT_CONFIG:
+ case INV_ICM42607_REG_PWR_MGMT0 ... INV_ICM42607_REG_INT_SOURCE4:
+ case INV_ICM42607_REG_INTF_CONFIG0 ... INV_ICM42607_REG_INTF_CONFIG1:
+ return true;
+ }
+
+ return false;
+}
+
+static bool inv_icm42607_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case INV_ICM42607_REG_MCLK_RDY:
+ case INV_ICM42607_REG_SIGNAL_PATH_RESET:
+ case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_APEX_DATA5:
+ case INV_ICM42607_REG_APEX_CONFIG0:
+ case INV_ICM42607_REG_FIFO_LOST_PKT0 ... INV_ICM42607_REG_APEX_DATA3:
+ case INV_ICM42607_REG_INT_STATUS_DRDY:
+ case INV_ICM42607_REG_INT_STATUS ... INV_ICM42607_REG_FIFO_DATA:
+ return true;
+ }
+
+ return false;
+}
+
+const struct regmap_config inv_icm42607_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = inv_icm42607_is_writeable_reg,
+ .readable_reg = inv_icm42607_is_readable_reg,
+ .volatile_reg = inv_icm42607_is_volatile_reg,
+ .max_register = INV_ICM42607_REG_WHOAMI,
+ .cache_type = REGCACHE_MAPLE,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_regmap_config, "IIO_ICM42607");
+
+/* chip initial default configuration */
+static const struct inv_icm42607_conf inv_icm42607_default_conf = {
+ .gyro = {
+ .mode = INV_ICM42607_SENSOR_MODE_OFF,
+ .fs = INV_ICM42607_GYRO_FS_1000DPS,
+ .odr = INV_ICM42607_ODR_100HZ,
+ .filter = INV_ICM42607_FILTER_BW_25HZ,
+ },
+ .accel = {
+ .mode = INV_ICM42607_SENSOR_MODE_OFF,
+ .fs = INV_ICM42607_ACCEL_FS_4G,
+ .odr = INV_ICM42607_ODR_100HZ,
+ .filter = INV_ICM42607_FILTER_BW_25HZ,
+ },
+};
+
+const struct inv_icm42607_hw inv_icm42607_hw_data = {
+ .whoami = INV_ICM42607_WHOAMI,
+ .name = "icm42607",
+ .conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_hw_data, "IIO_ICM42607");
+
+const struct inv_icm42607_hw inv_icm42607p_hw_data = {
+ .whoami = INV_ICM42607P_WHOAMI,
+ .name = "icm42607p",
+ .conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
+
+const struct iio_mount_matrix *
+inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ const struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+
+ return &st->orientation;
+}
+
+static u32 inv_icm42607_odr_to_period_us(enum inv_icm42607_odr odr)
+{
+ static const u32 odr_periods[INV_ICM42607_ODR_NB] = {
+ /* Reserved values */
+ 0, 0, 0, 0, 0,
+ /* 1600Hz */
+ 625,
+ /* 800Hz */
+ 1250,
+ /* 400Hz */
+ 2500,
+ /* 200Hz */
+ 5000,
+ /* 100 Hz */
+ 10000,
+ /* 50Hz */
+ 20000,
+ /* 25Hz */
+ 40000,
+ /* 12.5Hz */
+ 80000,
+ /* 6.25Hz */
+ 160000,
+ /* 3.125Hz */
+ 320000,
+ /* 1.5625Hz */
+ 640000,
+ };
+
+ odr = clamp(odr, INV_ICM42607_ODR_1600HZ, INV_ICM42607_ODR_1_5625HZ_LP);
+
+ return odr_periods[odr];
+}
+
+int inv_icm42607_get_pwr_mgmt0(struct inv_icm42607_state *st,
+ enum inv_icm42607_sensor_mode *gyro,
+ enum inv_icm42607_sensor_mode *accel)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->map, INV_ICM42607_REG_PWR_MGMT0, &val);
+ if (ret)
+ return ret;
+
+ *gyro = FIELD_GET(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, val);
+ *accel = FIELD_GET(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, val);
+
+ return 0;
+}
+
+static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
+ enum inv_icm42607_sensor_mode gyro,
+ enum inv_icm42607_sensor_mode accel)
+{
+ enum inv_icm42607_sensor_mode oldaccel, oldgyro;
+ unsigned int sleepval_us, odr_us;
+ unsigned int val;
+ s64 disable_wait;
+ int ret;
+
+ ret = inv_icm42607_get_pwr_mgmt0(st, &oldgyro, &oldaccel);
+ if (ret)
+ return ret;
+
+ if (gyro == oldgyro && accel == oldaccel)
+ return 0;
+
+ /*
+ * Datasheet on page 14.26 says we need to ensure the gyro sensor is on
+ * for a minimum of 45ms. So if we transition from an on state to an
+ * off state make sure at least 45ms have passed before power off and
+ * wait if it hasn't. In case some platforms don't respond well to a
+ * sleep of 0, make sure the fsleep duration is > 0.
+ */
+ if (!gyro && oldgyro) {
+ disable_wait = clamp(ktime_us_delta(st->conf.gyro_stop, ktime_get()),
+ 0, INV_ICM42607_GYRO_STOP_TIME_US);
+
+ if (disable_wait > 0)
+ fsleep(disable_wait);
+ }
+
+ val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, gyro) |
+ FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, accel);
+ ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+ if (ret)
+ return ret;
+
+ /*
+ * If a state change occurs from off to on, sleep for the startup time
+ * of the sensor. Since more than one sensor can be transitioned from
+ * off to on, select the maximum time from each of the sensors changing
+ * from off to on. Also account for the time it takes for the first
+ * sample to be ready by looking up the odr value and adding it to the
+ * sleep time. The startup time for the temp sensor is considerably
+ * smaller than the startup time for the other sensors and one or more
+ * are required to be on for the temp sensor to function, so any start
+ * delay should be enough.
+ */
+ sleepval_us = 0;
+ odr_us = 0;
+ if (accel && !oldaccel) {
+ sleepval_us = max(sleepval_us, INV_ICM42607_ACCEL_STARTUP_TIME_US);
+ odr_us = max(odr_us, inv_icm42607_odr_to_period_us(st->conf.accel.odr));
+ }
+
+ if (gyro && !oldgyro) {
+ sleepval_us = max(sleepval_us, INV_ICM42607_GYRO_STARTUP_TIME_US);
+ odr_us = max(odr_us, inv_icm42607_odr_to_period_us(st->conf.gyro.odr));
+ /* Track the earliest we can turn off the gyroscope. */
+ st->conf.gyro_stop = ktime_add_us(ktime_get(),
+ INV_ICM42607_GYRO_STOP_TIME_US);
+ }
+
+ sleepval_us += odr_us;
+
+ /*
+ * Only sleep if sleepval_us is greater than 0 in case some platforms
+ * have issues with a 0 delay. The 0 delay can happen if one or both
+ * sensors is shut down.
+ */
+ if (sleepval_us > 0)
+ fsleep(sleepval_us);
+
+ return 0;
+}
+
+/*
+ * Sanity test between old and new config values, and note if we need
+ * to update register config0 or config1.
+ */
+static void inv_icm42607_update_config(struct inv_icm42607_sensor_conf *conf,
+ struct inv_icm42607_sensor_conf *oldconf,
+ bool *config0, bool *config1)
+{
+ if (conf->mode < 0)
+ conf->mode = oldconf->mode;
+ if (conf->fs < 0)
+ conf->fs = oldconf->fs;
+ if (conf->odr < 0)
+ conf->odr = oldconf->odr;
+ if (conf->filter < 0)
+ conf->filter = oldconf->filter;
+
+ *config0 = (conf->fs != oldconf->fs) || (conf->odr != oldconf->odr);
+
+ *config1 = (conf->filter != oldconf->filter);
+}
+
+int inv_icm42607_set_sensor_conf(struct inv_icm42607_state *st,
+ struct inv_icm42607_sensor_conf *conf,
+ enum iio_chan_type chan_type)
+{
+ enum inv_icm42607_sensor_mode accel_mode, gyro_mode;
+ struct inv_icm42607_sensor_conf *oldconf;
+ bool config0, config1;
+ unsigned int val;
+ int ret;
+
+ switch (chan_type) {
+ case IIO_ACCEL:
+ oldconf = &st->conf.accel;
+ break;
+ case IIO_ANGL_VEL:
+ oldconf = &st->conf.gyro;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Since we are only making one-shot calls today, we can avoid needless
+ * on/off cycles if we rely on the runtime power management to handle
+ * shutting off the sensors when not in use. The downside is if we
+ * enable both sensors then only read from one, we have to wait for
+ * runtime PM to turn it off. So just keep the mode of the sensor we
+ * are not actively using to whatever it's already set as.
+ */
+ ret = inv_icm42607_get_pwr_mgmt0(st, &gyro_mode, &accel_mode);
+ if (ret)
+ return ret;
+
+ inv_icm42607_update_config(conf, oldconf, &config0, &config1);
+
+ if (config0) {
+ if (chan_type == IIO_ANGL_VEL) {
+ val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK, conf->fs);
+ val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK, conf->odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+ } else {
+ val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->fs);
+ val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+ }
+ if (ret)
+ return ret;
+
+ oldconf->fs = conf->fs;
+ oldconf->odr = conf->odr;
+ }
+
+ if (config1) {
+ if (chan_type == IIO_ANGL_VEL) {
+ val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK,
+ conf->filter);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+ INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+ } else {
+ val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK,
+ conf->filter);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+ INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+ }
+ if (ret)
+ return ret;
+
+ oldconf->filter = conf->filter;
+ }
+
+ oldconf->mode = conf->mode;
+
+ switch (chan_type) {
+ case IIO_ACCEL:
+ return inv_icm42607_set_pwr_mgmt0(st, gyro_mode, conf->mode);
+ case IIO_ANGL_VEL:
+ return inv_icm42607_set_pwr_mgmt0(st, conf->mode, accel_mode);
+ default:
+ return -EINVAL;
+ }
+}
+
+int inv_icm42607_read_sensor(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ s16 *val)
+{
+ struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42607_sensor_state *sensor_st = iio_priv(indio_dev);
+ struct device *dev = regmap_get_device(st->map);
+ unsigned int reg;
+ __be16 data;
+ int ret;
+
+ if ((chan->type != IIO_ANGL_VEL) && (chan->type != IIO_ACCEL))
+ return -EINVAL;
+
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ if (chan->type == IIO_ANGL_VEL)
+ reg = INV_ICM42607_REG_GYRO_DATA_X1;
+ else
+ reg = INV_ICM42607_REG_ACCEL_DATA_X1;
+ break;
+ case IIO_MOD_Y:
+ if (chan->type == IIO_ANGL_VEL)
+ reg = INV_ICM42607_REG_GYRO_DATA_Y1;
+ else
+ reg = INV_ICM42607_REG_ACCEL_DATA_Y1;
+ break;
+ case IIO_MOD_Z:
+ if (chan->type == IIO_ANGL_VEL)
+ reg = INV_ICM42607_REG_GYRO_DATA_Z1;
+ else
+ reg = INV_ICM42607_REG_ACCEL_DATA_Z1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&st->lock);
+
+ /* enable sensor */
+ conf.mode = sensor_st->power_mode;
+ conf.filter = sensor_st->filter;
+ ret = inv_icm42607_set_sensor_conf(st, &conf, chan->type);
+ if (ret)
+ return ret;
+
+ /* read sensor register data */
+ ret = regmap_bulk_read(st->map, reg, &data, sizeof(data));
+ if (ret)
+ return ret;
+
+ *val = be16_to_cpu(data);
+ if (*val == INV_ICM42607_DATA_INVALID)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int inv_icm42607_set_init_conf(struct inv_icm42607_state *st,
+ const struct inv_icm42607_conf *conf)
+{
+ unsigned int val;
+ int ret;
+
+ val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, conf->gyro.mode);
+ val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, conf->accel.mode);
+ ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK, conf->gyro.fs);
+ val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK, conf->gyro.odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->accel.fs);
+ val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->accel.odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, conf->gyro.filter);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+ INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, conf->accel.filter);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+ INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_TEMP_CONFIG0_FILTER_MASK,
+ INV_ICM42607_TEMP_FILTER_BW_34HZ);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_TEMP_CONFIG0,
+ INV_ICM42607_TEMP_CONFIG0_FILTER_MASK, val);
+ if (ret)
+ return ret;
+
+ st->conf = *conf;
+
+ return 0;
+}
+
+static int inv_icm42607_setup(struct inv_icm42607_state *st,
+ inv_icm42607_bus_setup inv_icm42607_bus_setup)
+{
+ const struct device *dev = regmap_get_device(st->map);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
+ if (ret)
+ return ret;
+
+ /* Warn, but don't fail. */
+ if (val != st->hw->whoami)
+ dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
+ val, st->hw->whoami, st->hw->name);
+
+ ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+ INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
+ if (ret)
+ return ret;
+
+ fsleep(1 * USEC_PER_MSEC);
+
+ /*
+ * No polling interval specified in datasheet, so use reset time as
+ * polling interval and 10x reset time as timeout period.
+ */
+ ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
+ val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
+ 1 * USEC_PER_MSEC, 10 * USEC_PER_MSEC);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "reset error, reset done bit not set\n");
+
+ /* Sync the regcache again after a reset. */
+ regcache_mark_dirty(st->map);
+ ret = regcache_sync(st->map);
+ if (ret)
+ return ret;
+
+ ret = inv_icm42607_bus_setup(st);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+ INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+ INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+ val);
+ if (ret)
+ return ret;
+
+ return inv_icm42607_set_init_conf(st, st->hw->conf);
+}
+
+static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
+{
+ int ret;
+
+ if (st->vddio_en)
+ return 0;
+
+ ret = regulator_enable(st->vddio_supply);
+ if (ret)
+ return ret;
+
+ fsleep(INV_ICM42607_POWER_UP_TIME_US);
+
+ st->vddio_en = true;
+
+ return 0;
+}
+
+static void inv_icm42607_sensors_off(void *_data)
+{
+ struct inv_icm42607_state *st = _data;
+ const struct device *dev = regmap_get_device(st->map);
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ st->conf.gyro.mode = INV_ICM42607_SENSOR_MODE_OFF;
+ st->conf.accel.mode = INV_ICM42607_SENSOR_MODE_OFF;
+
+ ret = inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode,
+ st->conf.accel.mode);
+ if (ret)
+ dev_err(dev, "Unable to turn off sensors\n");
+}
+
+static void inv_icm42607_disable_vddio_reg(void *_data)
+{
+ struct inv_icm42607_state *st = _data;
+
+ if (!st->vddio_en)
+ return;
+
+ regulator_disable(st->vddio_supply);
+
+ st->vddio_en = false;
+}
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+ const struct inv_icm42607_hw *hw,
+ inv_icm42607_bus_setup inv_icm42607_bus_setup)
+{
+ struct device *dev = regmap_get_device(regmap);
+ struct inv_icm42607_state *st;
+ int ret;
+
+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, st);
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ st->hw = hw;
+ st->map = regmap;
+
+ ret = iio_read_mount_matrix(dev, &st->orientation);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to retrieve mounting matrix\n");
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get vdd regulator\n");
+
+ st->vddio_supply = devm_regulator_get(dev, "vddio");
+ if (IS_ERR(st->vddio_supply))
+ return dev_err_probe(dev, PTR_ERR(st->vddio_supply),
+ "Failed to get vddio regulator\n");
+
+ ret = inv_icm42607_enable_vddio_reg(st);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, inv_icm42607_disable_vddio_reg, st);
+ if (ret)
+ return ret;
+
+ /* Setup chip registers (includes WHOAMI check, reset check, bus setup) */
+ ret = inv_icm42607_setup(st, inv_icm42607_bus_setup);
+ if (ret)
+ return ret;
+
+ /*
+ * Ensure if sensors get turned on at some point, they're turned off
+ * as part of teardown.
+ */
+ ret = devm_add_action_or_reset(dev, inv_icm42607_sensors_off, st);
+ if (ret)
+ return ret;
+
+ ret = devm_pm_runtime_set_active_enabled(dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(dev, INV_ICM42607_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+
+ /* Initialize IIO device for Accel */
+ st->indio_accel = inv_icm42607_accel_init(st);
+ if (IS_ERR(st->indio_accel))
+ return PTR_ERR(st->indio_accel);
+
+ /* Initialize IIO device for Gyro */
+ st->indio_gyro = inv_icm42607_gyro_init(st);
+ if (IS_ERR(st->indio_gyro))
+ return PTR_ERR(st->indio_gyro);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
+
+static int inv_icm42607_suspend(struct device *dev)
+{
+ struct inv_icm42607_state *st = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ return ret;
+
+ inv_icm42607_disable_vddio_reg(st);
+
+ return 0;
+}
+
+static int inv_icm42607_resume(struct device *dev)
+{
+ struct inv_icm42607_state *st = dev_get_drvdata(dev);
+ int ret;
+
+ ret = inv_icm42607_enable_vddio_reg(st);
+ if (ret)
+ return ret;
+
+ /* Sync the regcache again after regulator shutdown. */
+ regcache_mark_dirty(st->map);
+ ret = regcache_sync(st->map);
+ if (ret)
+ return ret;
+
+ return pm_runtime_force_resume(dev);
+}
+
+static int inv_icm42607_runtime_suspend(struct device *dev)
+{
+ struct inv_icm42607_state *st = dev_get_drvdata(dev);
+
+ /*
+ * Set sensors state to off. Since we only support one-shot
+ * today we can use runtime PM to turn sensors off when not
+ * in use, and then when needed the reads/writes will
+ * re-enable the sensors as needed. This reduces complexity,
+ * however the tradeoff is that an unused sensor won't be
+ * turned off until the entire chip is no longer in use.
+ */
+ inv_icm42607_sensors_off(st);
+ return 0;
+}
+
+EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42607_pm_ops, IIO_ICM42607) = {
+ SYSTEM_SLEEP_PM_OPS(inv_icm42607_suspend, inv_icm42607_resume)
+ RUNTIME_PM_OPS(inv_icm42607_runtime_suspend, NULL, NULL)
+};
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607 device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
new file mode 100644
index 000000000000..5b4683c2dd1e
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/device/devres.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+#define INV_ICM42607_GYRO_CHAN(_modifier, _index, _ext_info) \
+{ \
+ .type = IIO_ANGL_VEL, \
+ .modified = 1, \
+ .channel2 = _modifier, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ }, \
+ .ext_info = _ext_info, \
+}
+
+enum inv_icm42607_gyro_scan {
+ INV_ICM42607_GYRO_SCAN_X,
+ INV_ICM42607_GYRO_SCAN_Y,
+ INV_ICM42607_GYRO_SCAN_Z,
+ INV_ICM42607_GYRO_SCAN_TEMP,
+};
+
+static const struct iio_chan_spec_ext_info inv_icm42607_gyro_ext_infos[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix),
+ { }
+};
+
+static const struct iio_chan_spec inv_icm42607_gyro_channels[] = {
+ INV_ICM42607_GYRO_CHAN(IIO_MOD_X, INV_ICM42607_GYRO_SCAN_X,
+ inv_icm42607_gyro_ext_infos),
+ INV_ICM42607_GYRO_CHAN(IIO_MOD_Y, INV_ICM42607_GYRO_SCAN_Y,
+ inv_icm42607_gyro_ext_infos),
+ INV_ICM42607_GYRO_CHAN(IIO_MOD_Z, INV_ICM42607_GYRO_SCAN_Z,
+ inv_icm42607_gyro_ext_infos),
+ INV_ICM42607_TEMP_CHAN(INV_ICM42607_GYRO_SCAN_TEMP),
+};
+
+static const int inv_icm42607_gyro_scale_nano[][2] = {
+ [INV_ICM42607_GYRO_FS_2000DPS] = { 0, 1065264 },
+ [INV_ICM42607_GYRO_FS_1000DPS] = { 0, 532632 },
+ [INV_ICM42607_GYRO_FS_500DPS] = { 0, 266316 },
+ [INV_ICM42607_GYRO_FS_250DPS] = { 0, 133158 },
+};
+
+static int inv_icm42607_gyro_read_scale(struct iio_dev *indio_dev,
+ int *val, int *val2)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ unsigned int idx;
+
+ guard(mutex)(&st->lock);
+
+ idx = st->conf.gyro.fs;
+
+ *val = inv_icm42607_gyro_scale_nano[idx][0];
+ *val2 = inv_icm42607_gyro_scale_nano[idx][1];
+ return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int inv_icm42607_gyro_write_scale(struct iio_dev *indio_dev,
+ int val, int val2)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ struct device *dev = regmap_get_device(st->map);
+ unsigned int idx;
+ struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+ size_t scales_len = ARRAY_SIZE(inv_icm42607_gyro_scale_nano);
+ int ret;
+
+ for (idx = 0; idx < scales_len; idx++) {
+ if (val == inv_icm42607_gyro_scale_nano[idx][0] &&
+ val2 == inv_icm42607_gyro_scale_nano[idx][1])
+ break;
+ }
+ if (idx == scales_len)
+ return -EINVAL;
+
+ conf.fs = idx;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&st->lock);
+
+ return inv_icm42607_set_sensor_conf(st, &conf, IIO_ANGL_VEL);
+}
+
+/* IIO format int + micro , values 0-4 reserved. */
+static const int inv_icm42607_gyro_odr[][2] = {
+ [INV_ICM42607_ODR_1600HZ] = { 1600, 0 },
+ [INV_ICM42607_ODR_800HZ] = { 800, 0 },
+ [INV_ICM42607_ODR_400HZ] = { 400, 0 },
+ [INV_ICM42607_ODR_200HZ] = { 200, 0 },
+ [INV_ICM42607_ODR_100HZ] = { 100, 0 },
+ [INV_ICM42607_ODR_50HZ] = { 50, 0 },
+ [INV_ICM42607_ODR_25HZ] = { 25, 0 },
+ [INV_ICM42607_ODR_12_5HZ] = { 12, 500000 },
+};
+
+static int inv_icm42607_gyro_read_odr(struct inv_icm42607_state *st,
+ int *val, int *val2)
+{
+ unsigned int odr;
+ unsigned int i;
+
+ guard(mutex)(&st->lock);
+
+ odr = st->conf.gyro.odr;
+
+ for (i = INV_ICM42607_ODR_1600HZ; i < ARRAY_SIZE(inv_icm42607_gyro_odr); i++) {
+ if (i == odr)
+ break;
+ }
+ if (i == ARRAY_SIZE(inv_icm42607_gyro_odr))
+ return -EINVAL;
+
+ *val = inv_icm42607_gyro_odr[i][0];
+ *val2 = inv_icm42607_gyro_odr[i][1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int inv_icm42607_gyro_write_odr(struct iio_dev *indio_dev,
+ int val, int val2)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ struct device *dev = regmap_get_device(st->map);
+ unsigned int idx;
+ struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+ int ret;
+
+ for (idx = INV_ICM42607_ODR_1600HZ;
+ idx < ARRAY_SIZE(inv_icm42607_gyro_odr); idx++) {
+ if (val == inv_icm42607_gyro_odr[idx][0] &&
+ val2 == inv_icm42607_gyro_odr[idx][1])
+ break;
+ }
+ if (idx == ARRAY_SIZE(inv_icm42607_gyro_odr))
+ return -EINVAL;
+
+ conf.odr = idx;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&st->lock);
+
+ return inv_icm42607_set_sensor_conf(st, &conf, IIO_ANGL_VEL);
+}
+
+static int inv_icm42607_gyro_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ s16 data;
+ int ret;
+
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ break;
+ case IIO_TEMP:
+ if (mask != IIO_CHAN_INFO_SAMP_FREQ)
+ return inv_icm42607_temp_read_raw(indio_dev, chan,
+ val, val2, mask);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = inv_icm42607_read_sensor(indio_dev, chan, &data);
+ if (ret)
+ return ret;
+ *val = data;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ return inv_icm42607_gyro_read_scale(indio_dev, val, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return inv_icm42607_gyro_read_odr(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int inv_icm42607_gyro_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_SCALE:
+ if (chan->type != IIO_ANGL_VEL)
+ return -EINVAL;
+ *vals = (const int *)inv_icm42607_gyro_scale_nano;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ *length = ARRAY_SIZE(inv_icm42607_gyro_scale_nano) * 2;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = (const int *)inv_icm42607_gyro_odr[INV_ICM42607_ODR_1600HZ];
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *length = (ARRAY_SIZE(inv_icm42607_gyro_odr) -
+ INV_ICM42607_ODR_1600HZ) * 2;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int inv_icm42607_gyro_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type != IIO_ANGL_VEL)
+ return -EINVAL;
+ ret = inv_icm42607_gyro_write_scale(indio_dev, val, val2);
+ return ret;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return inv_icm42607_gyro_write_odr(indio_dev, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int inv_icm42607_gyro_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type != IIO_ANGL_VEL)
+ return -EINVAL;
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info inv_icm42607_gyro_info = {
+ .read_raw = inv_icm42607_gyro_read_raw,
+ .read_avail = inv_icm42607_gyro_read_avail,
+ .write_raw = inv_icm42607_gyro_write_raw,
+ .write_raw_get_fmt = inv_icm42607_gyro_write_raw_get_fmt,
+};
+
+struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st)
+{
+ struct device *dev = regmap_get_device(st->map);
+ const char *name;
+ struct inv_icm42607_sensor_state *gyro_st;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->hw->name);
+ if (!name)
+ return ERR_PTR(-ENOMEM);
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*gyro_st));
+ if (!indio_dev)
+ return ERR_PTR(-ENOMEM);
+
+ gyro_st = iio_priv(indio_dev);
+ gyro_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+ gyro_st->filter = INV_ICM42607_FILTER_BW_73HZ;
+
+ indio_dev->name = name;
+ indio_dev->info = &inv_icm42607_gyro_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = inv_icm42607_gyro_channels;
+ indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_gyro_channels);
+ iio_device_set_drvdata(indio_dev, st);
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return indio_dev;
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
new file mode 100644
index 000000000000..e903106af84a
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_i2c_bus_setup(struct inv_icm42607_state *st)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+ INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+ INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_I2C_MASK,
+ INV_ICM42607_SLEW_RATE_12_36NS);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG2,
+ INV_ICM42607_DRIVE_CONFIG2_I2C_MASK, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS);
+
+ return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ val);
+}
+
+static int inv_icm42607_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ const struct inv_icm42607_hw *hw;
+ struct regmap *regmap;
+
+ hw = i2c_get_match_data(client);
+ if (!hw)
+ return dev_err_probe(dev, -ENODEV, "Failed to get i2c data\n");
+
+ regmap = devm_regmap_init_i2c(client, &inv_icm42607_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to register i2c regmap\n");
+
+ return inv_icm42607_core_probe(regmap, hw, inv_icm42607_i2c_bus_setup);
+}
+
+static const struct i2c_device_id inv_icm42607_id[] = {
+ {
+ .name = "icm42607",
+ .driver_data = (kernel_ulong_t)&inv_icm42607_hw_data,
+ }, {
+ .name = "icm42607p",
+ .driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, inv_icm42607_id);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+ {
+ .compatible = "invensense,icm42607",
+ .data = &inv_icm42607_hw_data,
+ }, {
+ .compatible = "invensense,icm42607p",
+ .data = &inv_icm42607p_hw_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct i2c_driver inv_icm42607_driver = {
+ .driver = {
+ .name = "inv-icm42607-i2c",
+ .of_match_table = inv_icm42607_of_matches,
+ .pm = pm_ptr(&inv_icm42607_pm_ops),
+ },
+ .id_table = inv_icm42607_id,
+ .probe = inv_icm42607_probe,
+};
+module_i2c_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607 I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
new file mode 100644
index 000000000000..cd739375f6b2
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_spi_bus_setup(struct inv_icm42607_state *st)
+{
+ unsigned int val;
+ int ret;
+
+ /* Only support 4-wire mode for now. */
+ ret = regmap_set_bits(st->map, INV_ICM42607_REG_DEVICE_CONFIG,
+ INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE);
+ if (ret)
+ return ret;
+
+ ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+ INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+ INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG3_SPI_MASK,
+ INV_ICM42607_SLEW_RATE_2NS);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG3,
+ INV_ICM42607_DRIVE_CONFIG3_SPI_MASK, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS);
+
+ return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ val);
+}
+
+static int inv_icm42607_probe(struct spi_device *spi)
+{
+ const struct inv_icm42607_hw *hw;
+ struct device *dev = &spi->dev;
+ struct regmap *regmap;
+
+ hw = spi_get_device_match_data(spi);
+ if (!hw)
+ return dev_err_probe(dev, -ENODATA, "Failed to get SPI data\n");
+
+ if (spi->mode & SPI_3WIRE)
+ return dev_err_probe(dev, -ENODEV, "SPI 3-wire mode not supported\n");
+
+ regmap = devm_regmap_init_spi(spi, &inv_icm42607_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to register spi regmap\n");
+
+ return inv_icm42607_core_probe(regmap, hw, inv_icm42607_spi_bus_setup);
+}
+
+static const struct spi_device_id inv_icm42607_spi_id_table[] = {
+ {
+ .name = "icm42607",
+ .driver_data = (kernel_ulong_t)&inv_icm42607_hw_data,
+ }, {
+ .name = "icm42607p",
+ .driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, inv_icm42607_spi_id_table);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+ {
+ .compatible = "invensense,icm42607",
+ .data = &inv_icm42607_hw_data,
+ },
+ {
+ .compatible = "invensense,icm42607p",
+ .data = &inv_icm42607p_hw_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct spi_driver inv_icm42607_driver = {
+ .driver = {
+ .name = "inv-icm42607-spi",
+ .of_match_table = inv_icm42607_of_matches,
+ .pm = pm_ptr(&inv_icm42607_pm_ops),
+ },
+ .id_table = inv_icm42607_spi_id_table,
+ .probe = inv_icm42607_probe,
+};
+module_spi_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607 SPI driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
new file mode 100644
index 000000000000..53f0484c0845
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+static int inv_icm42607_temp_read(struct inv_icm42607_state *st, s16 *temp)
+{
+ struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+ struct device *dev = regmap_get_device(st->map);
+ int ret, gyro_mode, accel_mode;
+ unsigned int val;
+ u8 raw[2];
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&st->lock);
+
+ /*
+ * Check if both the gyro and accel are off and if so, enable one
+ * of them. The temp sensor cannot be read if both the gyro and
+ * accel sensor are off. Prefer to enable the accel over the gyro
+ * as the datasheet says the gyro uses 5x more power and it has
+ * a minimum run time of 45ms.
+ */
+ ret = regmap_read(st->map, INV_ICM42607_REG_PWR_MGMT0, &val);
+ if (ret)
+ return ret;
+
+ accel_mode = FIELD_GET(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, val);
+ gyro_mode = FIELD_GET(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, val);
+ if (!gyro_mode && !accel_mode) {
+ /* enable accel sensor */
+ conf.mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+ ret = inv_icm42607_set_sensor_conf(st, &conf, IIO_ACCEL);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_bulk_read(st->map, INV_ICM42607_REG_TEMP_DATA1,
+ raw, sizeof(raw));
+ if (ret)
+ return ret;
+
+ *temp = get_unaligned_be16(raw);
+ if (*temp == INV_ICM42607_DATA_INVALID)
+ return -EINVAL;
+
+ return 0;
+}
+
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+ s16 temp;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = inv_icm42607_temp_read(st, &temp);
+ if (ret)
+ return ret;
+ *val = temp;
+ return IIO_VAL_INT;
+ /*
+ * T°C = (temp / 128) + 25
+ * Tm°C = 1000 * ((temp * 100 / 12800) + 25)
+ * scale: 100000 / 12800 ~= 7.8125
+ * offset: 3200
+ */
+ case IIO_CHAN_INFO_SCALE:
+ *val = 7;
+ *val2 = 812500000;
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = 3200;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
new file mode 100644
index 000000000000..18499b4d0b94
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_TEMP_H_
+#define INV_ICM42607_TEMP_H_
+
+#include <linux/bitops.h>
+
+struct iio_dev;
+struct iio_chan_spec;
+
+#define INV_ICM42607_TEMP_CHAN(_index) \
+{ \
+ .type = IIO_TEMP, \
+ .info_mask_separate = \
+ BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_OFFSET) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600.h b/drivers/iio/imu/inv_icm45600/inv_icm45600.h
index 1c796d4b2a40..95fa934a42b4 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600.h
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600.h
@@ -190,7 +190,7 @@ struct inv_icm45600_sensor_state {
#define INV_ICM45600_REG_IREG_ADDR 0x7C
#define INV_ICM45600_REG_IREG_DATA 0x7E
-/* Direct acces registers */
+/* Direct access registers */
#define INV_ICM45600_REG_MISC2 0x007F
#define INV_ICM45600_MISC2_SOFT_RESET BIT(1)
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c
index 2b9ea317385c..42111c543d3c 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c
@@ -422,8 +422,11 @@ int inv_icm45600_buffer_fifo_read(struct inv_icm45600_state *st,
if (max > 0 && fifo_nb > max)
fifo_nb = max;
- /* Try to read all FIFO data in internal buffer. */
- st->fifo.count = fifo_nb * packet_size;
+ /*
+ * Read all FIFO data into the internal buffer, clamping the
+ * device-reported count to the buffer capacity.
+ */
+ st->fifo.count = min(fifo_nb * packet_size, INV_ICM45600_FIFO_SIZE_MAX);
ret = regmap_noinc_read(st->map, INV_ICM45600_REG_FIFO_DATA,
st->fifo.data, st->fifo.count);
if (ret == -ENOTSUPP || ret == -EFBIG) {
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c
index d49053161a65..c1d7aa7e950d 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c
@@ -716,7 +716,7 @@ int inv_icm45600_core_probe(struct regmap *regmap, const struct inv_icm45600_chi
dev_set_drvdata(dev, st);
- st->fifo.data = devm_kzalloc(dev, 8192, GFP_KERNEL);
+ st->fifo.data = devm_kzalloc(dev, INV_ICM45600_FIFO_SIZE_MAX, GFP_KERNEL);
if (!st->fifo.data)
return -ENOMEM;
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c
index 5ebc18121a11..69acf9bac2db 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c
@@ -5,7 +5,6 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include "inv_icm45600.h"
@@ -23,7 +22,7 @@ static int inv_icm45600_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
return -ENODEV;
- chip_info = device_get_match_data(&client->dev);
+ chip_info = i2c_get_match_data(client);
if (!chip_info)
return -ENODEV;
@@ -39,14 +38,14 @@ static int inv_icm45600_probe(struct i2c_client *client)
* supported by this driver.
*/
static const struct i2c_device_id inv_icm45600_id[] = {
- { "icm45605", (kernel_ulong_t)&inv_icm45605_chip_info },
- { "icm45606", (kernel_ulong_t)&inv_icm45606_chip_info },
- { "icm45608", (kernel_ulong_t)&inv_icm45608_chip_info },
- { "icm45634", (kernel_ulong_t)&inv_icm45634_chip_info },
- { "icm45686", (kernel_ulong_t)&inv_icm45686_chip_info },
- { "icm45687", (kernel_ulong_t)&inv_icm45687_chip_info },
- { "icm45688p", (kernel_ulong_t)&inv_icm45688p_chip_info },
- { "icm45689", (kernel_ulong_t)&inv_icm45689_chip_info },
+ { .name = "icm45605", .driver_data = (kernel_ulong_t)&inv_icm45605_chip_info },
+ { .name = "icm45606", .driver_data = (kernel_ulong_t)&inv_icm45606_chip_info },
+ { .name = "icm45608", .driver_data = (kernel_ulong_t)&inv_icm45608_chip_info },
+ { .name = "icm45634", .driver_data = (kernel_ulong_t)&inv_icm45634_chip_info },
+ { .name = "icm45686", .driver_data = (kernel_ulong_t)&inv_icm45686_chip_info },
+ { .name = "icm45687", .driver_data = (kernel_ulong_t)&inv_icm45687_chip_info },
+ { .name = "icm45688p", .driver_data = (kernel_ulong_t)&inv_icm45688p_chip_info },
+ { .name = "icm45689", .driver_data = (kernel_ulong_t)&inv_icm45689_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, inv_icm45600_id);
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c
index 9247eae9b3e2..8fb2e519bfc8 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c
@@ -2,7 +2,6 @@
/* Copyright (C) 2025 InvenSense, Inc. */
#include <linux/err.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c
index 6288113a6d7c..087e590e04c2 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c
@@ -5,7 +5,6 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -49,14 +48,14 @@ static int inv_icm45600_probe(struct spi_device *spi)
* supported by this driver.
*/
static const struct spi_device_id inv_icm45600_id[] = {
- { "icm45605", (kernel_ulong_t)&inv_icm45605_chip_info },
- { "icm45606", (kernel_ulong_t)&inv_icm45606_chip_info },
- { "icm45608", (kernel_ulong_t)&inv_icm45608_chip_info },
- { "icm45634", (kernel_ulong_t)&inv_icm45634_chip_info },
- { "icm45686", (kernel_ulong_t)&inv_icm45686_chip_info },
- { "icm45687", (kernel_ulong_t)&inv_icm45687_chip_info },
- { "icm45688p", (kernel_ulong_t)&inv_icm45688p_chip_info },
- { "icm45689", (kernel_ulong_t)&inv_icm45689_chip_info },
+ { .name = "icm45605", .driver_data = (kernel_ulong_t)&inv_icm45605_chip_info },
+ { .name = "icm45606", .driver_data = (kernel_ulong_t)&inv_icm45606_chip_info },
+ { .name = "icm45608", .driver_data = (kernel_ulong_t)&inv_icm45608_chip_info },
+ { .name = "icm45634", .driver_data = (kernel_ulong_t)&inv_icm45634_chip_info },
+ { .name = "icm45686", .driver_data = (kernel_ulong_t)&inv_icm45686_chip_info },
+ { .name = "icm45687", .driver_data = (kernel_ulong_t)&inv_icm45687_chip_info },
+ { .name = "icm45688p", .driver_data = (kernel_ulong_t)&inv_icm45688p_chip_info },
+ { .name = "icm45689", .driver_data = (kernel_ulong_t)&inv_icm45689_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, inv_icm45600_id);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
index 8dc61812a8fc..9ef6ab74af8b 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
@@ -7,7 +7,6 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
@@ -174,24 +173,24 @@ static void inv_mpu_remove(struct i2c_client *client)
* supported by this driver
*/
static const struct i2c_device_id inv_mpu_id[] = {
- {"mpu6050", INV_MPU6050},
- {"mpu6500", INV_MPU6500},
- {"mpu6515", INV_MPU6515},
- {"mpu6880", INV_MPU6880},
- {"mpu9150", INV_MPU9150},
- {"mpu9250", INV_MPU9250},
- {"mpu9255", INV_MPU9255},
- {"icm20608", INV_ICM20608},
- {"icm20608d", INV_ICM20608D},
- {"icm20609", INV_ICM20609},
- {"icm20689", INV_ICM20689},
- {"icm20600", INV_ICM20600},
- {"icm20602", INV_ICM20602},
- {"icm20690", INV_ICM20690},
- {"iam20380", INV_IAM20380},
- {"iam20680", INV_IAM20680},
- {"iam20680hp", INV_IAM20680HP},
- {"iam20680ht", INV_IAM20680HT},
+ { .name = "mpu6050", .driver_data = INV_MPU6050 },
+ { .name = "mpu6500", .driver_data = INV_MPU6500 },
+ { .name = "mpu6515", .driver_data = INV_MPU6515 },
+ { .name = "mpu6880", .driver_data = INV_MPU6880 },
+ { .name = "mpu9150", .driver_data = INV_MPU9150 },
+ { .name = "mpu9250", .driver_data = INV_MPU9250 },
+ { .name = "mpu9255", .driver_data = INV_MPU9255 },
+ { .name = "icm20608", .driver_data = INV_ICM20608 },
+ { .name = "icm20608d", .driver_data = INV_ICM20608D },
+ { .name = "icm20609", .driver_data = INV_ICM20609 },
+ { .name = "icm20689", .driver_data = INV_ICM20689 },
+ { .name = "icm20600", .driver_data = INV_ICM20600 },
+ { .name = "icm20602", .driver_data = INV_ICM20602 },
+ { .name = "icm20690", .driver_data = INV_ICM20690 },
+ { .name = "iam20380", .driver_data = INV_IAM20380 },
+ { .name = "iam20680", .driver_data = INV_IAM20680 },
+ { .name = "iam20680hp", .driver_data = INV_IAM20680HP },
+ { .name = "iam20680ht", .driver_data = INV_IAM20680HT },
{ }
};
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
index 6aee6c989485..6b858fdfd1c6 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
@@ -106,9 +106,9 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
return ret;
/*
- * Sensor sentivity
+ * Sensor sensitivity
* 1 uT = 0.01 G and value is in micron (1e6)
- * sensitvity = x uT * 0.01 * 1e6
+ * sensitivity = x uT * 0.01 * 1e6
*/
switch (st->chip_type) {
case INV_MPU9150:
@@ -125,7 +125,7 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
}
/*
- * Sensitivity adjustement and scale to Gauss
+ * Sensitivity adjustment and scale to Gauss
*
* Hadj = H * (((ASA - 128) * 0.5 / 128) + 1)
* Factor simplification:
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
index 1f4c62142b60..71e90ddc19dd 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
@@ -2,7 +2,6 @@
/*
* Copyright (C) 2015 Intel Corporation Inc.
*/
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
@@ -66,23 +65,23 @@ static int inv_mpu_probe(struct spi_device *spi)
* supported by this driver
*/
static const struct spi_device_id inv_mpu_id[] = {
- {"mpu6000", INV_MPU6000},
- {"mpu6500", INV_MPU6500},
- {"mpu6515", INV_MPU6515},
- {"mpu6880", INV_MPU6880},
- {"mpu9250", INV_MPU9250},
- {"mpu9255", INV_MPU9255},
- {"icm20608", INV_ICM20608},
- {"icm20608d", INV_ICM20608D},
- {"icm20609", INV_ICM20609},
- {"icm20689", INV_ICM20689},
- {"icm20600", INV_ICM20600},
- {"icm20602", INV_ICM20602},
- {"icm20690", INV_ICM20690},
- {"iam20380", INV_IAM20380},
- {"iam20680", INV_IAM20680},
- {"iam20680hp", INV_IAM20680HP},
- {"iam20680ht", INV_IAM20680HT},
+ { .name = "mpu6000", .driver_data = INV_MPU6000 },
+ { .name = "mpu6500", .driver_data = INV_MPU6500 },
+ { .name = "mpu6515", .driver_data = INV_MPU6515 },
+ { .name = "mpu6880", .driver_data = INV_MPU6880 },
+ { .name = "mpu9250", .driver_data = INV_MPU9250 },
+ { .name = "mpu9255", .driver_data = INV_MPU9255 },
+ { .name = "icm20608", .driver_data = INV_ICM20608 },
+ { .name = "icm20608d", .driver_data = INV_ICM20608D },
+ { .name = "icm20609", .driver_data = INV_ICM20609 },
+ { .name = "icm20689", .driver_data = INV_ICM20689 },
+ { .name = "icm20600", .driver_data = INV_ICM20600 },
+ { .name = "icm20602", .driver_data = INV_ICM20602 },
+ { .name = "icm20690", .driver_data = INV_ICM20690 },
+ { .name = "iam20380", .driver_data = INV_IAM20380 },
+ { .name = "iam20680", .driver_data = INV_IAM20680 },
+ { .name = "iam20680hp", .driver_data = INV_IAM20680HP },
+ { .name = "iam20680ht", .driver_data = INV_IAM20680HT },
{ }
};
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index 3cd91d8a89ee..c288437d53ea 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -7,9 +7,9 @@
* IIO driver for KMX61 (7-bit I2C slave address 0x0E or 0x0F).
*/
+#include <linux/cleanup.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@@ -783,7 +783,7 @@ static int kmx61_read_raw(struct iio_dev *indio_dev,
struct kmx61_data *data = kmx61_get_data(indio_dev);
switch (mask) {
- case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_RAW: {
switch (chan->type) {
case IIO_ACCEL:
base_reg = KMX61_ACC_XOUT_L;
@@ -794,28 +794,24 @@ static int kmx61_read_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
ret = kmx61_set_power_state(data, true, chan->address);
- if (ret) {
- mutex_unlock(&data->lock);
+ if (ret)
return ret;
- }
ret = kmx61_read_measurement(data, base_reg, chan->scan_index);
if (ret < 0) {
kmx61_set_power_state(data, false, chan->address);
- mutex_unlock(&data->lock);
return ret;
}
*val = sign_extend32(ret >> chan->scan_type.shift,
chan->scan_type.realbits - 1);
ret = kmx61_set_power_state(data, false, chan->address);
-
- mutex_unlock(&data->lock);
if (ret)
return ret;
return IIO_VAL_INT;
+ }
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ACCEL:
@@ -830,45 +826,46 @@ static int kmx61_read_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
- case IIO_CHAN_INFO_SAMP_FREQ:
+ case IIO_CHAN_INFO_SAMP_FREQ: {
if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN)
return -EINVAL;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
+
ret = kmx61_get_odr(data, val, val2, chan->address);
- mutex_unlock(&data->lock);
if (ret)
return -EINVAL;
return IIO_VAL_INT_PLUS_MICRO;
}
- return -EINVAL;
+ default:
+ return -EINVAL;
+ }
}
static int kmx61_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
{
- int ret;
struct kmx61_data *data = kmx61_get_data(indio_dev);
switch (mask) {
- case IIO_CHAN_INFO_SAMP_FREQ:
+ case IIO_CHAN_INFO_SAMP_FREQ: {
if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN)
return -EINVAL;
- mutex_lock(&data->lock);
- ret = kmx61_set_odr(data, val, val2, chan->address);
- mutex_unlock(&data->lock);
- return ret;
+ guard(mutex)(&data->lock);
+
+ return kmx61_set_odr(data, val, val2, chan->address);
+ }
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
- case IIO_ACCEL:
+ case IIO_ACCEL: {
if (val != 0)
return -EINVAL;
- mutex_lock(&data->lock);
- ret = kmx61_set_scale(data, val2);
- mutex_unlock(&data->lock);
- return ret;
+ guard(mutex)(&data->lock);
+
+ return kmx61_set_scale(data, val2);
+ }
default:
return -EINVAL;
}
@@ -945,29 +942,26 @@ static int kmx61_write_event_config(struct iio_dev *indio_dev,
if (state && data->ev_enable_state)
return 0;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
if (!state && data->motion_trig_on) {
data->ev_enable_state = false;
- goto err_unlock;
+ return ret;
}
ret = kmx61_set_power_state(data, state, KMX61_ACC);
if (ret < 0)
- goto err_unlock;
+ return ret;
ret = kmx61_setup_any_motion_interrupt(data, state);
if (ret < 0) {
kmx61_set_power_state(data, false, KMX61_ACC);
- goto err_unlock;
+ return ret;
}
data->ev_enable_state = state;
-err_unlock:
- mutex_unlock(&data->lock);
-
- return ret;
+ return 0;
}
static int kmx61_acc_validate_trigger(struct iio_dev *indio_dev,
@@ -1020,11 +1014,11 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig,
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct kmx61_data *data = kmx61_get_data(indio_dev);
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
if (!state && data->ev_enable_state && data->motion_trig_on) {
data->motion_trig_on = false;
- goto err_unlock;
+ return ret;
}
if (data->acc_dready_trig == trig || data->motion_trig == trig)
@@ -1034,7 +1028,7 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig,
ret = kmx61_set_power_state(data, state, device);
if (ret < 0)
- goto err_unlock;
+ return ret;
if (data->acc_dready_trig == trig || data->mag_dready_trig == trig)
ret = kmx61_setup_new_data_interrupt(data, state, device);
@@ -1042,7 +1036,7 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig,
ret = kmx61_setup_any_motion_interrupt(data, state);
if (ret < 0) {
kmx61_set_power_state(data, false, device);
- goto err_unlock;
+ return ret;
}
if (data->acc_dready_trig == trig)
@@ -1051,10 +1045,8 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig,
data->mag_dready_trig_on = state;
else
data->motion_trig_on = state;
-err_unlock:
- mutex_unlock(&data->lock);
- return ret;
+ return 0;
}
static void kmx61_trig_reenable(struct iio_trigger *trig)
@@ -1181,30 +1173,49 @@ static irqreturn_t kmx61_data_rdy_trig_poll(int irq, void *private)
return IRQ_HANDLED;
}
-static irqreturn_t kmx61_trigger_handler(int irq, void *p)
+/**
+ * kmx61_read_for_each_active_channel() - Read each active channel into a buffer
+ *
+ * @indio_dev: IIO Device struct to read from
+ * @buffer: Destination buffer to write to, the array must be of at least size 8
+ *
+ * Return:
+ * 0 on success, negative errno on failure.
+ */
+static int kmx61_read_for_each_active_channel(struct iio_dev *indio_dev, s16 *buffer)
{
- struct iio_poll_func *pf = p;
- struct iio_dev *indio_dev = pf->indio_dev;
struct kmx61_data *data = kmx61_get_data(indio_dev);
- int bit, ret, i = 0;
u8 base;
- s16 buffer[8] = { };
+ int ret, bit;
+ int i = 0;
if (indio_dev == data->acc_indio_dev)
base = KMX61_ACC_XOUT_L;
else
base = KMX61_MAG_XOUT_L;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
+
iio_for_each_active_channel(indio_dev, bit) {
ret = kmx61_read_measurement(data, base, bit);
- if (ret < 0) {
- mutex_unlock(&data->lock);
- goto err;
- }
+ if (ret < 0)
+ return ret;
buffer[i++] = ret;
}
- mutex_unlock(&data->lock);
+
+ return 0;
+}
+
+static irqreturn_t kmx61_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ int ret;
+ s16 buffer[8] = { };
+
+ ret = kmx61_read_for_each_active_channel(indio_dev, buffer);
+ if (ret < 0)
+ goto err;
iio_push_to_buffers(indio_dev, buffer);
err:
@@ -1419,22 +1430,18 @@ static void kmx61_remove(struct i2c_client *client)
iio_trigger_unregister(data->motion_trig);
}
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
+
kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
- mutex_unlock(&data->lock);
}
static int kmx61_suspend(struct device *dev)
{
- int ret;
struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
- mutex_lock(&data->lock);
- ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG,
- false);
- mutex_unlock(&data->lock);
+ guard(mutex)(&data->lock);
- return ret;
+ return kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, false);
}
static int kmx61_resume(struct device *dev)
@@ -1453,13 +1460,10 @@ static int kmx61_resume(struct device *dev)
static int kmx61_runtime_suspend(struct device *dev)
{
struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
- int ret;
- mutex_lock(&data->lock);
- ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
- mutex_unlock(&data->lock);
+ guard(mutex)(&data->lock);
- return ret;
+ return kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
}
static int kmx61_runtime_resume(struct device *dev)
@@ -1481,7 +1485,7 @@ static const struct dev_pm_ops kmx61_pm_ops = {
};
static const struct i2c_device_id kmx61_id[] = {
- { "kmx611021" },
+ { .name = "kmx611021" },
{ }
};
diff --git a/drivers/iio/imu/smi240.c b/drivers/iio/imu/smi240.c
index d159ee59acdd..f419296bba88 100644
--- a/drivers/iio/imu/smi240.c
+++ b/drivers/iio/imu/smi240.c
@@ -593,7 +593,7 @@ static int smi240_probe(struct spi_device *spi)
}
static const struct spi_device_id smi240_spi_id[] = {
- { "smi240" },
+ { .name = "smi240" },
{ }
};
MODULE_DEVICE_TABLE(spi, smi240_spi_id);
diff --git a/drivers/iio/imu/smi330/smi330_i2c.c b/drivers/iio/imu/smi330/smi330_i2c.c
index e5f1825beb71..eb9413e22e14 100644
--- a/drivers/iio/imu/smi330/smi330_i2c.c
+++ b/drivers/iio/imu/smi330/smi330_i2c.c
@@ -3,7 +3,6 @@
* Copyright (c) 2025 Robert Bosch GmbH.
*/
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
diff --git a/drivers/iio/imu/smi330/smi330_spi.c b/drivers/iio/imu/smi330/smi330_spi.c
index a6044e02b451..78c2bfb15cce 100644
--- a/drivers/iio/imu/smi330/smi330_spi.c
+++ b/drivers/iio/imu/smi330/smi330_spi.c
@@ -2,7 +2,6 @@
/*
* Copyright (c) 2025 Robert Bosch GmbH.
*/
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile
index 57cbcd67d64f..19a488254de3 100644
--- a/drivers/iio/imu/st_lsm6dsx/Makefile
+++ b/drivers/iio/imu/st_lsm6dsx/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \
- st_lsm6dsx_shub.o
+ st_lsm6dsx_shub.o st_lsm6dsx_fusion.o
obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o
obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index 07b1773c87bd..767aadfe7061 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -294,6 +294,7 @@ enum st_lsm6dsx_sensor_id {
ST_LSM6DSX_ID_EXT0,
ST_LSM6DSX_ID_EXT1,
ST_LSM6DSX_ID_EXT2,
+ ST_LSM6DSX_ID_FUSION,
ST_LSM6DSX_ID_MAX
};
@@ -301,6 +302,17 @@ enum st_lsm6dsx_ext_sensor_id {
ST_LSM6DSX_ID_MAGN,
};
+struct st_lsm6dsx_fusion_settings {
+ const struct iio_chan_spec *chan;
+ int chan_len;
+ struct st_lsm6dsx_reg odr_reg;
+ int odr_hz[ST_LSM6DSX_ODR_LIST_SIZE];
+ int odr_len;
+ struct st_lsm6dsx_reg fifo_enable;
+ struct st_lsm6dsx_reg page_mux;
+ struct st_lsm6dsx_reg enable;
+};
+
/**
* struct st_lsm6dsx_ext_dev_settings - i2c controller slave settings
* @i2c_addr: I2c slave address list.
@@ -388,6 +400,7 @@ struct st_lsm6dsx_settings {
struct st_lsm6dsx_hw_ts_settings ts_settings;
struct st_lsm6dsx_shub_settings shub_settings;
struct st_lsm6dsx_event_settings event_settings;
+ struct st_lsm6dsx_fusion_settings fusion_settings;
};
enum st_lsm6dsx_fifo_mode {
@@ -510,6 +523,9 @@ 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_fusion_probe(struct st_lsm6dsx_hw *hw, const char *name);
+int st_lsm6dsx_fusion_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable);
+int st_lsm6dsx_fusion_set_odr(struct st_lsm6dsx_sensor *sensor, bool enable);
int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable);
static inline int
@@ -564,12 +580,14 @@ st_lsm6dsx_get_mount_matrix(const struct iio_dev *iio_dev,
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)
+ switch (sensor->id) {
+ case ST_LSM6DSX_ID_EXT0 ... ST_LSM6DSX_ID_EXT2:
return st_lsm6dsx_shub_set_enable(sensor, enable);
-
- return st_lsm6dsx_sensor_set_enable(sensor, enable);
+ case ST_LSM6DSX_ID_FUSION:
+ return st_lsm6dsx_fusion_set_enable(sensor, enable);
+ default:
+ return st_lsm6dsx_sensor_set_enable(sensor, enable);
+ }
}
static const
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
index 55d877745575..777d479f10c0 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -88,6 +88,7 @@ enum st_lsm6dsx_fifo_tag {
ST_LSM6DSX_EXT0_TAG = 0x0f,
ST_LSM6DSX_EXT1_TAG = 0x10,
ST_LSM6DSX_EXT2_TAG = 0x11,
+ ST_LSM6DSX_ROT_TAG = 0x13,
};
static const
@@ -225,6 +226,13 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor,
const struct st_lsm6dsx_reg *batch_reg;
u8 data;
+ /* Only internal sensors have a FIFO ODR configuration register. */
+ if (sensor->id >= ARRAY_SIZE(hw->settings->batch)) {
+ if (sensor->id == ST_LSM6DSX_ID_FUSION)
+ return st_lsm6dsx_fusion_set_odr(sensor, enable);
+ return 0;
+ }
+
batch_reg = &hw->settings->batch[sensor->id];
if (batch_reg->addr) {
int val;
@@ -361,8 +369,6 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr,
return 0;
}
-#define ST_LSM6DSX_IIO_BUFF_SIZE (ALIGN(ST_LSM6DSX_SAMPLE_SIZE, \
- sizeof(s64)) + sizeof(s64))
/**
* st_lsm6dsx_read_fifo() - hw FIFO read routine
* @hw: Pointer to instance of struct st_lsm6dsx_hw.
@@ -533,16 +539,23 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
}
#define ST_LSM6DSX_INVALID_SAMPLE 0x7ffd
-static int
-st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag,
- u8 *data, s64 ts)
+static bool st_lsm6dsx_check_data(u8 tag, __le16 *data)
+{
+ if ((tag == ST_LSM6DSX_GYRO_TAG || tag == ST_LSM6DSX_ACC_TAG) &&
+ (s16)le16_to_cpup(data) >= ST_LSM6DSX_INVALID_SAMPLE)
+ return false;
+
+ return true;
+}
+
+static int st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag,
+ __le16 *data, s64 ts)
{
- s16 val = le16_to_cpu(*(__le16 *)data);
struct st_lsm6dsx_sensor *sensor;
struct iio_dev *iio_dev;
/* invalid sample during bootstrap phase */
- if (val >= ST_LSM6DSX_INVALID_SAMPLE)
+ if (!st_lsm6dsx_check_data(tag, data))
return -EINVAL;
/*
@@ -576,6 +589,9 @@ st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag,
case ST_LSM6DSX_EXT2_TAG:
iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2];
break;
+ case ST_LSM6DSX_ROT_TAG:
+ iio_dev = hw->iio_devs[ST_LSM6DSX_ID_FUSION];
+ break;
default:
return -EINVAL;
}
@@ -605,7 +621,13 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
* must be passed a buffer that is aligned to 8 bytes so
* as to allow insertion of a naturally aligned timestamp.
*/
- u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE] __aligned(8);
+ struct {
+ union {
+ __le16 data[3];
+ __le32 fifo_ts;
+ };
+ aligned_s64 timestamp;
+ } iio_buff = { };
u8 tag;
bool reset_ts = false;
int i, err, read_len;
@@ -644,7 +666,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
for (i = 0; i < pattern_len;
i += ST_LSM6DSX_TAGGED_SAMPLE_SIZE) {
- memcpy(iio_buff, &hw->buff[i + ST_LSM6DSX_TAG_SIZE],
+ memcpy(&iio_buff, &hw->buff[i + ST_LSM6DSX_TAG_SIZE],
ST_LSM6DSX_SAMPLE_SIZE);
tag = hw->buff[i] >> 3;
@@ -655,7 +677,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
* B0 = ts[7:0], B1 = ts[15:8], B2 = ts[23:16],
* B3 = ts[31:24]
*/
- ts = le32_to_cpu(*((__le32 *)iio_buff));
+ ts = le32_to_cpu(iio_buff.fifo_ts);
/*
* check if hw timestamp engine is going to
* reset (the sensor generates an interrupt
@@ -666,7 +688,8 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
reset_ts = true;
ts *= hw->ts_gain;
} else {
- st_lsm6dsx_push_tagged_data(hw, tag, iio_buff,
+ st_lsm6dsx_push_tagged_data(hw, tag,
+ iio_buff.data,
ts);
}
}
@@ -858,12 +881,21 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
int i, ret;
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ const struct iio_dev_attr **attrs;
+
if (!hw->iio_devs[i])
continue;
+ /*
+ * For the accelerometer, allow setting FIFO sampling frequency
+ * values different from the sensor sampling frequency, which
+ * may be needed to keep FIFO data rate low while sampling
+ * acceleration data at high rates for accurate event detection.
+ */
+ attrs = i == ST_LSM6DSX_ID_ACC ? st_lsm6dsx_buffer_attrs : NULL;
ret = devm_iio_kfifo_buffer_setup_ext(hw->dev, hw->iio_devs[i],
&st_lsm6dsx_buffer_ops,
- st_lsm6dsx_buffer_attrs);
+ attrs);
if (ret)
return ret;
}
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index 450cb5b47346..360f1365f892 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -94,6 +94,26 @@
#define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f
+/* Raw values from the IMU are 16-bit half-precision floating-point numbers. */
+#define ST_LSM6DSX_CHANNEL_ROT \
+{ \
+ .type = IIO_ROT, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_QUATERNION_AXIS, \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = 0, \
+ .scan_type = { \
+ .format = IIO_SCAN_FORMAT_FLOAT, \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_LE, \
+ .repeat = 3, \
+ }, \
+ .ext_info = st_lsm6dsx_ext_info, \
+}
+
static const struct iio_event_spec st_lsm6dsx_ev_motion[] = {
{
.type = IIO_EV_TYPE_THRESH,
@@ -153,6 +173,11 @@ static const struct iio_chan_spec st_lsm6ds0_gyro_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(3),
};
+static const struct iio_chan_spec st_lsm6dsx_fusion_channels[] = {
+ ST_LSM6DSX_CHANNEL_ROT,
+ IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
{
.reset = {
@@ -1492,6 +1517,33 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
},
+ .fusion_settings = {
+ .chan = st_lsm6dsx_fusion_channels,
+ .chan_len = ARRAY_SIZE(st_lsm6dsx_fusion_channels),
+ .odr_reg = {
+ .addr = 0x5e,
+ .mask = GENMASK(5, 3),
+ },
+ .odr_hz[0] = 15,
+ .odr_hz[1] = 30,
+ .odr_hz[2] = 60,
+ .odr_hz[3] = 120,
+ .odr_hz[4] = 240,
+ .odr_hz[5] = 480,
+ .odr_len = 6,
+ .fifo_enable = {
+ .addr = 0x44,
+ .mask = BIT(1),
+ },
+ .page_mux = {
+ .addr = 0x01,
+ .mask = BIT(7),
+ },
+ .enable = {
+ .addr = 0x04,
+ .mask = BIT(1),
+ },
+ },
},
{
.reset = {
@@ -1660,6 +1712,26 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
return -ENODEV;
}
+ hw->settings = &st_lsm6dsx_sensor_settings[i];
+
+ if (hw->settings->shub_settings.page_mux.addr) {
+ /*
+ * If the IMU has the shub page selected on init, for example
+ * after a CPU watchdog reset while the page is selected, the
+ * regular register space is shadowed. While the regular
+ * register space is shadowed, the registers needed for
+ * initializing the IMU are not available.
+ *
+ * Unconditionally clear the shub page selection to ensure
+ * normal register access.
+ */
+ err = st_lsm6dsx_set_page(hw, false);
+ if (err < 0) {
+ dev_err(hw->dev, "failed to clear shub page\n");
+ return err;
+ }
+ }
+
err = regmap_read(hw->regmap, ST_LSM6DSX_REG_WHOAMI_ADDR, &data);
if (err < 0) {
dev_err(hw->dev, "failed to read whoami register\n");
@@ -1672,7 +1744,6 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
}
*name = st_lsm6dsx_sensor_settings[i].id[j].name;
- hw->settings = &st_lsm6dsx_sensor_settings[i];
return 0;
}
@@ -2781,11 +2852,8 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
st_lsm6dsx_handler_thread,
irq_type | IRQF_ONESHOT,
"lsm6dsx", hw);
- if (err) {
- dev_err(hw->dev, "failed to request trigger irq %d\n",
- hw->irq);
+ if (err)
return err;
- }
return 0;
}
@@ -2899,6 +2967,12 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
return err;
}
+ if (hw->settings->fusion_settings.chan) {
+ err = st_lsm6dsx_fusion_probe(hw, name);
+ if (err)
+ return err;
+ }
+
if (hw->irq > 0) {
err = st_lsm6dsx_irq_setup(hw);
if (err < 0)
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c
new file mode 100644
index 000000000000..5321033daebc
--- /dev/null
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * STMicroelectronics st_lsm6dsx IMU sensor fusion
+ *
+ * Copyright 2026 BayLibre, SAS
+ */
+
+#include <linux/cleanup.h>
+#include <linux/errno.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/sprintf.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include "st_lsm6dsx.h"
+
+static int
+st_lsm6dsx_fusion_get_odr_val(const struct st_lsm6dsx_fusion_settings *settings,
+ u32 odr_mHz, u8 *val)
+{
+ int odr_hz = odr_mHz / MILLI;
+ int i;
+
+ for (i = 0; i < settings->odr_len; i++) {
+ if (settings->odr_hz[i] == odr_hz)
+ break;
+ }
+ if (i == settings->odr_len)
+ return -EINVAL;
+
+ *val = i;
+ return 0;
+}
+
+/**
+ * st_lsm6dsx_fusion_page_enable - Enable access to sensor fusion configuration
+ * registers.
+ * @hw: Sensor hardware instance.
+ *
+ * Return: 0 on success, negative value on error.
+ */
+static int st_lsm6dsx_fusion_page_enable(struct st_lsm6dsx_hw *hw)
+{
+ const struct st_lsm6dsx_reg *mux;
+
+ mux = &hw->settings->fusion_settings.page_mux;
+
+ return regmap_set_bits(hw->regmap, mux->addr, mux->mask);
+}
+
+/**
+ * st_lsm6dsx_fusion_page_disable - Disable access to sensor fusion
+ * configuration registers.
+ * @hw: Sensor hardware instance.
+ *
+ * Return: 0 on success, negative value on error.
+ */
+static int st_lsm6dsx_fusion_page_disable(struct st_lsm6dsx_hw *hw)
+{
+ const struct st_lsm6dsx_reg *mux;
+
+ mux = &hw->settings->fusion_settings.page_mux;
+
+ return regmap_clear_bits(hw->regmap, mux->addr, mux->mask);
+}
+
+static int st_lsm6dsx_fusion_set_odr_locked(struct st_lsm6dsx_sensor *sensor,
+ bool enable)
+{
+ const struct st_lsm6dsx_fusion_settings *settings;
+ struct st_lsm6dsx_hw *hw = sensor->hw;
+ int err;
+
+ settings = &hw->settings->fusion_settings;
+ if (enable) {
+ const struct st_lsm6dsx_reg *reg = &settings->odr_reg;
+ u8 odr_val;
+ u8 data;
+
+ st_lsm6dsx_fusion_get_odr_val(settings, sensor->hwfifo_odr_mHz,
+ &odr_val);
+ data = ST_LSM6DSX_SHIFT_VAL(odr_val, reg->mask);
+ err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
+ data);
+ if (err)
+ return err;
+ }
+
+ return regmap_assign_bits(hw->regmap, settings->fifo_enable.addr,
+ settings->fifo_enable.mask, enable);
+}
+
+int st_lsm6dsx_fusion_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable)
+{
+ struct st_lsm6dsx_hw *hw = sensor->hw;
+ const struct st_lsm6dsx_reg *en_reg;
+ int err;
+
+ guard(mutex)(&hw->page_lock);
+
+ en_reg = &hw->settings->fusion_settings.enable;
+ err = st_lsm6dsx_fusion_page_enable(hw);
+ if (err)
+ return err;
+
+ err = regmap_assign_bits(hw->regmap, en_reg->addr, en_reg->mask, enable);
+ if (err) {
+ st_lsm6dsx_fusion_page_disable(hw);
+ return err;
+ }
+
+ if (enable)
+ hw->enable_mask |= BIT(ST_LSM6DSX_ID_FUSION);
+ else
+ hw->enable_mask &= ~BIT(ST_LSM6DSX_ID_FUSION);
+
+ return st_lsm6dsx_fusion_page_disable(hw);
+}
+
+int st_lsm6dsx_fusion_set_odr(struct st_lsm6dsx_sensor *sensor, bool enable)
+{
+ struct st_lsm6dsx_hw *hw = sensor->hw;
+ int err;
+
+ guard(mutex)(&hw->page_lock);
+
+ err = st_lsm6dsx_fusion_page_enable(hw);
+ if (err)
+ return err;
+
+ err = st_lsm6dsx_fusion_set_odr_locked(sensor, enable);
+ if (err) {
+ st_lsm6dsx_fusion_page_disable(hw);
+ return err;
+ }
+
+ return st_lsm6dsx_fusion_page_disable(hw);
+}
+
+static int st_lsm6dsx_fusion_read_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *ch,
+ int *val, int *val2, long mask)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = sensor->hwfifo_odr_mHz / MILLI;
+ *val2 = (sensor->hwfifo_odr_mHz % MILLI) * (MICRO / MILLI);
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int st_lsm6dsx_fusion_write_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+ const struct st_lsm6dsx_fusion_settings *settings;
+ int err;
+
+ settings = &sensor->hw->settings->fusion_settings;
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ u32 odr_mHz = val * MILLI + val2 * (MILLI / MICRO);
+ u8 odr_val;
+
+ /* check that the requested frequency is supported */
+ err = st_lsm6dsx_fusion_get_odr_val(settings, odr_mHz, &odr_val);
+ if (err)
+ return err;
+
+ sensor->hwfifo_odr_mHz = odr_mHz;
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int st_lsm6dsx_fusion_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type,
+ int *length, long mask)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(indio_dev);
+ const struct st_lsm6dsx_fusion_settings *settings;
+
+ settings = &sensor->hw->settings->fusion_settings;
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = settings->odr_hz;
+ *type = IIO_VAL_INT;
+ *length = settings->odr_len;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info st_lsm6dsx_fusion_info = {
+ .read_raw = st_lsm6dsx_fusion_read_raw,
+ .read_avail = st_lsm6dsx_fusion_read_avail,
+ .write_raw = st_lsm6dsx_fusion_write_raw,
+ .hwfifo_set_watermark = st_lsm6dsx_set_watermark,
+};
+
+int st_lsm6dsx_fusion_probe(struct st_lsm6dsx_hw *hw, const char *name)
+{
+ const struct st_lsm6dsx_fusion_settings *settings;
+ struct st_lsm6dsx_sensor *sensor;
+ struct iio_dev *iio_dev;
+ int ret;
+
+ iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor));
+ if (!iio_dev)
+ return -ENOMEM;
+
+ settings = &hw->settings->fusion_settings;
+ sensor = iio_priv(iio_dev);
+ sensor->id = ST_LSM6DSX_ID_FUSION;
+ sensor->hw = hw;
+ sensor->hwfifo_odr_mHz = settings->odr_hz[0] * MILLI;
+ sensor->watermark = 1;
+ iio_dev->modes = INDIO_DIRECT_MODE;
+ iio_dev->info = &st_lsm6dsx_fusion_info;
+ iio_dev->channels = settings->chan;
+ iio_dev->num_channels = settings->chan_len;
+ ret = snprintf(sensor->name, sizeof(sensor->name), "%s_fusion", name);
+ if (ret >= sizeof(sensor->name))
+ return -E2BIG;
+ iio_dev->name = sensor->name;
+
+ /*
+ * Put the IIO device pointer in the iio_devs array so that the caller
+ * can set up a buffer and register this IIO device.
+ */
+ hw->iio_devs[ST_LSM6DSX_ID_FUSION] = iio_dev;
+
+ return 0;
+}
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
index 7c933218036b..edec898cb11f 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
@@ -144,35 +144,36 @@ MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
static const struct acpi_device_id st_lsm6dsx_i2c_acpi_match[] = {
{ "SMO8B30", ST_LSM6DS3TRC_ID, },
+ { "SMOCF00", ST_LSM6DSO_ID, },
{ }
};
MODULE_DEVICE_TABLE(acpi, st_lsm6dsx_i2c_acpi_match);
static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
- { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID },
- { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID },
- { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID },
- { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
- { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
- { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
- { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID },
- { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID },
- { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID },
- { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID },
- { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID },
- { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID },
- { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID },
- { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID },
- { ST_LSM6DST_DEV_NAME, ST_LSM6DST_ID },
- { 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 },
- { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID },
- { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID },
+ { .name = ST_LSM6DS3_DEV_NAME, .driver_data = ST_LSM6DS3_ID },
+ { .name = ST_LSM6DS3H_DEV_NAME, .driver_data = ST_LSM6DS3H_ID },
+ { .name = ST_LSM6DSL_DEV_NAME, .driver_data = ST_LSM6DSL_ID },
+ { .name = ST_LSM6DSM_DEV_NAME, .driver_data = ST_LSM6DSM_ID },
+ { .name = ST_ISM330DLC_DEV_NAME, .driver_data = ST_ISM330DLC_ID },
+ { .name = ST_LSM6DSO_DEV_NAME, .driver_data = ST_LSM6DSO_ID },
+ { .name = ST_ASM330LHH_DEV_NAME, .driver_data = ST_ASM330LHH_ID },
+ { .name = ST_LSM6DSOX_DEV_NAME, .driver_data = ST_LSM6DSOX_ID },
+ { .name = ST_LSM6DSR_DEV_NAME, .driver_data = ST_LSM6DSR_ID },
+ { .name = ST_LSM6DS3TRC_DEV_NAME, .driver_data = ST_LSM6DS3TRC_ID },
+ { .name = ST_ISM330DHCX_DEV_NAME, .driver_data = ST_ISM330DHCX_ID },
+ { .name = ST_LSM9DS1_DEV_NAME, .driver_data = ST_LSM9DS1_ID },
+ { .name = ST_LSM6DS0_DEV_NAME, .driver_data = ST_LSM6DS0_ID },
+ { .name = ST_LSM6DSRX_DEV_NAME, .driver_data = ST_LSM6DSRX_ID },
+ { .name = ST_LSM6DST_DEV_NAME, .driver_data = ST_LSM6DST_ID },
+ { .name = ST_LSM6DSOP_DEV_NAME, .driver_data = ST_LSM6DSOP_ID },
+ { .name = ST_ASM330LHHX_DEV_NAME, .driver_data = ST_ASM330LHHX_ID },
+ { .name = ST_LSM6DSTX_DEV_NAME, .driver_data = ST_LSM6DSTX_ID },
+ { .name = ST_LSM6DSV_DEV_NAME, .driver_data = ST_LSM6DSV_ID },
+ { .name = ST_LSM6DSV16X_DEV_NAME, .driver_data = ST_LSM6DSV16X_ID },
+ { .name = ST_LSM6DSO16IS_DEV_NAME, .driver_data = ST_LSM6DSO16IS_ID },
+ { .name = ST_ISM330IS_DEV_NAME, .driver_data = ST_ISM330IS_ID },
+ { .name = ST_ASM330LHB_DEV_NAME, .driver_data = ST_ASM330LHB_ID },
+ { .name = ST_ASM330LHHXG1_DEV_NAME, .driver_data = ST_ASM330LHHXG1_ID },
{ }
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c
index cb5c5d7e1f3d..cd59edcf6d71 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c
@@ -6,7 +6,6 @@
*/
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/i3c/device.h>
#include <linux/slab.h>
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
index 3389b15df0bc..ed47d5a6f11c 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
@@ -138,30 +138,30 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
- { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID },
- { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID },
- { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID },
- { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
- { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
- { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
- { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID },
- { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID },
- { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID },
- { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID },
- { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID },
- { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID },
- { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID },
- { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID },
- { ST_LSM6DST_DEV_NAME, ST_LSM6DST_ID },
- { 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 },
- { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID },
- { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID },
+ { .name = ST_LSM6DS3_DEV_NAME, .driver_data = ST_LSM6DS3_ID },
+ { .name = ST_LSM6DS3H_DEV_NAME, .driver_data = ST_LSM6DS3H_ID },
+ { .name = ST_LSM6DSL_DEV_NAME, .driver_data = ST_LSM6DSL_ID },
+ { .name = ST_LSM6DSM_DEV_NAME, .driver_data = ST_LSM6DSM_ID },
+ { .name = ST_ISM330DLC_DEV_NAME, .driver_data = ST_ISM330DLC_ID },
+ { .name = ST_LSM6DSO_DEV_NAME, .driver_data = ST_LSM6DSO_ID },
+ { .name = ST_ASM330LHH_DEV_NAME, .driver_data = ST_ASM330LHH_ID },
+ { .name = ST_LSM6DSOX_DEV_NAME, .driver_data = ST_LSM6DSOX_ID },
+ { .name = ST_LSM6DSR_DEV_NAME, .driver_data = ST_LSM6DSR_ID },
+ { .name = ST_LSM6DS3TRC_DEV_NAME, .driver_data = ST_LSM6DS3TRC_ID },
+ { .name = ST_ISM330DHCX_DEV_NAME, .driver_data = ST_ISM330DHCX_ID },
+ { .name = ST_LSM9DS1_DEV_NAME, .driver_data = ST_LSM9DS1_ID },
+ { .name = ST_LSM6DS0_DEV_NAME, .driver_data = ST_LSM6DS0_ID },
+ { .name = ST_LSM6DSRX_DEV_NAME, .driver_data = ST_LSM6DSRX_ID },
+ { .name = ST_LSM6DST_DEV_NAME, .driver_data = ST_LSM6DST_ID },
+ { .name = ST_LSM6DSOP_DEV_NAME, .driver_data = ST_LSM6DSOP_ID },
+ { .name = ST_ASM330LHHX_DEV_NAME, .driver_data = ST_ASM330LHHX_ID },
+ { .name = ST_LSM6DSTX_DEV_NAME, .driver_data = ST_LSM6DSTX_ID },
+ { .name = ST_LSM6DSV_DEV_NAME, .driver_data = ST_LSM6DSV_ID },
+ { .name = ST_LSM6DSV16X_DEV_NAME, .driver_data = ST_LSM6DSV16X_ID },
+ { .name = ST_LSM6DSO16IS_DEV_NAME, .driver_data = ST_LSM6DSO16IS_ID },
+ { .name = ST_ISM330IS_DEV_NAME, .driver_data = ST_ISM330IS_ID },
+ { .name = ST_ASM330LHB_DEV_NAME, .driver_data = ST_ASM330LHB_ID },
+ { .name = ST_ASM330LHHXG1_DEV_NAME, .driver_data = ST_ASM330LHHXG1_ID },
{ }
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
index 4232a9d800fc..6581d14e2bcf 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
@@ -12,7 +12,6 @@
#include <linux/gfp_types.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/iio/common/st_sensors_i2c.h>
@@ -33,8 +32,8 @@ static const struct of_device_id st_lsm9ds0_of_match[] = {
MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match);
static const struct i2c_device_id st_lsm9ds0_id_table[] = {
- { LSM303D_IMU_DEV_NAME },
- { LSM9DS0_IMU_DEV_NAME },
+ { .name = LSM303D_IMU_DEV_NAME },
+ { .name = LSM9DS0_IMU_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table);
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
index acea8a0757d7..e67f09e1f093 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
@@ -11,7 +11,6 @@
#include <linux/err.h>
#include <linux/gfp_types.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -33,8 +32,8 @@ static const struct of_device_id st_lsm9ds0_of_match[] = {
MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match);
static const struct spi_device_id st_lsm9ds0_id_table[] = {
- { LSM303D_IMU_DEV_NAME },
- { LSM9DS0_IMU_DEV_NAME },
+ { .name = LSM303D_IMU_DEV_NAME },
+ { .name = LSM9DS0_IMU_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(spi, st_lsm9ds0_id_table);
diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
index 447b694d6d5f..f7a4be8ec320 100644
--- a/drivers/iio/industrialio-backend.c
+++ b/drivers/iio/industrialio-backend.c
@@ -56,6 +56,7 @@ struct iio_backend {
void *priv;
const char *name;
unsigned int cached_reg_addr;
+ u32 caps;
/*
* This index is relative to the frontend. Meaning that for
* frontends with multiple backends, this will be the index of this
@@ -155,7 +156,7 @@ static ssize_t iio_backend_debugfs_write_reg(struct file *file,
ssize_t rc;
int ret;
- if (count >= sizeof(buf))
+ if (*ppos != 0 || count >= sizeof(buf))
return -ENOSPC;
rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf, count);
@@ -648,7 +649,7 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_get, "IIO_BACKEND");
* @len: Buffer length
*
* This helper is intended to be used by backends that extend an IIO channel
- * (trough iio_backend_extend_chan_spec()) with extended info. In that case,
+ * (through iio_backend_extend_chan_spec()) with extended info. In that case,
* backends are not supposed to give their own callbacks (as they would not have
* a way to get the backend from indio_dev). This is the setter.
*
@@ -774,6 +775,20 @@ int iio_backend_extend_chan_spec(struct iio_backend *back,
}
EXPORT_SYMBOL_NS_GPL(iio_backend_extend_chan_spec, "IIO_BACKEND");
+/**
+ * iio_backend_has_caps - Check if backend has specific capabilities
+ * @back: Backend device
+ * @caps: Capabilities to check
+ *
+ * RETURNS:
+ * True if backend has all the requested capabilities, false otherwise.
+ */
+bool iio_backend_has_caps(struct iio_backend *back, u32 caps)
+{
+ return (back->caps & caps) == caps;
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_has_caps, "IIO_BACKEND");
+
static void iio_backend_release(void *arg)
{
struct iio_backend *back = arg;
@@ -836,7 +851,7 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_filter_type_set, "IIO_BACKEND");
* @back: Backend device
* @timeout_us: Timeout value in us.
*
- * When activated, it initates a proccess that aligns the sample's most
+ * When activated, it initiates a process that aligns the sample's most
* significant bit (MSB) based solely on the captured data, without
* considering any other external signals.
*
@@ -949,25 +964,15 @@ int iio_backend_data_transfer_addr(struct iio_backend *back, u32 address)
}
EXPORT_SYMBOL_NS_GPL(iio_backend_data_transfer_addr, "IIO_BACKEND");
-static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, const char *name,
- struct fwnode_handle *fwnode)
+static struct iio_backend *__devm_iio_backend_fwnode_get_by_index(struct device *dev,
+ struct fwnode_handle *fwnode,
+ unsigned int index)
{
- struct fwnode_handle *fwnode_back;
struct iio_backend *back;
- unsigned int index;
int ret;
- if (name) {
- ret = device_property_match_string(dev, "io-backend-names",
- name);
- if (ret < 0)
- return ERR_PTR(ret);
- index = ret;
- } else {
- index = 0;
- }
-
- fwnode_back = fwnode_find_reference(fwnode, "io-backends", index);
+ struct fwnode_handle *fwnode_back __free(fwnode_handle) =
+ fwnode_find_reference(fwnode, "io-backends", index);
if (IS_ERR(fwnode_back))
return dev_err_cast_probe(dev, fwnode_back,
"Cannot get Firmware reference\n");
@@ -977,27 +982,42 @@ static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, con
if (!device_match_fwnode(back->dev, fwnode_back))
continue;
- fwnode_handle_put(fwnode_back);
ret = __devm_iio_backend_get(dev, back);
if (ret)
return ERR_PTR(ret);
- if (name)
- back->idx = index;
+ back->idx = index;
return back;
}
- fwnode_handle_put(fwnode_back);
return ERR_PTR(-EPROBE_DEFER);
}
+static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, const char *name,
+ struct fwnode_handle *fwnode)
+{
+ unsigned int index;
+ int ret;
+
+ if (name) {
+ ret = device_property_match_string(dev, "io-backend-names", name);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ index = ret;
+ } else {
+ index = 0;
+ }
+
+ return __devm_iio_backend_fwnode_get_by_index(dev, fwnode, index);
+}
+
/**
* devm_iio_backend_get - Device managed backend device get
* @dev: Consumer device for the backend
* @name: Backend name
*
- * Get's the backend associated with @dev.
+ * Gets the backend associated with @dev.
*
* RETURNS:
* A backend pointer, negative error pointer otherwise.
@@ -1009,12 +1029,28 @@ struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name)
EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, "IIO_BACKEND");
/**
+ * devm_iio_backend_get_by_index - Device managed backend device get by index
+ * @dev: Consumer device for the backend
+ * @index: Index of the backend in the io-backends property
+ *
+ * Gets the backend at @index associated with @dev.
+ *
+ * RETURNS:
+ * A backend pointer, negative error pointer otherwise.
+ */
+struct iio_backend *devm_iio_backend_get_by_index(struct device *dev, unsigned int index)
+{
+ return __devm_iio_backend_fwnode_get_by_index(dev, dev_fwnode(dev), index);
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get_by_index, "IIO_BACKEND");
+
+/**
* devm_iio_backend_fwnode_get - Device managed backend firmware node get
* @dev: Consumer device for the backend
* @name: Backend name
* @fwnode: Firmware node of the backend consumer
*
- * Get's the backend associated with a firmware node.
+ * Gets the backend associated with a firmware node.
*
* RETURNS:
* A backend pointer, negative error pointer otherwise.
@@ -1114,6 +1150,7 @@ int devm_iio_backend_register(struct device *dev,
back->ops = info->ops;
back->name = info->name;
+ back->caps = info->caps;
back->owner = dev->driver->owner;
back->dev = dev;
back->priv = priv;
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 46f36a6ed271..2c9ec93dff47 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -47,9 +47,6 @@ struct iio_dmabuf_priv {
u64 context;
- /* Spinlock used for locking the dma_fence */
- spinlock_t lock;
-
struct dma_buf_attachment *attach;
struct sg_table *sgt;
enum dma_data_direction dir;
@@ -57,7 +54,12 @@ struct iio_dmabuf_priv {
};
struct iio_dma_fence {
+ /*
+ * Must remain the first member so the default release callback can pass
+ * the fence directly to dma_fence_free().
+ */
struct dma_fence base;
+ spinlock_t lock; /* protects base */
struct iio_dmabuf_priv *priv;
struct work_struct work;
};
@@ -750,7 +752,7 @@ static int iio_storage_bytes_for_si(struct iio_dev *indio_dev,
bytes = scan_type->storagebits / 8;
if (scan_type->repeat > 1)
- bytes *= scan_type->repeat;
+ bytes *= roundup_pow_of_two(scan_type->repeat);
return bytes;
}
@@ -764,7 +766,9 @@ static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
}
static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
- const unsigned long *mask, bool timestamp)
+ const unsigned long *mask, bool timestamp,
+ unsigned int *scan_bytes,
+ unsigned int *timestamp_offset)
{
unsigned int bytes = 0;
int length, i, largest = 0;
@@ -786,12 +790,17 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
return length;
bytes = ALIGN(bytes, length);
+
+ if (timestamp_offset)
+ *timestamp_offset = bytes;
+
bytes += length;
largest = max(largest, length);
}
- bytes = ALIGN(bytes, largest);
- return bytes;
+ *scan_bytes = ALIGN(bytes, largest);
+
+ return 0;
}
static void iio_buffer_activate(struct iio_dev *indio_dev,
@@ -836,18 +845,23 @@ static int iio_buffer_disable(struct iio_buffer *buffer,
return buffer->access->disable(buffer, indio_dev);
}
-static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
- struct iio_buffer *buffer)
+static int iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer)
{
unsigned int bytes;
+ int ret;
if (!buffer->access->set_bytes_per_datum)
- return;
+ return 0;
- bytes = iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
- buffer->scan_timestamp);
+ ret = iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
+ buffer->scan_timestamp, &bytes, NULL);
+ if (ret)
+ return ret;
buffer->access->set_bytes_per_datum(buffer, bytes);
+
+ return 0;
}
static int iio_buffer_request_update(struct iio_dev *indio_dev,
@@ -855,7 +869,10 @@ static int iio_buffer_request_update(struct iio_dev *indio_dev,
{
int ret;
- iio_buffer_update_bytes_per_datum(indio_dev, buffer);
+ ret = iio_buffer_update_bytes_per_datum(indio_dev, buffer);
+ if (ret)
+ return ret;
+
if (buffer->access->request_update) {
ret = buffer->access->request_update(buffer);
if (ret) {
@@ -882,6 +899,7 @@ struct iio_device_config {
unsigned int watermark;
const unsigned long *scan_mask;
unsigned int scan_bytes;
+ unsigned int scan_timestamp_offset;
bool scan_timestamp;
};
@@ -898,6 +916,7 @@ static int iio_verify_update(struct iio_dev *indio_dev,
struct iio_buffer *buffer;
bool scan_timestamp;
unsigned int modes;
+ int ret;
if (insert_buffer &&
bitmap_empty(insert_buffer->scan_mask, masklength)) {
@@ -985,8 +1004,12 @@ static int iio_verify_update(struct iio_dev *indio_dev,
scan_mask = compound_mask;
}
- config->scan_bytes = iio_compute_scan_bytes(indio_dev,
- scan_mask, scan_timestamp);
+ ret = iio_compute_scan_bytes(indio_dev, scan_mask, scan_timestamp,
+ &config->scan_bytes,
+ &config->scan_timestamp_offset);
+ if (ret)
+ return ret;
+
config->scan_mask = scan_mask;
config->scan_timestamp = scan_timestamp;
@@ -1141,6 +1164,7 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
indio_dev->active_scan_mask = config->scan_mask;
ACCESS_PRIVATE(indio_dev, scan_timestamp) = config->scan_timestamp;
indio_dev->scan_bytes = config->scan_bytes;
+ ACCESS_PRIVATE(indio_dev, scan_timestamp_offset) = config->scan_timestamp_offset;
iio_dev_opaque->currentmode = config->mode;
iio_update_demux(indio_dev);
@@ -1597,12 +1621,16 @@ static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep)
wake_up(&buffer->pollq);
- guard(mutex)(&buffer->dmabufs_mutex);
-
- /* Close all attached DMABUFs */
- list_for_each_entry_safe(priv, tmp, &buffer->dmabufs, entry) {
- list_del_init(&priv->entry);
- iio_buffer_dmabuf_put(priv->attach);
+ /*
+ * The mutex must be unlocked before iio_device_put(), which might drop the
+ * last reference and free the buffer.
+ */
+ scoped_guard(mutex, &buffer->dmabufs_mutex) {
+ /* Close all attached DMABUFs */
+ list_for_each_entry_safe(priv, tmp, &buffer->dmabufs, entry) {
+ list_del_init(&priv->entry);
+ iio_buffer_dmabuf_put(priv->attach);
+ }
}
kfree(ib);
@@ -1680,7 +1708,6 @@ static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib,
if (!priv)
return -ENOMEM;
- spin_lock_init(&priv->lock);
priv->context = dma_fence_context_alloc(1);
dmabuf = dma_buf_get(fd);
@@ -1805,18 +1832,9 @@ iio_buffer_dma_fence_get_driver_name(struct dma_fence *fence)
return "iio";
}
-static void iio_buffer_dma_fence_release(struct dma_fence *fence)
-{
- struct iio_dma_fence *iio_fence =
- container_of(fence, struct iio_dma_fence, base);
-
- kfree(iio_fence);
-}
-
static const struct dma_fence_ops iio_buffer_dma_fence_ops = {
.get_driver_name = iio_buffer_dma_fence_get_driver_name,
.get_timeline_name = iio_buffer_dma_fence_get_driver_name,
- .release = iio_buffer_dma_fence_release,
};
static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib,
@@ -1870,6 +1888,8 @@ static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib,
goto err_attachment_put;
}
+ spin_lock_init(&fence->lock);
+
fence->priv = priv;
seqno = atomic_add_return(1, &priv->seqno);
@@ -1880,7 +1900,7 @@ static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib,
* the dma_fence.
*/
dma_fence_init(&fence->base, &iio_buffer_dma_fence_ops,
- &priv->lock, priv->context, seqno);
+ &fence->lock, priv->context, seqno);
ret = iio_dma_resv_lock(dmabuf, nonblock);
if (ret)
@@ -1909,6 +1929,7 @@ static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib,
dma_resv_add_fence(dmabuf->resv, &fence->base,
dma_to_ram ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ);
+ dma_fence_put(&fence->base);
dma_resv_unlock(dmabuf->resv);
cookie = dma_fence_begin_signalling();
@@ -2422,7 +2443,7 @@ EXPORT_SYMBOL_GPL(iio_push_to_buffers);
int iio_push_to_buffers_with_ts_unaligned(struct iio_dev *indio_dev,
const void *data,
size_t data_sz,
- int64_t timestamp)
+ s64 timestamp)
{
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 22eefd048ba9..767a7794624a 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -19,6 +19,7 @@
#include <linux/idr.h>
#include <linux/kdev_t.h>
#include <linux/kernel.h>
+#include <linux/math64.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/poll.h>
@@ -26,7 +27,6 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/wait.h>
-#include <linux/wordpart.h>
#include <linux/iio/buffer.h>
#include <linux/iio/buffer_impl.h>
@@ -98,6 +98,8 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_CHROMATICITY] = "chromaticity",
[IIO_ATTENTION] = "attention",
[IIO_ALTCURRENT] = "altcurrent",
+ [IIO_COVERAGE] = "coverage",
+ [IIO_VOLUMEFLOW] = "volumeflow",
};
static const char * const iio_modifier_names[] = {
@@ -157,6 +159,7 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_ACTIVE] = "active",
[IIO_MOD_REACTIVE] = "reactive",
[IIO_MOD_APPARENT] = "apparent",
+ [IIO_MOD_QUATERNION_AXIS] = "quaternionaxis",
};
/* relies on pairs of these shared then separate */
@@ -418,7 +421,7 @@ static ssize_t iio_debugfs_write_reg(struct file *file,
char buf[80];
int ret;
- if (count >= sizeof(buf))
+ if (*ppos != 0 || count >= sizeof(buf))
return -EINVAL;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf,
@@ -654,6 +657,7 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type,
int size, const int *vals)
{
int tmp0, tmp1;
+ int l = 0;
s64 tmp2;
bool scale_db = false;
@@ -697,7 +701,6 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type,
case IIO_VAL_INT_MULTIPLE:
{
int i;
- int l = 0;
for (i = 0; i < size; ++i)
l += sysfs_emit_at(buf, offset + l, "%d ", vals[i]);
@@ -706,8 +709,26 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type,
case IIO_VAL_CHAR:
return sysfs_emit_at(buf, offset, "%c", (char)vals[0]);
case IIO_VAL_INT_64:
- tmp2 = (s64)((((u64)vals[1]) << 32) | (u32)vals[0]);
- return sysfs_emit_at(buf, offset, "%lld", tmp2);
+ return sysfs_emit_at(buf, offset, "%lld",
+ iio_val_s64_compose(vals[0], vals[1]));
+ case IIO_VAL_DECIMAL64_MILLI:
+ case IIO_VAL_DECIMAL64_MICRO:
+ case IIO_VAL_DECIMAL64_NANO:
+ case IIO_VAL_DECIMAL64_PICO:
+ case IIO_VAL_DECIMAL64_FEMTO:
+ {
+ int scale = type - IIO_VAL_DECIMAL64_BASE;
+ s64 frac;
+
+ tmp2 = div64_s64_rem(iio_val_s64_compose(vals[0], vals[1]),
+ int_pow(10, scale), &frac);
+ if (tmp2 == 0 && frac < 0)
+ l += sysfs_emit_at(buf, offset, "-");
+
+ l += sysfs_emit_at(buf, offset + l, "%lld.%0*lld", tmp2, scale,
+ abs(frac));
+ return l;
+ }
default:
return 0;
}
@@ -977,6 +998,7 @@ static ssize_t iio_write_channel_info(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret, fract_mult = 100000;
+ int type, dec_scale = 0;
int integer, fract = 0;
long long integer64;
bool is_char = false;
@@ -987,9 +1009,11 @@ static ssize_t iio_write_channel_info(struct device *dev,
if (!indio_dev->info->write_raw)
return -EINVAL;
- if (indio_dev->info->write_raw_get_fmt)
- switch (indio_dev->info->write_raw_get_fmt(indio_dev,
- this_attr->c, this_attr->address)) {
+ if (indio_dev->info->write_raw_get_fmt) {
+ type = indio_dev->info->write_raw_get_fmt(indio_dev,
+ this_attr->c,
+ this_attr->address);
+ switch (type) {
case IIO_VAL_INT:
fract_mult = 0;
break;
@@ -1005,12 +1029,20 @@ static ssize_t iio_write_channel_info(struct device *dev,
case IIO_VAL_CHAR:
is_char = true;
break;
+ case IIO_VAL_DECIMAL64_MILLI:
+ case IIO_VAL_DECIMAL64_MICRO:
+ case IIO_VAL_DECIMAL64_NANO:
+ case IIO_VAL_DECIMAL64_PICO:
+ case IIO_VAL_DECIMAL64_FEMTO:
+ dec_scale = type - IIO_VAL_DECIMAL64_BASE;
+ fallthrough;
case IIO_VAL_INT_64:
is_64bit = true;
break;
default:
return -EINVAL;
}
+ }
if (is_char) {
char ch;
@@ -1019,12 +1051,14 @@ static ssize_t iio_write_channel_info(struct device *dev,
return -EINVAL;
integer = ch;
} else if (is_64bit) {
- ret = kstrtoll(buf, 0, &integer64);
+ if (dec_scale)
+ ret = kstrtodec64(buf, dec_scale, &integer64);
+ else
+ ret = kstrtoll(buf, 0, &integer64);
if (ret)
return ret;
- fract = upper_32_bits(integer64);
- integer = lower_32_bits(integer64);
+ iio_val_s64_decompose(integer64, &integer, &fract);
} else {
ret = __iio_str_to_fixpoint(buf, fract_mult, &integer, &fract,
scale_db);
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 4149efcd5539..e6730f52262a 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -207,6 +207,8 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
goto unlock;
}
+ kfifo_reset_out(&ev_int->det_events);
+
iio_device_get(indio_dev);
fd = anon_inode_getfd("iio:event", &iio_event_chrdev_fileops,
@@ -214,10 +216,7 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
if (fd < 0) {
clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
iio_device_put(indio_dev);
- } else {
- kfifo_reset_out(&ev_int->det_events);
}
-
unlock:
mutex_unlock(&iio_dev_opaque->mlock);
return fd;
@@ -256,6 +255,7 @@ static const char * const iio_ev_info_text[] = {
[IIO_EV_INFO_TAP2_MIN_DELAY] = "tap2_min_delay",
[IIO_EV_INFO_RUNNING_PERIOD] = "runningperiod",
[IIO_EV_INFO_RUNNING_COUNT] = "runningcount",
+ [IIO_EV_INFO_SCALE] = "scale",
};
static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr)
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 7f34fe7bad07..17781c12bc85 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -561,10 +561,6 @@ struct iio_trigger *viio_trigger_alloc(struct device *parent,
if (!trig)
return NULL;
- trig->dev.parent = parent;
- trig->dev.type = &iio_trig_type;
- trig->dev.bus = &iio_bus_type;
- device_initialize(&trig->dev);
INIT_WORK(&trig->reenable_work, iio_reenable_work_fn);
mutex_init(&trig->pool_lock);
@@ -592,6 +588,11 @@ struct iio_trigger *viio_trigger_alloc(struct device *parent,
IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
}
+ trig->dev.parent = parent;
+ trig->dev.type = &iio_trig_type;
+ trig->dev.bus = &iio_bus_type;
+ device_initialize(&trig->dev);
+
return trig;
free_descs:
@@ -634,9 +635,9 @@ void iio_trigger_free(struct iio_trigger *trig)
}
EXPORT_SYMBOL(iio_trigger_free);
-static void devm_iio_trigger_release(struct device *dev, void *res)
+static void devm_iio_trigger_release(void *trig)
{
- iio_trigger_free(*(struct iio_trigger **)res);
+ iio_trigger_free(trig);
}
/**
@@ -658,24 +659,20 @@ struct iio_trigger *__devm_iio_trigger_alloc(struct device *parent,
struct module *this_mod,
const char *fmt, ...)
{
- struct iio_trigger **ptr, *trig;
+ struct iio_trigger *trig;
va_list vargs;
-
- ptr = devres_alloc(devm_iio_trigger_release, sizeof(*ptr),
- GFP_KERNEL);
- if (!ptr)
- return NULL;
+ int ret;
/* use raw alloc_dr for kmalloc caller tracing */
va_start(vargs, fmt);
trig = viio_trigger_alloc(parent, this_mod, fmt, vargs);
va_end(vargs);
- if (trig) {
- *ptr = trig;
- devres_add(parent, ptr);
- } else {
- devres_free(ptr);
- }
+ if (!trig)
+ return NULL;
+
+ ret = devm_add_action_or_reset(parent, devm_iio_trigger_release, trig);
+ if (ret)
+ return NULL;
return trig;
}
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 0df0ab3de270..1f22275de55c 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -281,7 +281,7 @@ struct iio_channel *fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode,
return ERR_PTR(-ENODEV);
}
-EXPORT_SYMBOL_GPL(fwnode_iio_channel_get_by_name);
+EXPORT_SYMBOL_NS_GPL(fwnode_iio_channel_get_by_name, "IIO_CONSUMER");
static struct iio_channel *fwnode_iio_channel_get_all(struct device *dev)
{
@@ -345,7 +345,7 @@ static struct iio_channel *iio_channel_get_sys(const char *name,
return ERR_PTR(-ENODEV);
struct iio_channel *channel __free(kfree) =
- kzalloc(sizeof(*channel), GFP_KERNEL);
+ kzalloc_obj(*channel);
if (!channel) {
err = -ENOMEM;
goto error_no_mem;
@@ -386,7 +386,7 @@ struct iio_channel *iio_channel_get(struct device *dev,
return iio_channel_get_sys(name, channel_name);
}
-EXPORT_SYMBOL_GPL(iio_channel_get);
+EXPORT_SYMBOL_NS_GPL(iio_channel_get, "IIO_CONSUMER");
void iio_channel_release(struct iio_channel *channel)
{
@@ -395,7 +395,7 @@ void iio_channel_release(struct iio_channel *channel)
iio_device_put(channel->indio_dev);
kfree(channel);
}
-EXPORT_SYMBOL_GPL(iio_channel_release);
+EXPORT_SYMBOL_NS_GPL(iio_channel_release, "IIO_CONSUMER");
static void devm_iio_channel_free(void *iio_channel)
{
@@ -418,7 +418,7 @@ struct iio_channel *devm_iio_channel_get(struct device *dev,
return channel;
}
-EXPORT_SYMBOL_GPL(devm_iio_channel_get);
+EXPORT_SYMBOL_NS_GPL(devm_iio_channel_get, "IIO_CONSUMER");
struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev,
struct fwnode_handle *fwnode,
@@ -437,7 +437,7 @@ struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev,
return channel;
}
-EXPORT_SYMBOL_GPL(devm_fwnode_iio_channel_get_by_name);
+EXPORT_SYMBOL_NS_GPL(devm_fwnode_iio_channel_get_by_name, "IIO_CONSUMER");
struct iio_channel *iio_channel_get_all(struct device *dev)
{
@@ -506,7 +506,7 @@ error_free_chans:
iio_device_put(chans[i].indio_dev);
return ERR_PTR(ret);
}
-EXPORT_SYMBOL_GPL(iio_channel_get_all);
+EXPORT_SYMBOL_NS_GPL(iio_channel_get_all, "IIO_CONSUMER");
void iio_channel_release_all(struct iio_channel *channels)
{
@@ -518,7 +518,7 @@ void iio_channel_release_all(struct iio_channel *channels)
}
kfree(channels);
}
-EXPORT_SYMBOL_GPL(iio_channel_release_all);
+EXPORT_SYMBOL_NS_GPL(iio_channel_release_all, "IIO_CONSUMER");
static void devm_iio_channel_free_all(void *iio_channels)
{
@@ -541,7 +541,7 @@ struct iio_channel *devm_iio_channel_get_all(struct device *dev)
return channels;
}
-EXPORT_SYMBOL_GPL(devm_iio_channel_get_all);
+EXPORT_SYMBOL_NS_GPL(devm_iio_channel_get_all, "IIO_CONSUMER");
static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
enum iio_chan_info_enum info)
@@ -585,7 +585,7 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val)
return iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_raw);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_raw, "IIO_CONSUMER");
int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
{
@@ -597,7 +597,7 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
return iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_average_raw);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_average_raw, "IIO_CONSUMER");
int iio_multiply_value(int *result, s64 multiplier,
unsigned int type, int val, int val2)
@@ -701,7 +701,7 @@ int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
return iio_convert_raw_to_processed_unlocked(chan, raw, processed,
scale);
}
-EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed);
+EXPORT_SYMBOL_NS_GPL(iio_convert_raw_to_processed, "IIO_CONSUMER");
int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2,
enum iio_chan_info_enum attribute)
@@ -714,13 +714,13 @@ int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2,
return iio_channel_read(chan, val, val2, attribute);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_attribute);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_attribute, "IIO_CONSUMER");
int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2)
{
return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_OFFSET);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_offset);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_offset, "IIO_CONSUMER");
int iio_read_channel_processed_scale(struct iio_channel *chan, int *val,
unsigned int scale)
@@ -738,7 +738,11 @@ int iio_read_channel_processed_scale(struct iio_channel *chan, int *val,
if (ret < 0)
return ret;
- return iio_multiply_value(val, scale, ret, pval, pval2);
+ ret = iio_multiply_value(val, scale, ret, pval, pval2);
+ if (ret < 0)
+ return ret;
+
+ return 0;
} else {
ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
if (ret < 0)
@@ -748,20 +752,20 @@ int iio_read_channel_processed_scale(struct iio_channel *chan, int *val,
scale);
}
}
-EXPORT_SYMBOL_GPL(iio_read_channel_processed_scale);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_processed_scale, "IIO_CONSUMER");
int iio_read_channel_processed(struct iio_channel *chan, int *val)
{
/* This is just a special case with scale factor 1 */
return iio_read_channel_processed_scale(chan, val, 1);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_processed);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_processed, "IIO_CONSUMER");
int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
{
return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_SCALE);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_scale);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_scale, "IIO_CONSUMER");
static int iio_channel_read_avail(struct iio_channel *chan,
const int **vals, int *type, int *length,
@@ -790,7 +794,7 @@ int iio_read_avail_channel_attribute(struct iio_channel *chan,
return iio_channel_read_avail(chan, vals, type, length, attribute);
}
-EXPORT_SYMBOL_GPL(iio_read_avail_channel_attribute);
+EXPORT_SYMBOL_NS_GPL(iio_read_avail_channel_attribute, "IIO_CONSUMER");
int iio_read_avail_channel_raw(struct iio_channel *chan,
const int **vals, int *length)
@@ -807,7 +811,7 @@ int iio_read_avail_channel_raw(struct iio_channel *chan,
return ret;
}
-EXPORT_SYMBOL_GPL(iio_read_avail_channel_raw);
+EXPORT_SYMBOL_NS_GPL(iio_read_avail_channel_raw, "IIO_CONSUMER");
static int iio_channel_read_max(struct iio_channel *chan,
int *val, int *val2, int *type,
@@ -863,7 +867,7 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val)
return iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW);
}
-EXPORT_SYMBOL_GPL(iio_read_max_channel_raw);
+EXPORT_SYMBOL_NS_GPL(iio_read_max_channel_raw, "IIO_CONSUMER");
static int iio_channel_read_min(struct iio_channel *chan,
int *val, int *val2, int *type,
@@ -919,7 +923,7 @@ int iio_read_min_channel_raw(struct iio_channel *chan, int *val)
return iio_channel_read_min(chan, val, NULL, &type, IIO_CHAN_INFO_RAW);
}
-EXPORT_SYMBOL_GPL(iio_read_min_channel_raw);
+EXPORT_SYMBOL_NS_GPL(iio_read_min_channel_raw, "IIO_CONSUMER");
int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
{
@@ -933,7 +937,7 @@ int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
return 0;
}
-EXPORT_SYMBOL_GPL(iio_get_channel_type);
+EXPORT_SYMBOL_NS_GPL(iio_get_channel_type, "IIO_CONSUMER");
static int iio_channel_write(struct iio_channel *chan, int val, int val2,
enum iio_chan_info_enum info)
@@ -957,13 +961,13 @@ int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2,
return iio_channel_write(chan, val, val2, attribute);
}
-EXPORT_SYMBOL_GPL(iio_write_channel_attribute);
+EXPORT_SYMBOL_NS_GPL(iio_write_channel_attribute, "IIO_CONSUMER");
int iio_write_channel_raw(struct iio_channel *chan, int val)
{
return iio_write_channel_attribute(chan, val, 0, IIO_CHAN_INFO_RAW);
}
-EXPORT_SYMBOL_GPL(iio_write_channel_raw);
+EXPORT_SYMBOL_NS_GPL(iio_write_channel_raw, "IIO_CONSUMER");
unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
{
@@ -978,7 +982,7 @@ unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
return i;
}
-EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count);
+EXPORT_SYMBOL_NS_GPL(iio_get_channel_ext_info_count, "IIO_CONSUMER");
static const struct iio_chan_spec_ext_info *
iio_lookup_ext_info(const struct iio_channel *chan, const char *attr)
@@ -1013,7 +1017,7 @@ ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
return ext_info->read(chan->indio_dev, ext_info->private,
chan->channel, buf);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_ext_info);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_ext_info, "IIO_CONSUMER");
ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
const char *buf, size_t len)
@@ -1027,7 +1031,7 @@ ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
return ext_info->write(chan->indio_dev, ext_info->private,
chan->channel, buf, len);
}
-EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
+EXPORT_SYMBOL_NS_GPL(iio_write_channel_ext_info, "IIO_CONSUMER");
ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf)
{
@@ -1038,4 +1042,4 @@ ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf)
return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_label);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_label, "IIO_CONSUMER");
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index ac1408d374c9..f23bbce12c72 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -45,6 +45,7 @@ config ADUX1020
config AL3000A
tristate "AL3000a ambient light sensor"
+ select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Dyna Image AL3000a
@@ -55,6 +56,7 @@ config AL3000A
config AL3010
tristate "AL3010 ambient light sensor"
+ select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Dyna Image AL3010
@@ -65,6 +67,7 @@ config AL3010
config AL3320A
tristate "AL3320A ambient light sensor"
+ select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Dyna Image AL3320A
@@ -119,6 +122,20 @@ config APDS9960
To compile this driver as a module, choose M here: the
module will be called apds9960
+config APDS9999
+ tristate "Broadcom APDS9999 ALS, RGB and proximity sensor"
+ depends on I2C
+ help
+ Say Y here if you want to build support for the Broadcom APDS9999
+ ALS, RGB and proximity sensor with I2C interface.
+
+ This driver provides ambient light sensing (ALS/Lux), raw
+ intensity data for red, green, blue and IR channels, plus
+ proximity detection support.
+
+ To compile this driver as a module, choose M here: the
+ module will be called apds9999.
+
config AS73211
tristate "AMS AS73211 XYZ color sensor and AMS AS7331 UV sensor"
depends on I2C
@@ -359,7 +376,7 @@ config ROHM_BU27034
select IIO_KFIFO_BUF
help
Enable support for the ROHM BU27034 ambient light sensor. ROHM BU27034
- is an ambient light sesnor with 3 channels and 3 photo diodes capable
+ is an ambient light sensor with 3 channels and 3 photo diodes capable
of detecting a very wide range of illuminance.
Typical application is adjusting LCD and backlight power of TVs and
mobile phones.
@@ -699,6 +716,17 @@ config VEML3235
To compile this driver as a module, choose M here: the
module will be called veml3235.
+config VEML3328
+ tristate "VEML3328 RGBCIR light sensor"
+ select REGMAP_I2C
+ depends on I2C
+ help
+ Say Y here if you want to build a driver for the Vishay VEML3328
+ RGB IR light sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called veml3328
+
config VEML6030
tristate "VEML6030 and VEML6035 ambient light sensors"
select REGMAP_I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index c0048e0d5ca8..64e354c49ed8 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_APDS9160) += apds9160.o
obj-$(CONFIG_APDS9300) += apds9300.o
obj-$(CONFIG_APDS9306) += apds9306.o
obj-$(CONFIG_APDS9960) += apds9960.o
+obj-$(CONFIG_APDS9999) += apds9999.o
obj-$(CONFIG_AS73211) += as73211.o
obj-$(CONFIG_BH1745) += bh1745.o
obj-$(CONFIG_BH1750) += bh1750.o
@@ -65,6 +66,7 @@ obj-$(CONFIG_US5182D) += us5182d.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
obj-$(CONFIG_VCNL4035) += vcnl4035.o
obj-$(CONFIG_VEML3235) += veml3235.o
+obj-$(CONFIG_VEML3328) += veml3328.o
obj-$(CONFIG_VEML6030) += veml6030.o
obj-$(CONFIG_VEML6040) += veml6040.o
obj-$(CONFIG_VEML6046X00) += veml6046x00.o
diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c
index d5d1a8b9c035..1983a7f17aa9 100644
--- a/drivers/iio/light/acpi-als.c
+++ b/drivers/iio/light/acpi-als.c
@@ -18,6 +18,7 @@
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/mutex.h>
+#include <linux/platform_device.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
@@ -90,9 +91,9 @@ static int acpi_als_read_value(struct acpi_als *als, char *prop, s32 *val)
return 0;
}
-static void acpi_als_notify(struct acpi_device *device, u32 event)
+static void acpi_als_notify(acpi_handle handle, u32 event, void *data)
{
- struct iio_dev *indio_dev = acpi_driver_data(device);
+ struct iio_dev *indio_dev = data;
struct acpi_als *als = iio_priv(indio_dev);
if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev)) {
@@ -102,7 +103,7 @@ static void acpi_als_notify(struct acpi_device *device, u32 event)
break;
default:
/* Unhandled event */
- dev_dbg(&device->dev,
+ dev_dbg(&als->device->dev,
"Unhandled ACPI ALS event (%08x)!\n",
event);
}
@@ -175,20 +176,24 @@ out:
return IRQ_HANDLED;
}
-static int acpi_als_add(struct acpi_device *device)
+static int acpi_als_probe(struct platform_device *pdev)
{
- struct device *dev = &device->dev;
+ struct device *dev = &pdev->dev;
+ struct acpi_device *device;
struct iio_dev *indio_dev;
struct acpi_als *als;
int ret;
+ device = ACPI_COMPANION(dev);
+ if (!device)
+ return -ENODEV;
+
indio_dev = devm_iio_device_alloc(dev, sizeof(*als));
if (!indio_dev)
return -ENOMEM;
als = iio_priv(indio_dev);
- device->driver_data = indio_dev;
als->device = device;
mutex_init(&als->lock);
@@ -218,7 +223,18 @@ static int acpi_als_add(struct acpi_device *device)
if (ret)
return ret;
- return devm_iio_device_register(dev, indio_dev);
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return ret;
+
+ return acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
+ acpi_als_notify, indio_dev);
+}
+
+static void acpi_als_remove(struct platform_device *pdev)
+{
+ acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
+ ACPI_DEVICE_NOTIFY, acpi_als_notify);
}
static const struct acpi_device_id acpi_als_device_ids[] = {
@@ -228,17 +244,15 @@ static const struct acpi_device_id acpi_als_device_ids[] = {
MODULE_DEVICE_TABLE(acpi, acpi_als_device_ids);
-static struct acpi_driver acpi_als_driver = {
- .name = "acpi_als",
- .class = ACPI_ALS_CLASS,
- .ids = acpi_als_device_ids,
- .ops = {
- .add = acpi_als_add,
- .notify = acpi_als_notify,
+static struct platform_driver acpi_als_driver = {
+ .probe = acpi_als_probe,
+ .remove = acpi_als_remove,
+ .driver = {
+ .name = "acpi_als",
+ .acpi_match_table = acpi_als_device_ids,
},
};
-
-module_acpi_driver(acpi_als_driver);
+module_platform_driver(acpi_als_driver);
MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
MODULE_AUTHOR("Martin Liska <marxin.liska@gmail.com>");
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index edb3d9dc8bed..088b9431d10a 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -260,7 +260,7 @@ static int adjd_s311_probe(struct i2c_client *client)
}
static const struct i2c_device_id adjd_s311_id[] = {
- { "adjd_s311" },
+ { .name = "adjd_s311" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adjd_s311_id);
diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c
index 66ff9c5fb66a..0ea282ecc99a 100644
--- a/drivers/iio/light/adux1020.c
+++ b/drivers/iio/light/adux1020.c
@@ -808,17 +808,15 @@ static int adux1020_probe(struct i2c_client *client)
NULL, adux1020_interrupt_handler,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
ADUX1020_DRV_NAME, indio_dev);
- if (ret) {
- dev_err(&client->dev, "irq request error %d\n", -ret);
+ if (ret)
return ret;
- }
}
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id adux1020_id[] = {
- { "adux1020" },
+ { .name = "adux1020" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adux1020_id);
diff --git a/drivers/iio/light/al3000a.c b/drivers/iio/light/al3000a.c
index 9871096cbab3..957ec42333ef 100644
--- a/drivers/iio/light/al3000a.c
+++ b/drivers/iio/light/al3000a.c
@@ -4,7 +4,6 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/regmap.h>
@@ -183,7 +182,7 @@ static int al3000a_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(al3000a_pm_ops, al3000a_suspend, al3000a_resume);
static const struct i2c_device_id al3000a_id[] = {
- { "al3000a" },
+ { .name = "al3000a" },
{ }
};
MODULE_DEVICE_TABLE(i2c, al3000a_id);
diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c
index 0932fa2b49fa..49f6d8336dbe 100644
--- a/drivers/iio/light/al3010.c
+++ b/drivers/iio/light/al3010.c
@@ -18,7 +18,6 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
-#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -42,7 +41,7 @@ enum al3xxxx_range {
};
static const int al3010_scales[][2] = {
- {0, 1187200}, {0, 296800}, {0, 74200}, {0, 18600}
+ { 1, 187200 }, { 0, 296800 }, { 0, 74200 }, { 0, 18600 },
};
static const struct regmap_config al3010_regmap_config = {
@@ -111,7 +110,8 @@ static int al3010_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct al3010_data *data = iio_priv(indio_dev);
- int ret, gain, raw;
+ int ret, gain;
+ __le16 raw;
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -120,11 +120,12 @@ static int al3010_read_raw(struct iio_dev *indio_dev,
* - low byte of output is stored at AL3010_REG_DATA_LOW
* - high byte of output is stored at AL3010_REG_DATA_LOW + 1
*/
- ret = regmap_read(data->regmap, AL3010_REG_DATA_LOW, &raw);
+ ret = regmap_bulk_read(data->regmap, AL3010_REG_DATA_LOW,
+ &raw, sizeof(raw));
if (ret)
return ret;
- *val = raw;
+ *val = le16_to_cpu(raw);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@@ -218,7 +219,7 @@ static int al3010_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(al3010_pm_ops, al3010_suspend, al3010_resume);
static const struct i2c_device_id al3010_id[] = {
- {"al3010", },
+ { .name = "al3010" },
{ }
};
MODULE_DEVICE_TABLE(i2c, al3010_id);
diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c
index 63f5a85912fc..8bb7f7e878c2 100644
--- a/drivers/iio/light/al3320a.c
+++ b/drivers/iio/light/al3320a.c
@@ -16,7 +16,6 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
-#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -135,7 +134,8 @@ static int al3320a_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct al3320a_data *data = iio_priv(indio_dev);
- int ret, gain, raw;
+ int ret, gain;
+ __le16 raw;
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -144,11 +144,12 @@ static int al3320a_read_raw(struct iio_dev *indio_dev,
* - low byte of output is stored at AL3320A_REG_DATA_LOW
* - high byte of output is stored at AL3320A_REG_DATA_LOW + 1
*/
- ret = regmap_read(data->regmap, AL3320A_REG_DATA_LOW, &raw);
+ ret = regmap_bulk_read(data->regmap, AL3320A_REG_DATA_LOW,
+ &raw, sizeof(raw));
if (ret)
return ret;
- *val = raw;
+ *val = le16_to_cpu(raw);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@@ -246,7 +247,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(al3320a_pm_ops, al3320a_suspend,
al3320a_resume);
static const struct i2c_device_id al3320a_id[] = {
- { "al3320a" },
+ { .name = "al3320a" },
{ }
};
MODULE_DEVICE_TABLE(i2c, al3320a_id);
diff --git a/drivers/iio/light/apds9160.c b/drivers/iio/light/apds9160.c
index 9b8af11b7b67..d7e0924b8106 100644
--- a/drivers/iio/light/apds9160.c
+++ b/drivers/iio/light/apds9160.c
@@ -620,7 +620,7 @@ static int apds9160_set_ps_gain(struct apds9160_chip *data, int val)
/*
* The PS intelligent cancellation level register allows
- * for an on-chip substraction of the ADC count caused by
+ * for an on-chip subtraction of the ADC count caused by
* unwanted reflected light from PS ADC output.
*/
static int apds9160_set_ps_cancellation_level(struct apds9160_chip *data,
@@ -1545,11 +1545,8 @@ static int apds9160_probe(struct i2c_client *client)
apds9160_irq_handler,
IRQF_ONESHOT, "apds9160_event",
indio_dev);
- if (ret) {
- return dev_err_probe(dev, ret,
- "request irq (%d) failed\n",
- client->irq);
- }
+ if (ret)
+ return ret;
} else {
indio_dev->info = &apds9160_info_no_events;
indio_dev->channels = apds9160_channels_without_events;
@@ -1572,7 +1569,7 @@ static const struct of_device_id apds9160_of_match[] = {
MODULE_DEVICE_TABLE(of, apds9160_of_match);
static const struct i2c_device_id apds9160_id[] = {
- { "apds9160", 0 },
+ { .name = "apds9160" },
{ }
};
MODULE_DEVICE_TABLE(i2c, apds9160_id);
diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c
index 05ba21675063..f0abbc4a862a 100644
--- a/drivers/iio/light/apds9300.c
+++ b/drivers/iio/light/apds9300.c
@@ -432,10 +432,8 @@ static int apds9300_probe(struct i2c_client *client)
NULL, apds9300_interrupt_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"apds9300_event", indio_dev);
- if (ret) {
- dev_err(&client->dev, "irq request error %d\n", -ret);
+ if (ret)
goto err;
- }
}
ret = iio_device_register(indio_dev);
@@ -492,7 +490,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend,
apds9300_resume);
static const struct i2c_device_id apds9300_id[] = {
- { APDS9300_DRV_NAME },
+ { .name = APDS9300_DRV_NAME },
{ }
};
diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c
index 7e68cca0edfa..f681b02e4922 100644
--- a/drivers/iio/light/apds9306.c
+++ b/drivers/iio/light/apds9306.c
@@ -168,7 +168,6 @@ struct apds9306_regfields {
* respectively.
* @regmap: Regmap structure pointer
* @rf: Regmap register fields structure
- * @nlux_per_count: Nano lux per ADC count for a particular model
* @read_data_available: Flag set by IRQ handler for ADC data available
*/
struct apds9306_data {
@@ -180,7 +179,6 @@ struct apds9306_data {
struct regmap *regmap;
struct apds9306_regfields rf;
- int nlux_per_count;
int read_data_available;
};
@@ -471,9 +469,9 @@ static int apds9306_read_data(struct apds9306_data *data, int *val, int reg)
int status = 0;
u8 buff[3];
- ret = pm_runtime_resume_and_get(data->dev);
- if (ret)
- return ret;
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(data->dev, pm);
+ if (PM_RUNTIME_ACQUIRE_ERR(&pm))
+ return PM_RUNTIME_ACQUIRE_ERR(&pm);
ret = regmap_field_read(rf->intg_time, &intg_time_idx);
if (ret)
@@ -537,8 +535,6 @@ static int apds9306_read_data(struct apds9306_data *data, int *val, int reg)
*val = get_unaligned_le24(&buff);
- pm_runtime_put_autosuspend(data->dev);
-
return 0;
}
@@ -1176,7 +1172,7 @@ static int apds9306_init_iio_gts(struct apds9306_data *data)
static void apds9306_powerdown(void *ptr)
{
- struct apds9306_data *data = (struct apds9306_data *)ptr;
+ struct apds9306_data *data = ptr;
struct apds9306_regfields *rf = &data->rf;
int ret;
@@ -1288,8 +1284,7 @@ static int apds9306_probe(struct i2c_client *client)
apds9306_irq_handler, IRQF_ONESHOT,
"apds9306_event", indio_dev);
if (ret)
- return dev_err_probe(dev, ret,
- "failed to assign interrupt.\n");
+ return ret;
} else {
indio_dev->info = &apds9306_info_no_events;
indio_dev->channels = apds9306_channels_without_events;
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index 785c5dbe2d08..afe520de60e2 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -1098,10 +1098,8 @@ static int apds9960_probe(struct i2c_client *client)
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"apds9960_event",
indio_dev);
- if (ret) {
- dev_err(&client->dev, "request irq (%d) failed\n", client->irq);
+ if (ret)
goto error_power_down;
- }
ret = iio_device_register(indio_dev);
if (ret)
@@ -1154,7 +1152,7 @@ static const struct dev_pm_ops apds9960_pm_ops = {
};
static const struct i2c_device_id apds9960_id[] = {
- { "apds9960" },
+ { .name = "apds9960" },
{ }
};
MODULE_DEVICE_TABLE(i2c, apds9960_id);
diff --git a/drivers/iio/light/apds9999.c b/drivers/iio/light/apds9999.c
new file mode 100644
index 000000000000..43fa9992c9c2
--- /dev/null
+++ b/drivers/iio/light/apds9999.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * IIO driver for Broadcom APDS9999 Lux Light Sensor
+ *
+ * Copyright (C) 2026
+ * Author: Jose A. Perez de Azpillaga <azpijr@gmail.com>
+ *
+ * TODO: proximity sensor
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/unaligned.h>
+#include <linux/units.h>
+
+#define APDS9999_REG_MAIN_CTRL 0x00
+#define APDS9999_MAIN_CTRL_LS_EN BIT(1)
+#define APDS9999_REG_LS_MEAS_RATE 0x04
+#define APDS9999_LS_RES_MASK GENMASK(6, 4)
+#define APDS9999_LS_RATE_MASK GENMASK(2, 0)
+#define APDS9999_REG_LS_GAIN 0x05
+#define APDS9999_REG_PART_ID 0x06
+#define APDS9999_REG_MAIN_STATUS 0x07
+#define APDS9999_MAIN_STATUS_LS_DATA BIT(3)
+#define APDS9999_REG_LS_DATA_IR_0 0x0A
+#define APDS9999_REG_LS_DATA_GREEN_0 0x0D
+#define APDS9999_REG_LS_DATA_BLUE_0 0x10
+#define APDS9999_REG_LS_DATA_RED_0 0x13
+
+#define APDS9999_PART_ID 0xC2
+
+#define APDS9999_GAIN_1X 0
+#define APDS9999_GAIN_3X 1
+#define APDS9999_GAIN_6X 2
+#define APDS9999_GAIN_9X 3
+#define APDS9999_GAIN_18X 4
+
+static const int apds9999_gains[] = {
+ [APDS9999_GAIN_1X] = 1,
+ [APDS9999_GAIN_3X] = 3,
+ [APDS9999_GAIN_6X] = 6,
+ [APDS9999_GAIN_9X] = 9,
+ [APDS9999_GAIN_18X] = 18,
+};
+
+#define APDS9999_RES_20BIT 0
+#define APDS9999_RES_19BIT 1
+#define APDS9999_RES_18BIT 2
+#define APDS9999_RES_17BIT 3
+#define APDS9999_RES_16BIT 4
+#define APDS9999_RES_13BIT 5
+
+static const int apds9999_itimes_us[] = {
+ [APDS9999_RES_20BIT] = 400 * USEC_PER_MSEC,
+ [APDS9999_RES_19BIT] = 200 * USEC_PER_MSEC,
+ [APDS9999_RES_18BIT] = 100 * USEC_PER_MSEC,
+ [APDS9999_RES_17BIT] = 50 * USEC_PER_MSEC,
+ [APDS9999_RES_16BIT] = 25 * USEC_PER_MSEC,
+ [APDS9999_RES_13BIT] = 3125,
+};
+
+#define APDS9999_RATE_25_MS 0
+#define APDS9999_RATE_50_MS 1
+#define APDS9999_RATE_100_MS 2
+#define APDS9999_RATE_200_MS 3
+#define APDS9999_RATE_500_MS 4
+#define APDS9999_RATE_1000_MS 5
+#define APDS9999_RATE_2000_MS 6
+
+struct apds9999_data {
+ struct i2c_client *client;
+ /* lock: serializes access to device registers and cached values */
+ struct mutex lock;
+ int als_gain_idx;
+ int als_res;
+ int als_rate;
+};
+
+static void apds9999_standby(void *client)
+{
+ i2c_smbus_write_byte_data(client, APDS9999_REG_MAIN_CTRL, 0);
+}
+
+/*
+ * Apply power-on defaults: 18-bit / 100 ms resolution and rate,
+ * 3x gain. These match the datasheet reset values.
+ */
+static int apds9999_init(struct apds9999_data *data)
+{
+ struct device *dev = &data->client->dev;
+ struct i2c_client *client = data->client;
+ u8 regval;
+ int ret;
+
+ ret = devm_add_action_or_reset(dev, apds9999_standby, client);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&data->lock);
+
+ regval = FIELD_PREP(APDS9999_LS_RES_MASK, APDS9999_RES_18BIT) |
+ FIELD_PREP(APDS9999_LS_RATE_MASK, APDS9999_RATE_100_MS);
+ ret = i2c_smbus_write_byte_data(client, APDS9999_REG_LS_MEAS_RATE,
+ regval);
+ if (ret)
+ return ret;
+ data->als_res = APDS9999_RES_18BIT;
+ data->als_rate = APDS9999_RATE_100_MS;
+
+ ret = i2c_smbus_write_byte_data(client, APDS9999_REG_LS_GAIN,
+ APDS9999_GAIN_3X);
+ if (ret)
+ return ret;
+ data->als_gain_idx = APDS9999_GAIN_3X;
+
+ return i2c_smbus_write_byte_data(client, APDS9999_REG_MAIN_CTRL,
+ APDS9999_MAIN_CTRL_LS_EN);
+}
+
+static int apds9999_read_channel(struct apds9999_data *data, u8 reg,
+ u32 *counts)
+{
+ struct i2c_client *client = data->client;
+ u8 buf[3];
+ int ret, tries;
+
+ guard(mutex)(&data->lock);
+
+ /*
+ * Poll MAIN_STATUS for new data. Timeout: ~2 integration periods
+ * plus margin. Each try sleeps 20 ms.
+ */
+ tries = max(2, (apds9999_itimes_us[data->als_res] * 2) / 20000);
+
+ while (tries--) {
+ ret = i2c_smbus_read_byte_data(client,
+ APDS9999_REG_MAIN_STATUS);
+ if (ret < 0)
+ return ret;
+ if (ret & APDS9999_MAIN_STATUS_LS_DATA)
+ break;
+ fsleep(20000);
+ }
+
+ if (tries < 0)
+ return -ETIMEDOUT;
+
+ ret = i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf);
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(buf))
+ return -EIO;
+
+ *counts = get_unaligned_le24(buf) & GENMASK(19, 0);
+ return 0;
+}
+
+static int apds9999_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct apds9999_data *data = iio_priv(indio_dev);
+ int gain, itime_us;
+ u64 scale_nano;
+ u32 counts;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = apds9999_read_channel(data, chan->address, &counts);
+ if (ret)
+ return ret;
+ *val = (int)counts;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE: {
+ u32 remainder;
+
+ /*
+ * Scale (lux per count) = 54 / (gain * integration_time_ms)
+ *
+ * The constant 54 is derived from the datasheet table:
+ * at gain = 3x, itime = 100 ms -> 0.180 lux/count
+ * -> C = 0.180 * 3 * 100 = 54
+ *
+ * Expressed as IIO_VAL_INT_PLUS_NANO.
+ */
+ gain = apds9999_gains[data->als_gain_idx];
+ itime_us = apds9999_itimes_us[data->als_res];
+
+ /* scale_nano = 54 * 1e12 / (gain * itime_us) nano-lux/count */
+ scale_nano = div_u64(54ULL * NSEC_PER_SEC * USEC_PER_MSEC, (u32)(gain * itime_us));
+ *val = (int)div_u64_rem(scale_nano, NSEC_PER_SEC, &remainder);
+ *val2 = (int)remainder;
+ return IIO_VAL_INT_PLUS_NANO;
+ }
+ case IIO_CHAN_INFO_INT_TIME:
+ *val = 0;
+ *val2 = apds9999_itimes_us[data->als_res];
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info apds9999_info = {
+ .read_raw = apds9999_read_raw,
+};
+
+/*
+ * The green channel uses optical coating to approximate the human eye
+ * spectral response. IIO_INTENSITY channels provide raw ADC data for
+ * red, green, blue, and IR so userspace can compute weighted lux.
+ */
+static const struct iio_chan_spec apds9999_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+ .address = APDS9999_REG_LS_DATA_GREEN_0,
+ },
+ {
+ .type = IIO_INTENSITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_RED,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+ .address = APDS9999_REG_LS_DATA_RED_0,
+ },
+ {
+ .type = IIO_INTENSITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_GREEN,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+ .address = APDS9999_REG_LS_DATA_GREEN_0,
+ },
+ {
+ .type = IIO_INTENSITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_BLUE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+ .address = APDS9999_REG_LS_DATA_BLUE_0,
+ },
+ {
+ .type = IIO_INTENSITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_IR,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+ .address = APDS9999_REG_LS_DATA_IR_0,
+ },
+};
+
+static int apds9999_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct apds9999_data *data;
+ struct iio_dev *indio_dev;
+ int ret, part_id;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+
+ ret = devm_mutex_init(dev, &data->lock);
+ if (ret)
+ return ret;
+
+ part_id = i2c_smbus_read_byte_data(client, APDS9999_REG_PART_ID);
+ if (part_id < 0)
+ return dev_err_probe(dev, part_id, "failed to read PART_ID\n");
+ if (part_id != APDS9999_PART_ID)
+ dev_info(dev, "unexpected PART_ID 0x%02x (expected 0x%02x)\n",
+ part_id, APDS9999_PART_ID);
+
+ ret = apds9999_init(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize device\n");
+
+ indio_dev->name = "apds9999";
+ indio_dev->info = &apds9999_info;
+ indio_dev->channels = apds9999_channels;
+ indio_dev->num_channels = ARRAY_SIZE(apds9999_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register IIO device\n");
+
+ return 0;
+}
+
+static const struct i2c_device_id apds9999_id[] = {
+ { .name = "apds9999" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, apds9999_id);
+
+static const struct of_device_id apds9999_of_match[] = {
+ { .compatible = "brcm,apds9999" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, apds9999_of_match);
+
+static struct i2c_driver apds9999_driver = {
+ .driver = {
+ .name = "apds9999",
+ .of_match_table = apds9999_of_match,
+ },
+ .probe = apds9999_probe,
+ .id_table = apds9999_id,
+};
+module_i2c_driver(apds9999_driver);
+
+MODULE_AUTHOR("Jose A. Perez de Azpillaga <azpijr@gmail.com>");
+MODULE_DESCRIPTION("APDS-9999 Lux Light Sensor IIO Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c
index 32719f584c47..67f33bbe1c13 100644
--- a/drivers/iio/light/as73211.c
+++ b/drivers/iio/light/as73211.c
@@ -677,9 +677,6 @@ static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p)
(char *)&scan.chan[0], 3 * sizeof(scan.chan[0]));
if (ret < 0)
goto done;
-
- /* Avoid pushing uninitialized data */
- scan.chan[3] = 0;
}
if (data_result) {
@@ -878,8 +875,8 @@ static const struct of_device_id as73211_of_match[] = {
MODULE_DEVICE_TABLE(of, as73211_of_match);
static const struct i2c_device_id as73211_id[] = {
- { "as73211", (kernel_ulong_t)&as73211_spec },
- { "as7331", (kernel_ulong_t)&as7331_spec },
+ { .name = "as73211", .driver_data = (kernel_ulong_t)&as73211_spec },
+ { .name = "as7331", .driver_data = (kernel_ulong_t)&as7331_spec },
{ }
};
MODULE_DEVICE_TABLE(i2c, as73211_id);
diff --git a/drivers/iio/light/bh1745.c b/drivers/iio/light/bh1745.c
index 10b00344bbed..2b8ff36071b8 100644
--- a/drivers/iio/light/bh1745.c
+++ b/drivers/iio/light/bh1745.c
@@ -784,8 +784,7 @@ static int bh1745_setup_triggered_buffer(struct iio_dev *indio_dev,
IRQF_ONESHOT,
"bh1745_interrupt", indio_dev);
if (ret)
- return dev_err_probe(dev, ret,
- "Request for IRQ failed\n");
+ return ret;
}
return 0;
@@ -874,7 +873,7 @@ static int bh1745_probe(struct i2c_client *client)
}
static const struct i2c_device_id bh1745_idtable[] = {
- { "bh1745" },
+ { .name = "bh1745" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bh1745_idtable);
diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c
index 764f88826fcb..a51ac98c83c8 100644
--- a/drivers/iio/light/bh1750.c
+++ b/drivers/iio/light/bh1750.c
@@ -319,11 +319,11 @@ static int bh1750_suspend(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(bh1750_pm_ops, bh1750_suspend, NULL);
static const struct i2c_device_id bh1750_id[] = {
- { "bh1710", BH1710 },
- { "bh1715", BH1750 },
- { "bh1721", BH1721 },
- { "bh1750", BH1750 },
- { "bh1751", BH1750 },
+ { .name = "bh1710", .driver_data = BH1710 },
+ { .name = "bh1715", .driver_data = BH1750 },
+ { .name = "bh1721", .driver_data = BH1721 },
+ { .name = "bh1750", .driver_data = BH1750 },
+ { .name = "bh1751", .driver_data = BH1750 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bh1750_id);
diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c
index a740d1f992a8..5447b990ffb7 100644
--- a/drivers/iio/light/bh1780.c
+++ b/drivers/iio/light/bh1780.c
@@ -13,7 +13,6 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -255,7 +254,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(bh1780_dev_pm_ops, bh1780_runtime_suspend,
bh1780_runtime_resume, NULL);
static const struct i2c_device_id bh1780_id[] = {
- { "bh1780" },
+ { .name = "bh1780" },
{ }
};
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index bb90f738312a..b32a94028f09 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -10,7 +10,6 @@
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
@@ -369,7 +368,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_CALIBSCALE:
cm32181->calibscale = val;
- return val;
+ return 0;
case IIO_CHAN_INFO_INT_TIME:
ret = cm32181_write_als_it(cm32181, val2);
return ret;
diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c
index 3a3ad6b4c468..5f25452633f2 100644
--- a/drivers/iio/light/cm3232.c
+++ b/drivers/iio/light/cm3232.c
@@ -10,7 +10,6 @@
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/init.h>
@@ -366,9 +365,10 @@ static void cm3232_remove(struct i2c_client *client)
}
static const struct i2c_device_id cm3232_id[] = {
- { "cm3232" },
+ { .name = "cm3232" },
{ }
};
+MODULE_DEVICE_TABLE(i2c, cm3232_id);
static int cm3232_suspend(struct device *dev)
{
@@ -400,8 +400,6 @@ static int cm3232_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(cm3232_pm_ops, cm3232_suspend, cm3232_resume);
-MODULE_DEVICE_TABLE(i2c, cm3232_id);
-
static const struct of_device_id cm3232_of_match[] = {
{.compatible = "capella,cm3232"},
{ }
diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c
index 79ad6e2209ca..506c91f44f43 100644
--- a/drivers/iio/light/cm3323.c
+++ b/drivers/iio/light/cm3323.c
@@ -80,24 +80,20 @@ static int cm3323_init(struct iio_dev *indio_dev)
{
int ret;
struct cm3323_data *data = iio_priv(indio_dev);
+ struct device *dev = &data->client->dev;
ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_conf\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Error reading reg_conf\n");
/* enable sensor and set auto force mode */
ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT);
-
- ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, ret);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_conf\n");
- return ret;
- }
-
data->reg_conf = ret;
+ ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, data->reg_conf);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Error writing reg_conf\n");
+
return 0;
}
@@ -237,10 +233,8 @@ static int cm3323_probe(struct i2c_client *client)
indio_dev->modes = INDIO_DIRECT_MODE;
ret = cm3323_init(indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "cm3323 chip init failed\n");
+ if (ret < 0)
return ret;
- }
ret = devm_add_action_or_reset(&client->dev, cm3323_disable, indio_dev);
if (ret < 0)
@@ -250,7 +244,7 @@ static int cm3323_probe(struct i2c_client *client)
}
static const struct i2c_device_id cm3323_id[] = {
- { "cm3323" },
+ { .name = "cm3323" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cm3323_id);
diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c
index 0c17378e27d1..34c127593947 100644
--- a/drivers/iio/light/cm3605.c
+++ b/drivers/iio/light/cm3605.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
@@ -233,10 +232,8 @@ static int cm3605_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(dev, irq, cm3605_prox_irq,
NULL, 0, "cm3605", indio_dev);
- if (ret) {
- dev_err(dev, "unable to request IRQ\n");
+ if (ret)
goto out_disable_aset;
- }
/* Just name the trigger the same as the driver */
led_trigger_register_simple("cm3605", &cm3605->led);
@@ -325,3 +322,4 @@ module_platform_driver(cm3605_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("CM3605 ambient light and proximity sensor driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c
index 446dd54d5037..6ebd8ce4ca12 100644
--- a/drivers/iio/light/cm36651.c
+++ b/drivers/iio/light/cm36651.c
@@ -713,7 +713,7 @@ static void cm36651_remove(struct i2c_client *client)
}
static const struct i2c_device_id cm36651_id[] = {
- { "cm36651" },
+ { .name = "cm36651" },
{ }
};
diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c
index 815806ceb5c8..7ab565b1fb9f 100644
--- a/drivers/iio/light/cros_ec_light_prox.c
+++ b/drivers/iio/light/cros_ec_light_prox.c
@@ -14,7 +14,6 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
@@ -223,14 +222,8 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
return -EINVAL;
}
- /* Timestamp */
channel++;
- channel->type = IIO_TIMESTAMP;
- channel->channel = -1;
- channel->scan_index = 1;
- channel->scan_type.sign = 's';
- channel->scan_type.realbits = 64;
- channel->scan_type.storagebits = 64;
+ *channel = IIO_CHAN_SOFT_TIMESTAMP(1);
indio_dev->channels = state->channels;
diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c
index a0d8a58f2704..1fd40d60182e 100644
--- a/drivers/iio/light/gp2ap002.c
+++ b/drivers/iio/light/gp2ap002.c
@@ -258,7 +258,7 @@ static int gp2ap002_read_raw(struct iio_dev *indio_dev,
case IIO_LIGHT:
ret = gp2ap002_get_lux(gp2ap002);
if (ret < 0)
- return ret;
+ goto out;
*val = ret;
ret = IIO_VAL_INT;
goto out;
@@ -342,6 +342,10 @@ static int gp2ap002_write_event_config(struct iio_dev *indio_dev,
bool state)
{
struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
+ int ret;
+
+ if (state == gp2ap002->enabled)
+ return 0;
if (state) {
/*
@@ -349,13 +353,16 @@ static int gp2ap002_write_event_config(struct iio_dev *indio_dev,
* already) and reintialize the sensor by using runtime_pm
* callbacks.
*/
- pm_runtime_get_sync(gp2ap002->dev);
- gp2ap002->enabled = true;
+ ret = pm_runtime_resume_and_get(gp2ap002->dev);
+ if (ret)
+ return ret;
+
} else {
pm_runtime_put_autosuspend(gp2ap002->dev);
- gp2ap002->enabled = false;
}
+ gp2ap002->enabled = state;
+
return 0;
}
@@ -573,10 +580,8 @@ static int gp2ap002_probe(struct i2c_client *client)
ret = devm_request_threaded_irq(dev, client->irq, NULL,
gp2ap002_prox_irq, IRQF_ONESHOT,
"gp2ap002", indio_dev);
- if (ret) {
- dev_err(dev, "unable to request IRQ\n");
+ if (ret)
goto out_put_pm;
- }
gp2ap002->irq = client->irq;
/*
@@ -642,6 +647,7 @@ static int gp2ap002_runtime_suspend(struct device *dev)
/* Disable chip and IRQ, everything off */
ret = regmap_write(gp2ap002->map, GP2AP002_OPMOD, 0x00);
if (ret) {
+ enable_irq(gp2ap002->irq);
dev_err(gp2ap002->dev, "error setting up operation mode\n");
return ret;
}
@@ -669,7 +675,7 @@ static int gp2ap002_runtime_resume(struct device *dev)
ret = regulator_enable(gp2ap002->vio);
if (ret) {
dev_err(dev, "failed to enable VIO regulator in resume path\n");
- return ret;
+ goto out_disable_vdd;
}
msleep(20);
@@ -677,20 +683,26 @@ static int gp2ap002_runtime_resume(struct device *dev)
ret = gp2ap002_init(gp2ap002);
if (ret) {
dev_err(dev, "re-initialization failed\n");
- return ret;
+ goto out_disable_vio;
}
/* Re-activate the IRQ */
enable_irq(gp2ap002->irq);
return 0;
+
+out_disable_vio:
+ regulator_disable(gp2ap002->vio);
+out_disable_vdd:
+ regulator_disable(gp2ap002->vdd);
+ return ret;
}
static DEFINE_RUNTIME_DEV_PM_OPS(gp2ap002_dev_pm_ops, gp2ap002_runtime_suspend,
gp2ap002_runtime_resume, NULL);
static const struct i2c_device_id gp2ap002_id_table[] = {
- { "gp2ap002" },
+ { .name = "gp2ap002" },
{ }
};
MODULE_DEVICE_TABLE(i2c, gp2ap002_id_table);
@@ -717,3 +729,4 @@ module_i2c_driver(gp2ap002_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("GP2AP002 ambient light and proximity sensor driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c
index c7df4b258e2c..63591b7ecb89 100644
--- a/drivers/iio/light/gp2ap020a00f.c
+++ b/drivers/iio/light/gp2ap020a00f.c
@@ -31,19 +31,21 @@
* the other one.
*/
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irq_work.h>
+#include <linux/minmax.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/unaligned.h>
+
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
@@ -52,8 +54,6 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
-#define GP2A_I2C_NAME "gp2ap020a00f"
-
/* Registers */
#define GP2AP020A00F_OP_REG 0x00 /* Basic operations */
#define GP2AP020A00F_ALS_REG 0x01 /* ALS related settings */
@@ -174,10 +174,8 @@
#define GP2AP020A00F_CHAN_TIMESTAMP 3
#define GP2AP020A00F_DATA_READY_TIMEOUT msecs_to_jiffies(1000)
-#define GP2AP020A00F_DATA_REG(chan) (GP2AP020A00F_D0_L_REG + \
- (chan) * 2)
-#define GP2AP020A00F_THRESH_REG(th_val_id) (GP2AP020A00F_TL_L_REG + \
- (th_val_id) * 2)
+#define GP2AP020A00F_DATA_REG(chan) (GP2AP020A00F_D0_L_REG + (chan) * 2)
+#define GP2AP020A00F_THRESH_REG(th_val_id) (GP2AP020A00F_TL_L_REG + (th_val_id) * 2)
#define GP2AP020A00F_THRESH_VAL_ID(reg_addr) ((reg_addr - 4) / 2)
#define GP2AP020A00F_SUBTRACT_MODE 0
@@ -194,7 +192,7 @@ enum gp2ap020a00f_opmode {
GP2AP020A00F_OPMODE_ALS_AND_PS,
GP2AP020A00F_OPMODE_PROX_DETECT,
GP2AP020A00F_OPMODE_SHUTDOWN,
- GP2AP020A00F_NUM_OPMODES,
+ GP2AP020A00F_NUM_OPMODES
};
enum gp2ap020a00f_cmd {
@@ -246,7 +244,6 @@ struct gp2ap020a00f_data {
struct iio_trigger *trig;
struct regmap *regmap;
unsigned int thresh_val[4];
- u8 debug_reg_addr;
struct irq_work work;
wait_queue_head_t data_ready_queue;
};
@@ -389,20 +386,17 @@ static int gp2ap020a00f_set_operation_mode(struct gp2ap020a00f_data *data,
}
err = regmap_update_bits(data->regmap, GP2AP020A00F_ALS_REG,
- GP2AP020A00F_PRST_MASK, opmode_regs_settings[op]
- .als_reg);
+ GP2AP020A00F_PRST_MASK, opmode_regs_settings[op].als_reg);
if (err < 0)
return err;
err = regmap_update_bits(data->regmap, GP2AP020A00F_PS_REG,
- GP2AP020A00F_INTTYPE_MASK, opmode_regs_settings[op]
- .ps_reg);
+ GP2AP020A00F_INTTYPE_MASK, opmode_regs_settings[op].ps_reg);
if (err < 0)
return err;
err = regmap_update_bits(data->regmap, GP2AP020A00F_LED_REG,
- GP2AP020A00F_PIN_MASK, opmode_regs_settings[op]
- .led_reg);
+ GP2AP020A00F_PIN_MASK, opmode_regs_settings[op].led_reg);
if (err < 0)
return err;
}
@@ -453,15 +447,13 @@ static int gp2ap020a00f_write_event_threshold(struct gp2ap020a00f_data *data,
*/
thresh_reg_val = data->thresh_val[th_val_id] / 16;
else
- thresh_reg_val = data->thresh_val[th_val_id] > 16000 ?
- 16000 :
- data->thresh_val[th_val_id];
+ thresh_reg_val = min(data->thresh_val[th_val_id], 16000U);
thresh_buf = cpu_to_le16(thresh_reg_val);
return regmap_bulk_write(data->regmap,
GP2AP020A00F_THRESH_REG(th_val_id),
- (u8 *)&thresh_buf, 2);
+ &thresh_buf, sizeof(thresh_buf));
}
static int gp2ap020a00f_alter_opmode(struct gp2ap020a00f_data *data,
@@ -493,27 +485,24 @@ static int gp2ap020a00f_alter_opmode(struct gp2ap020a00f_data *data,
static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
enum gp2ap020a00f_cmd cmd)
{
- int err = 0;
+ int err;
switch (cmd) {
case GP2AP020A00F_CMD_READ_RAW_CLEAR:
if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN)
return -EBUSY;
- err = gp2ap020a00f_set_operation_mode(data,
+ return gp2ap020a00f_set_operation_mode(data,
GP2AP020A00F_OPMODE_READ_RAW_CLEAR);
- break;
case GP2AP020A00F_CMD_READ_RAW_IR:
if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN)
return -EBUSY;
- err = gp2ap020a00f_set_operation_mode(data,
+ return gp2ap020a00f_set_operation_mode(data,
GP2AP020A00F_OPMODE_READ_RAW_IR);
- break;
case GP2AP020A00F_CMD_READ_RAW_PROXIMITY:
if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN)
return -EBUSY;
- err = gp2ap020a00f_set_operation_mode(data,
+ return gp2ap020a00f_set_operation_mode(data,
GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY);
- break;
case GP2AP020A00F_CMD_TRIGGER_CLEAR_EN:
if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)
return -EBUSY;
@@ -521,16 +510,17 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
err = gp2ap020a00f_alter_opmode(data,
GP2AP020A00F_OPMODE_ALS,
GP2AP020A00F_ADD_MODE);
+ else
+ err = 0;
set_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags);
- break;
+ return err;
case GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS:
clear_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags);
if (gp2ap020a00f_als_enabled(data))
break;
- err = gp2ap020a00f_alter_opmode(data,
+ return gp2ap020a00f_alter_opmode(data,
GP2AP020A00F_OPMODE_ALS,
GP2AP020A00F_SUBTRACT_MODE);
- break;
case GP2AP020A00F_CMD_TRIGGER_IR_EN:
if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)
return -EBUSY;
@@ -538,16 +528,17 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
err = gp2ap020a00f_alter_opmode(data,
GP2AP020A00F_OPMODE_ALS,
GP2AP020A00F_ADD_MODE);
+ else
+ err = 0;
set_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags);
- break;
+ return err;
case GP2AP020A00F_CMD_TRIGGER_IR_DIS:
clear_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags);
if (gp2ap020a00f_als_enabled(data))
break;
- err = gp2ap020a00f_alter_opmode(data,
+ return gp2ap020a00f_alter_opmode(data,
GP2AP020A00F_OPMODE_ALS,
GP2AP020A00F_SUBTRACT_MODE);
- break;
case GP2AP020A00F_CMD_TRIGGER_PROX_EN:
if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)
return -EBUSY;
@@ -555,13 +546,12 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
GP2AP020A00F_OPMODE_PS,
GP2AP020A00F_ADD_MODE);
set_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags);
- break;
+ return err;
case GP2AP020A00F_CMD_TRIGGER_PROX_DIS:
clear_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags);
- err = gp2ap020a00f_alter_opmode(data,
+ return gp2ap020a00f_alter_opmode(data,
GP2AP020A00F_OPMODE_PS,
GP2AP020A00F_SUBTRACT_MODE);
- break;
case GP2AP020A00F_CMD_ALS_HIGH_EV_EN:
if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags))
return 0;
@@ -575,9 +565,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
return err;
}
set_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags);
- err = gp2ap020a00f_write_event_threshold(data,
+ return gp2ap020a00f_write_event_threshold(data,
GP2AP020A00F_THRESH_TH, true);
- break;
case GP2AP020A00F_CMD_ALS_HIGH_EV_DIS:
if (!test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags))
return 0;
@@ -589,9 +578,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
if (err < 0)
return err;
}
- err = gp2ap020a00f_write_event_threshold(data,
+ return gp2ap020a00f_write_event_threshold(data,
GP2AP020A00F_THRESH_TH, false);
- break;
case GP2AP020A00F_CMD_ALS_LOW_EV_EN:
if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags))
return 0;
@@ -605,9 +593,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
return err;
}
set_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags);
- err = gp2ap020a00f_write_event_threshold(data,
+ return gp2ap020a00f_write_event_threshold(data,
GP2AP020A00F_THRESH_TL, true);
- break;
case GP2AP020A00F_CMD_ALS_LOW_EV_DIS:
if (!test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags))
return 0;
@@ -619,9 +606,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
if (err < 0)
return err;
}
- err = gp2ap020a00f_write_event_threshold(data,
+ return gp2ap020a00f_write_event_threshold(data,
GP2AP020A00F_THRESH_TL, false);
- break;
case GP2AP020A00F_CMD_PROX_HIGH_EV_EN:
if (test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags))
return 0;
@@ -635,9 +621,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
return err;
}
set_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags);
- err = gp2ap020a00f_write_event_threshold(data,
+ return gp2ap020a00f_write_event_threshold(data,
GP2AP020A00F_THRESH_PH, true);
- break;
case GP2AP020A00F_CMD_PROX_HIGH_EV_DIS:
if (!test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags))
return 0;
@@ -646,9 +631,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
GP2AP020A00F_OPMODE_SHUTDOWN);
if (err < 0)
return err;
- err = gp2ap020a00f_write_event_threshold(data,
+ return gp2ap020a00f_write_event_threshold(data,
GP2AP020A00F_THRESH_PH, false);
- break;
case GP2AP020A00F_CMD_PROX_LOW_EV_EN:
if (test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags))
return 0;
@@ -662,9 +646,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
return err;
}
set_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags);
- err = gp2ap020a00f_write_event_threshold(data,
+ return gp2ap020a00f_write_event_threshold(data,
GP2AP020A00F_THRESH_PL, true);
- break;
case GP2AP020A00F_CMD_PROX_LOW_EV_DIS:
if (!test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags))
return 0;
@@ -673,12 +656,11 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
GP2AP020A00F_OPMODE_SHUTDOWN);
if (err < 0)
return err;
- err = gp2ap020a00f_write_event_threshold(data,
+ return gp2ap020a00f_write_event_threshold(data,
GP2AP020A00F_THRESH_PL, false);
- break;
}
- return err;
+ return 0;
}
static int wait_conversion_complete_irq(struct gp2ap020a00f_data *data)
@@ -697,18 +679,18 @@ static int wait_conversion_complete_irq(struct gp2ap020a00f_data *data)
static int gp2ap020a00f_read_output(struct gp2ap020a00f_data *data,
unsigned int output_reg, int *val)
{
- u8 reg_buf[2];
+ __le16 reg_buf;
int err;
err = wait_conversion_complete_irq(data);
if (err < 0)
dev_dbg(&data->client->dev, "data ready timeout\n");
- err = regmap_bulk_read(data->regmap, output_reg, reg_buf, 2);
+ err = regmap_bulk_read(data->regmap, output_reg, &reg_buf, sizeof(reg_buf));
if (err < 0)
return err;
- *val = le16_to_cpup((__le16 *)reg_buf);
+ *val = le16_to_cpu(reg_buf);
return err;
}
@@ -866,13 +848,13 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data)
{
struct iio_dev *indio_dev = data;
struct gp2ap020a00f_data *priv = iio_priv(indio_dev);
- u8 op_reg_flags, d0_reg_buf[2];
unsigned int output_val, op_reg_val;
+ __le16 d0_reg_buf;
+ u8 op_reg_flags;
int thresh_val_id, ret;
/* Read interrupt flags */
- ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG,
- &op_reg_val);
+ ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG, &op_reg_val);
if (ret < 0)
goto done;
@@ -884,8 +866,7 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data)
/* Clear interrupt flags (if not in INTTYPE_PULSE mode) */
if (priv->cur_opmode != GP2AP020A00F_OPMODE_PROX_DETECT) {
- ret = regmap_write(priv->regmap, GP2AP020A00F_OP_REG,
- op_reg_val);
+ ret = regmap_write(priv->regmap, GP2AP020A00F_OP_REG, op_reg_val);
if (ret < 0)
goto done;
}
@@ -895,11 +876,11 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data)
* transition is required.
*/
ret = regmap_bulk_read(priv->regmap, GP2AP020A00F_D0_L_REG,
- d0_reg_buf, 2);
+ &d0_reg_buf, sizeof(d0_reg_buf));
if (ret < 0)
goto done;
- output_val = le16_to_cpup((__le16 *)d0_reg_buf);
+ output_val = le16_to_cpu(d0_reg_buf);
if (gp2ap020a00f_adjust_lux_mode(priv, output_val))
goto done;
@@ -966,17 +947,15 @@ static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data)
int i, out_val, ret;
iio_for_each_active_channel(indio_dev, i) {
- ret = regmap_bulk_read(priv->regmap,
- GP2AP020A00F_DATA_REG(i),
- &priv->buffer[d_size], 2);
+ ret = regmap_bulk_read(priv->regmap, GP2AP020A00F_DATA_REG(i),
+ &priv->buffer[d_size], 2);
if (ret < 0)
goto done;
if (i == GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR ||
i == GP2AP020A00F_SCAN_MODE_LIGHT_IR) {
- out_val = le16_to_cpup((__le16 *)&priv->buffer[d_size]);
+ out_val = get_unaligned_le16(&priv->buffer[d_size]);
gp2ap020a00f_output_to_lux(priv, &out_val);
-
put_unaligned_le32(out_val, &priv->buffer[d_size]);
d_size += 4;
} else {
@@ -984,16 +963,15 @@ static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data)
}
}
- iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer,
- pf->timestamp);
+ iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer, pf->timestamp);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
-static u8 gp2ap020a00f_get_thresh_reg(const struct iio_chan_spec *chan,
- enum iio_event_direction event_dir)
+static int gp2ap020a00f_get_thresh_reg(const struct iio_chan_spec *chan,
+ enum iio_event_direction event_dir)
{
switch (chan->type) {
case IIO_PROXIMITY:
@@ -1007,10 +985,8 @@ static u8 gp2ap020a00f_get_thresh_reg(const struct iio_chan_spec *chan,
else
return GP2AP020A00F_TL_L_REG;
default:
- break;
+ return -EINVAL;
}
-
- return -EINVAL;
}
static int gp2ap020a00f_write_event_val(struct iio_dev *indio_dev,
@@ -1023,53 +999,41 @@ static int gp2ap020a00f_write_event_val(struct iio_dev *indio_dev,
struct gp2ap020a00f_data *data = iio_priv(indio_dev);
bool event_en = false;
u8 thresh_val_id;
- u8 thresh_reg_l;
- int err = 0;
+ int thresh_reg_l;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir);
- thresh_val_id = GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l);
+ if (thresh_reg_l < 0)
+ return thresh_reg_l;
- if (thresh_val_id > GP2AP020A00F_THRESH_PH) {
- err = -EINVAL;
- goto error_unlock;
- }
+ thresh_val_id = GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l);
+ if (thresh_val_id > GP2AP020A00F_THRESH_PH)
+ return -EINVAL;
switch (thresh_reg_l) {
case GP2AP020A00F_TH_L_REG:
- event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV,
- &data->flags);
+ event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags);
break;
case GP2AP020A00F_TL_L_REG:
- event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV,
- &data->flags);
+ event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags);
break;
case GP2AP020A00F_PH_L_REG:
- if (val == 0) {
- err = -EINVAL;
- goto error_unlock;
- }
- event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV,
- &data->flags);
+ if (val == 0)
+ return -EINVAL;
+
+ event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags);
break;
case GP2AP020A00F_PL_L_REG:
- if (val == 0) {
- err = -EINVAL;
- goto error_unlock;
- }
- event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV,
- &data->flags);
+ if (val == 0)
+ return -EINVAL;
+
+ event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags);
break;
}
data->thresh_val[thresh_val_id] = val;
- err = gp2ap020a00f_write_event_threshold(data, thresh_val_id,
- event_en);
-error_unlock:
- mutex_unlock(&data->lock);
-
- return err;
+ return gp2ap020a00f_write_event_threshold(data, thresh_val_id, event_en);
}
static int gp2ap020a00f_read_event_val(struct iio_dev *indio_dev,
@@ -1080,24 +1044,19 @@ static int gp2ap020a00f_read_event_val(struct iio_dev *indio_dev,
int *val, int *val2)
{
struct gp2ap020a00f_data *data = iio_priv(indio_dev);
- u8 thresh_reg_l;
- int err = IIO_VAL_INT;
+ int thresh_reg_l;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir);
-
- if (thresh_reg_l > GP2AP020A00F_PH_L_REG) {
- err = -EINVAL;
- goto error_unlock;
- }
+ if (thresh_reg_l < 0)
+ return thresh_reg_l;
+ if (thresh_reg_l > GP2AP020A00F_PH_L_REG)
+ return -EINVAL;
*val = data->thresh_val[GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l)];
-error_unlock:
- mutex_unlock(&data->lock);
-
- return err;
+ return IIO_VAL_INT;
}
static int gp2ap020a00f_write_prox_event_config(struct iio_dev *indio_dev,
@@ -1163,32 +1122,25 @@ static int gp2ap020a00f_write_event_config(struct iio_dev *indio_dev,
{
struct gp2ap020a00f_data *data = iio_priv(indio_dev);
enum gp2ap020a00f_cmd cmd;
- int err;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (chan->type) {
case IIO_PROXIMITY:
- err = gp2ap020a00f_write_prox_event_config(indio_dev, state);
- break;
+ return gp2ap020a00f_write_prox_event_config(indio_dev, state);
case IIO_LIGHT:
if (dir == IIO_EV_DIR_RISING) {
cmd = state ? GP2AP020A00F_CMD_ALS_HIGH_EV_EN :
GP2AP020A00F_CMD_ALS_HIGH_EV_DIS;
- err = gp2ap020a00f_exec_cmd(data, cmd);
+ return gp2ap020a00f_exec_cmd(data, cmd);
} else {
cmd = state ? GP2AP020A00F_CMD_ALS_LOW_EV_EN :
GP2AP020A00F_CMD_ALS_LOW_EV_DIS;
- err = gp2ap020a00f_exec_cmd(data, cmd);
+ return gp2ap020a00f_exec_cmd(data, cmd);
}
- break;
default:
- err = -EINVAL;
+ return -EINVAL;
}
-
- mutex_unlock(&data->lock);
-
- return err;
}
static int gp2ap020a00f_read_event_config(struct iio_dev *indio_dev,
@@ -1197,40 +1149,29 @@ static int gp2ap020a00f_read_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir)
{
struct gp2ap020a00f_data *data = iio_priv(indio_dev);
- int event_en = 0;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (chan->type) {
case IIO_PROXIMITY:
if (dir == IIO_EV_DIR_RISING)
- event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV,
- &data->flags);
+ return test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags);
else
- event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV,
- &data->flags);
- break;
+ return test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags);
case IIO_LIGHT:
if (dir == IIO_EV_DIR_RISING)
- event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV,
- &data->flags);
+ return test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags);
else
- event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV,
- &data->flags);
- break;
+ return test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags);
default:
- event_en = -EINVAL;
- break;
+ return -EINVAL;
}
-
- mutex_unlock(&data->lock);
-
- return event_en;
}
static int gp2ap020a00f_read_channel(struct gp2ap020a00f_data *data,
struct iio_chan_spec const *chan, int *val)
{
+ struct device *dev = &data->client->dev;
enum gp2ap020a00f_cmd cmd;
int err;
@@ -1250,27 +1191,23 @@ static int gp2ap020a00f_read_channel(struct gp2ap020a00f_data *data,
err = gp2ap020a00f_exec_cmd(data, cmd);
if (err < 0) {
- dev_err(&data->client->dev,
- "gp2ap020a00f_exec_cmd failed\n");
- goto error_ret;
+ dev_err(dev, "gp2ap020a00f_exec_cmd failed\n");
+ return err;
}
err = gp2ap020a00f_read_output(data, chan->address, val);
if (err < 0)
- dev_err(&data->client->dev,
- "gp2ap020a00f_read_output failed\n");
+ dev_err(dev, "gp2ap020a00f_read_output failed\n");
err = gp2ap020a00f_set_operation_mode(data,
GP2AP020A00F_OPMODE_SHUTDOWN);
if (err < 0)
- dev_err(&data->client->dev,
- "Failed to shut down the device.\n");
+ dev_err(dev, "Failed to shut down the device.\n");
if (cmd == GP2AP020A00F_CMD_READ_RAW_CLEAR ||
cmd == GP2AP020A00F_CMD_READ_RAW_IR)
gp2ap020a00f_output_to_lux(data, val);
-error_ret:
return err;
}
@@ -1383,9 +1320,9 @@ static const struct iio_info gp2ap020a00f_info = {
static int gp2ap020a00f_buffer_postenable(struct iio_dev *indio_dev)
{
struct gp2ap020a00f_data *data = iio_priv(indio_dev);
- int i, err = 0;
+ int i, err;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
/*
* Enable triggers according to the scan_mask. Enabling either
@@ -1409,28 +1346,27 @@ static int gp2ap020a00f_buffer_postenable(struct iio_dev *indio_dev)
err = gp2ap020a00f_exec_cmd(data,
GP2AP020A00F_CMD_TRIGGER_PROX_EN);
break;
+ default:
+ err = -EINVAL;
+ break;
}
+ if (err)
+ return err;
}
- if (err < 0)
- goto error_unlock;
-
data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (!data->buffer)
- err = -ENOMEM;
-
-error_unlock:
- mutex_unlock(&data->lock);
+ return -ENOMEM;
- return err;
+ return 0;
}
static int gp2ap020a00f_buffer_predisable(struct iio_dev *indio_dev)
{
struct gp2ap020a00f_data *data = iio_priv(indio_dev);
- int i, err = 0;
+ int i, err;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
iio_for_each_active_channel(indio_dev, i) {
switch (i) {
@@ -1446,15 +1382,16 @@ static int gp2ap020a00f_buffer_predisable(struct iio_dev *indio_dev)
err = gp2ap020a00f_exec_cmd(data,
GP2AP020A00F_CMD_TRIGGER_PROX_DIS);
break;
+ default:
+ err = -EINVAL;
+ break;
}
+ if (err)
+ return err;
}
- if (err == 0)
- kfree(data->buffer);
-
- mutex_unlock(&data->lock);
-
- return err;
+ kfree(data->buffer);
+ return 0;
}
static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = {
@@ -1465,18 +1402,19 @@ static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = {
static int gp2ap020a00f_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ struct device *dev = &client->dev;
struct gp2ap020a00f_data *data;
struct iio_dev *indio_dev;
struct regmap *regmap;
int err;
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
- data->vled_reg = devm_regulator_get(&client->dev, "vled");
+ data->vled_reg = devm_regulator_get(dev, "vled");
if (IS_ERR(data->vled_reg))
return PTR_ERR(data->vled_reg);
@@ -1486,7 +1424,7 @@ static int gp2ap020a00f_probe(struct i2c_client *client)
regmap = devm_regmap_init_i2c(client, &gp2ap020a00f_regmap_config);
if (IS_ERR(regmap)) {
- dev_err(&client->dev, "Regmap initialization failed.\n");
+ dev_err(dev, "Regmap initialization failed.\n");
err = PTR_ERR(regmap);
goto error_regulator_disable;
}
@@ -1497,7 +1435,7 @@ static int gp2ap020a00f_probe(struct i2c_client *client)
ARRAY_SIZE(gp2ap020a00f_reg_init_tab));
if (err < 0) {
- dev_err(&client->dev, "Device initialization failed.\n");
+ dev_err(dev, "Device initialization failed.\n");
goto error_regulator_disable;
}
@@ -1522,11 +1460,10 @@ static int gp2ap020a00f_probe(struct i2c_client *client)
goto error_regulator_disable;
/* Allocate trigger */
- data->trig = devm_iio_trigger_alloc(&client->dev, "%s-trigger",
- indio_dev->name);
+ data->trig = devm_iio_trigger_alloc(dev, "%s-trigger", indio_dev->name);
if (data->trig == NULL) {
err = -ENOMEM;
- dev_err(&indio_dev->dev, "Failed to allocate iio trigger.\n");
+ dev_err(dev, "Failed to allocate iio trigger.\n");
goto error_uninit_buffer;
}
@@ -1538,7 +1475,7 @@ static int gp2ap020a00f_probe(struct i2c_client *client)
"gp2ap020a00f_als_event",
indio_dev);
if (err < 0) {
- dev_err(&client->dev, "Irq request failed.\n");
+ dev_err(dev, "Irq request failed.\n");
goto error_uninit_buffer;
}
@@ -1546,7 +1483,7 @@ static int gp2ap020a00f_probe(struct i2c_client *client)
err = iio_trigger_register(data->trig);
if (err < 0) {
- dev_err(&client->dev, "Failed to register iio trigger.\n");
+ dev_err(dev, "Failed to register iio trigger.\n");
goto error_free_irq;
}
@@ -1572,12 +1509,12 @@ static void gp2ap020a00f_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct gp2ap020a00f_data *data = iio_priv(indio_dev);
+ struct device *dev = &client->dev;
int err;
- err = gp2ap020a00f_set_operation_mode(data,
- GP2AP020A00F_OPMODE_SHUTDOWN);
+ err = gp2ap020a00f_set_operation_mode(data, GP2AP020A00F_OPMODE_SHUTDOWN);
if (err < 0)
- dev_err(&indio_dev->dev, "Failed to power off the device.\n");
+ dev_err(dev, "Failed to power off the device.\n");
iio_device_unregister(indio_dev);
iio_trigger_unregister(data->trig);
@@ -1587,10 +1524,9 @@ static void gp2ap020a00f_remove(struct i2c_client *client)
}
static const struct i2c_device_id gp2ap020a00f_id[] = {
- { GP2A_I2C_NAME },
+ { .name = "gp2ap020a00f" },
{ }
};
-
MODULE_DEVICE_TABLE(i2c, gp2ap020a00f_id);
static const struct of_device_id gp2ap020a00f_of_match[] = {
@@ -1601,14 +1537,13 @@ MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match);
static struct i2c_driver gp2ap020a00f_driver = {
.driver = {
- .name = GP2A_I2C_NAME,
+ .name = "gp2ap020a00f",
.of_match_table = gp2ap020a00f_of_match,
},
.probe = gp2ap020a00f_probe,
.remove = gp2ap020a00f_remove,
.id_table = gp2ap020a00f_id,
};
-
module_i2c_driver(gp2ap020a00f_driver);
MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index 384572844162..929343e42d83 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -3,10 +3,10 @@
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*/
+#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
@@ -33,9 +33,9 @@ struct als_state {
u32 illum[CHANNEL_SCAN_INDEX_MAX];
aligned_s64 timestamp;
} scan;
- int scale_pre_decml;
- int scale_post_decml;
- int scale_precision;
+ int scale_pre_decml[CHANNEL_SCAN_INDEX_MAX];
+ int scale_post_decml[CHANNEL_SCAN_INDEX_MAX];
+ int scale_precision[CHANNEL_SCAN_INDEX_MAX];
int value_offset;
int num_channels;
s64 timestamp;
@@ -117,22 +117,10 @@ static const struct iio_chan_spec als_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
};
-/* Adjust channel real bits based on report descriptor */
-static void als_adjust_channel_bit_mask(struct iio_chan_spec *channels,
- int channel, int size)
-{
- channels[channel].scan_type.sign = 's';
- /* Real storage bits will change based on the report desc. */
- channels[channel].scan_type.realbits = size * 8;
- /* Maximum size of a sample to capture is u32 */
- channels[channel].scan_type.storagebits = sizeof(u32) * 8;
-}
-
/* Channel read_raw handler */
static int als_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct als_state *als_state = iio_priv(indio_dev);
struct hid_sensor_hub_device *hsdev = als_state->common_attributes.hsdev;
@@ -173,12 +161,12 @@ static int als_read_raw(struct iio_dev *indio_dev,
}
if (report_id >= 0) {
hid_sensor_power_state(&als_state->common_attributes,
- true);
+ true);
*val = sensor_hub_input_attr_get_raw_value(
hsdev, hsdev->usage, address, report_id,
SENSOR_HUB_SYNC, min < 0);
hid_sensor_power_state(&als_state->common_attributes,
- false);
+ false);
} else {
*val = 0;
return -EINVAL;
@@ -186,9 +174,11 @@ static int als_read_raw(struct iio_dev *indio_dev,
ret_type = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
- *val = als_state->scale_pre_decml;
- *val2 = als_state->scale_post_decml;
- ret_type = als_state->scale_precision;
+ if (chan->scan_index >= CHANNEL_SCAN_INDEX_MAX)
+ return -EINVAL;
+ *val = als_state->scale_pre_decml[chan->scan_index];
+ *val2 = als_state->scale_post_decml[chan->scan_index];
+ ret_type = als_state->scale_precision[chan->scan_index];
break;
case IIO_CHAN_INFO_OFFSET:
*val = als_state->value_offset;
@@ -216,10 +206,8 @@ static int als_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int als_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct als_state *als_state = iio_priv(indio_dev);
int ret = 0;
@@ -251,8 +239,7 @@ static const struct iio_info als_info = {
/* Callback handler to send event after all samples are received and captured */
static int als_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct als_state *als_state = iio_priv(indio_dev);
@@ -273,9 +260,9 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct als_state *als_state = iio_priv(indio_dev);
@@ -314,9 +301,9 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int als_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- struct als_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ u32 usage_id,
+ struct als_state *st)
{
struct iio_chan_spec *channels;
int ret, index = 0;
@@ -335,9 +322,17 @@ static int als_parse_report(struct platform_device *pdev,
channels[index] = als_channels[i];
st->als_scan_mask[0] |= BIT(i);
- als_adjust_channel_bit_mask(channels, index, st->als[i].size);
+ channels[index].scan_type = (struct iio_scan_type) {
+ .format = 's',
+ .realbits = BYTES_TO_BITS(st->als[i].size),
+ .storagebits = BITS_PER_TYPE(u32),
+ };
++index;
+ st->scale_precision[i] = hid_sensor_format_scale(usage_id,
+ &st->als[i], &st->scale_pre_decml[i],
+ &st->scale_post_decml[i]);
+
dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index,
st->als[i].report_id);
}
@@ -347,10 +342,6 @@ static int als_parse_report(struct platform_device *pdev,
if (index)
ret = 0;
- st->scale_precision = hid_sensor_format_scale(usage_id,
- &st->als[CHANNEL_SCAN_INDEX_INTENSITY],
- &st->scale_pre_decml, &st->scale_post_decml);
-
return ret;
}
@@ -406,31 +397,31 @@ static int hid_als_probe(struct platform_device *pdev)
atomic_set(&als_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &als_state->common_attributes);
+ &als_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
als_state->callbacks.send_event = als_proc_event;
als_state->callbacks.capture_sample = als_capture_sample;
als_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, hsdev->usage, &als_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
return ret;
@@ -443,8 +434,8 @@ static void hid_als_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct als_state *als_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
}
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index efa904a70d0e..63fd3eff171c 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -3,10 +3,10 @@
* HID Sensors Driver
* Copyright (c) 2014, Intel Corporation.
*/
+#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
@@ -67,22 +67,10 @@ static const struct iio_chan_spec prox_channels[] = {
PROX_CHANNEL(false, 0),
};
-/* Adjust channel real bits based on report descriptor */
-static void prox_adjust_channel_bit_mask(struct iio_chan_spec *channels,
- int channel, int size)
-{
- channels[channel].scan_type.sign = 's';
- /* Real storage bits will change based on the report desc. */
- channels[channel].scan_type.realbits = size * 8;
- /* Maximum size of a sample to capture is u32 */
- channels[channel].scan_type.storagebits = sizeof(u32) * 8;
-}
-
/* Channel read_raw handler */
static int prox_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct prox_state *prox_state = iio_priv(indio_dev);
struct hid_sensor_hub_device *hsdev;
@@ -145,10 +133,8 @@ static int prox_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int prox_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct prox_state *prox_state = iio_priv(indio_dev);
int ret = 0;
@@ -176,8 +162,7 @@ static const struct iio_info prox_info = {
/* Callback handler to send event after all samples are received and captured */
static int prox_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct prox_state *prox_state = iio_priv(indio_dev);
@@ -193,9 +178,9 @@ static int prox_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct prox_state *prox_state = iio_priv(indio_dev);
@@ -228,8 +213,8 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int prox_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct prox_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct prox_state *st)
{
struct iio_chan_spec *channels = st->channels;
int index = 0;
@@ -250,8 +235,11 @@ static int prox_parse_report(struct platform_device *pdev,
st->scan_mask[0] |= BIT(index);
channels[index] = prox_channels[i];
channels[index].scan_index = index;
- prox_adjust_channel_bit_mask(channels, index,
- st->prox_attr[index].size);
+ channels[index].scan_type = (struct iio_scan_type) {
+ .format = 's',
+ .realbits = BYTES_TO_BITS(st->prox_attr[index].size),
+ .storagebits = BITS_PER_TYPE(u32),
+ };
dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr[index].index,
st->prox_attr[index].report_id);
st->scale_precision[index] =
@@ -278,8 +266,7 @@ static int hid_prox_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct prox_state *prox_state;
- indio_dev = devm_iio_device_alloc(&pdev->dev,
- sizeof(struct prox_state));
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct prox_state));
if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -313,18 +300,12 @@ static int hid_prox_probe(struct platform_device *pdev)
atomic_set(&prox_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &prox_state->common_attributes);
+ &prox_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
prox_state->callbacks.send_event = prox_proc_event;
prox_state->callbacks.capture_sample = prox_capture_sample;
prox_state->callbacks.pdev = pdev;
@@ -332,13 +313,19 @@ static int hid_prox_probe(struct platform_device *pdev)
&prox_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
return ret;
@@ -351,8 +338,8 @@ static void hid_prox_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct prox_state *prox_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
}
diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c
index b9f230210f07..cd5843e3e2c3 100644
--- a/drivers/iio/light/iqs621-als.c
+++ b/drivers/iio/light/iqs621-als.c
@@ -5,6 +5,7 @@
* Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
*/
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
@@ -107,26 +108,20 @@ static int iqs621_als_notifier(struct notifier_block *notifier,
indio_dev = iqs621_als->indio_dev;
timestamp = iio_get_time_ns(indio_dev);
- mutex_lock(&iqs621_als->lock);
+ guard(mutex)(&iqs621_als->lock);
if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
ret = iqs621_als_init(iqs621_als);
if (ret) {
dev_err(indio_dev->dev.parent,
"Failed to re-initialize device: %d\n", ret);
- ret = NOTIFY_BAD;
- } else {
- ret = NOTIFY_OK;
+ return NOTIFY_BAD;
}
-
- goto err_mutex;
+ return NOTIFY_OK;
}
- if (!iqs621_als->light_en && !iqs621_als->range_en &&
- !iqs621_als->prox_en) {
- ret = NOTIFY_DONE;
- goto err_mutex;
- }
+ if (!iqs621_als->light_en && !iqs621_als->range_en && !iqs621_als->prox_en)
+ return NOTIFY_DONE;
/* IQS621 only */
light_new = event_data->als_flags & IQS621_ALS_FLAGS_LIGHT;
@@ -181,12 +176,7 @@ static int iqs621_als_notifier(struct notifier_block *notifier,
iqs621_als->als_flags = event_data->als_flags;
iqs621_als->ir_flags = event_data->ir_flags;
- ret = NOTIFY_OK;
-
-err_mutex:
- mutex_unlock(&iqs621_als->lock);
-
- return ret;
+ return NOTIFY_OK;
}
static void iqs621_als_notifier_unregister(void *context)
@@ -241,30 +231,22 @@ static int iqs621_als_read_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir)
{
struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
- int ret;
- mutex_lock(&iqs621_als->lock);
+ guard(mutex)(&iqs621_als->lock);
switch (chan->type) {
case IIO_LIGHT:
- ret = iqs621_als->light_en;
- break;
+ return iqs621_als->light_en;
case IIO_INTENSITY:
- ret = iqs621_als->range_en;
- break;
+ return iqs621_als->range_en;
case IIO_PROXIMITY:
- ret = iqs621_als->prox_en;
- break;
+ return iqs621_als->prox_en;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
-
- mutex_unlock(&iqs621_als->lock);
-
- return ret;
}
static int iqs621_als_write_event_config(struct iio_dev *indio_dev,
@@ -278,11 +260,11 @@ static int iqs621_als_write_event_config(struct iio_dev *indio_dev,
unsigned int val;
int ret;
- mutex_lock(&iqs621_als->lock);
+ guard(mutex)(&iqs621_als->lock);
ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->als_flags, &val);
if (ret)
- goto err_mutex;
+ return ret;
iqs621_als->als_flags = val;
switch (chan->type) {
@@ -291,40 +273,41 @@ static int iqs621_als_write_event_config(struct iio_dev *indio_dev,
iqs62x->dev_desc->als_mask,
iqs621_als->range_en || state ? 0 :
0xFF);
- if (!ret)
- iqs621_als->light_en = state;
- break;
+ if (ret)
+ return ret;
+ iqs621_als->light_en = state;
+
+ return 0;
case IIO_INTENSITY:
ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
iqs62x->dev_desc->als_mask,
iqs621_als->light_en || state ? 0 :
0xFF);
- if (!ret)
- iqs621_als->range_en = state;
- break;
+ if (ret)
+ return ret;
+ iqs621_als->range_en = state;
+
+ return 0;
case IIO_PROXIMITY:
ret = regmap_read(iqs62x->regmap, IQS622_IR_FLAGS, &val);
if (ret)
- goto err_mutex;
+ return ret;
iqs621_als->ir_flags = val;
ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
iqs62x->dev_desc->ir_mask,
state ? 0 : 0xFF);
- if (!ret)
- iqs621_als->prox_en = state;
- break;
+ if (ret)
+ return ret;
+ iqs621_als->prox_en = state;
+
+ return 0;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
-
-err_mutex:
- mutex_unlock(&iqs621_als->lock);
-
- return ret;
}
static int iqs621_als_read_event_value(struct iio_dev *indio_dev,
@@ -335,33 +318,28 @@ static int iqs621_als_read_event_value(struct iio_dev *indio_dev,
int *val, int *val2)
{
struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
- int ret = IIO_VAL_INT;
- mutex_lock(&iqs621_als->lock);
+ guard(mutex)(&iqs621_als->lock);
switch (dir) {
case IIO_EV_DIR_RISING:
*val = iqs621_als->thresh_light * 16;
- break;
+ return IIO_VAL_INT;
case IIO_EV_DIR_FALLING:
*val = iqs621_als->thresh_dark * 4;
- break;
+ return IIO_VAL_INT;
case IIO_EV_DIR_EITHER:
if (iqs621_als->ir_flags_mask == IQS622_IR_FLAGS_TOUCH)
*val = iqs621_als->thresh_prox * 4;
else
*val = iqs621_als->thresh_prox;
- break;
+ return IIO_VAL_INT;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
-
- mutex_unlock(&iqs621_als->lock);
-
- return ret;
}
static int iqs621_als_write_event_value(struct iio_dev *indio_dev,
@@ -375,9 +353,9 @@ static int iqs621_als_write_event_value(struct iio_dev *indio_dev,
struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
unsigned int thresh_reg, thresh_val;
u8 ir_flags_mask, *thresh_cache;
- int ret = -EINVAL;
+ int ret;
- mutex_lock(&iqs621_als->lock);
+ guard(mutex)(&iqs621_als->lock);
switch (dir) {
case IIO_EV_DIR_RISING:
@@ -426,30 +404,27 @@ static int iqs621_als_write_event_value(struct iio_dev *indio_dev,
break;
default:
- goto err_mutex;
+ return -EINVAL;
}
thresh_cache = &iqs621_als->thresh_prox;
break;
default:
- goto err_mutex;
+ return -EINVAL;
}
if (thresh_val > 0xFF)
- goto err_mutex;
+ return -EINVAL;
ret = regmap_write(iqs62x->regmap, thresh_reg, thresh_val);
if (ret)
- goto err_mutex;
+ return ret;
*thresh_cache = thresh_val;
iqs621_als->ir_flags_mask = ir_flags_mask;
-err_mutex:
- mutex_unlock(&iqs621_als->lock);
-
- return ret;
+ return 0;
}
static const struct iio_info iqs621_als_info = {
diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c
index b6ab726d1dae..759cb71ed1c5 100644
--- a/drivers/iio/light/isl29018.c
+++ b/drivers/iio/light/isl29018.c
@@ -10,7 +10,6 @@
#include <linux/i2c.h>
#include <linux/err.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/delay.h>
@@ -829,9 +828,9 @@ static const struct acpi_device_id isl29018_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match);
static const struct i2c_device_id isl29018_id[] = {
- {"isl29018", isl29018},
- {"isl29023", isl29023},
- {"isl29035", isl29035},
+ { .name = "isl29018", .driver_data = isl29018 },
+ { .name = "isl29023", .driver_data = isl29023 },
+ { .name = "isl29035", .driver_data = isl29035 },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl29018_id);
diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c
index 374bccad9119..33deb1726689 100644
--- a/drivers/iio/light/isl29028.c
+++ b/drivers/iio/light/isl29028.c
@@ -333,16 +333,6 @@ static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
return isl29028_read_als_ir(chip, ir_data);
}
-static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on)
-{
- struct device *dev = regmap_get_device(chip->regmap);
-
- if (on)
- return pm_runtime_resume_and_get(dev);
-
- return pm_runtime_put_autosuspend(dev);
-}
-
/* Channel IO */
static int isl29028_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
@@ -352,7 +342,7 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
struct device *dev = regmap_get_device(chip->regmap);
int ret;
- ret = isl29028_set_pm_runtime_busy(chip, true);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
@@ -405,11 +395,11 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- ret = isl29028_set_pm_runtime_busy(chip, false);
+ ret = pm_runtime_put_autosuspend(dev);
if (ret < 0)
return ret;
- return ret;
+ return 0;
}
static int isl29028_read_raw(struct iio_dev *indio_dev,
@@ -420,7 +410,7 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
struct device *dev = regmap_get_device(chip->regmap);
int ret, pm_ret;
- ret = isl29028_set_pm_runtime_busy(chip, true);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
@@ -476,10 +466,10 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
/**
* Preserve the ret variable if the call to
- * isl29028_set_pm_runtime_busy() is successful so the reading
+ * pm_runtime_put_autosuspend() is successful so the reading
* (if applicable) is returned to user space.
*/
- pm_ret = isl29028_set_pm_runtime_busy(chip, false);
+ pm_ret = pm_runtime_put_autosuspend(dev);
if (pm_ret < 0)
return pm_ret;
@@ -673,8 +663,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(isl29028_pm_ops, isl29028_suspend,
isl29028_resume, NULL);
static const struct i2c_device_id isl29028_id[] = {
- { "isl29028" },
- { "isl29030" },
+ { .name = "isl29028" },
+ { .name = "isl29030" },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl29028_id);
diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c
index 3acb8a4f1d12..9e0b7e6a3ecf 100644
--- a/drivers/iio/light/isl29125.c
+++ b/drivers/iio/light/isl29125.c
@@ -325,7 +325,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend,
isl29125_resume);
static const struct i2c_device_id isl29125_id[] = {
- { "isl29125" },
+ { .name = "isl29125" },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl29125_id);
diff --git a/drivers/iio/light/isl76682.c b/drivers/iio/light/isl76682.c
index b6f2fc9978f6..9b9052d08e41 100644
--- a/drivers/iio/light/isl76682.c
+++ b/drivers/iio/light/isl76682.c
@@ -319,7 +319,7 @@ static int isl76682_probe(struct i2c_client *client)
}
static const struct i2c_device_id isl76682_id[] = {
- { "isl76682" },
+ { .name = "isl76682" },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl76682_id);
diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c
index 6978d02a4df5..038ee49723ae 100644
--- a/drivers/iio/light/jsa1212.c
+++ b/drivers/iio/light/jsa1212.c
@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
@@ -428,7 +427,7 @@ static const struct acpi_device_id jsa1212_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, jsa1212_acpi_match);
static const struct i2c_device_id jsa1212_id[] = {
- { JSA1212_DRIVER_NAME },
+ { .name = JSA1212_DRIVER_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, jsa1212_id);
diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c
index fc387426fa87..bc031f2c3141 100644
--- a/drivers/iio/light/ltr390.c
+++ b/drivers/iio/light/ltr390.c
@@ -101,7 +101,7 @@ enum ltr390_meas_rate {
struct ltr390_data {
struct regmap *regmap;
struct i2c_client *client;
- /* Protects device from simulataneous reads */
+ /* Protects device from simultaneous reads */
struct mutex lock;
enum ltr390_mode mode;
int gain;
@@ -838,8 +838,7 @@ static int ltr390_probe(struct i2c_client *client)
"ltr390_thresh_event",
indio_dev);
if (ret)
- return dev_err_probe(dev, ret,
- "request irq (%d) failed\n", client->irq);
+ return ret;
}
ret = ltr390_pm_init(data);
@@ -889,7 +888,7 @@ static const struct dev_pm_ops ltr390_pm_ops = {
};
static const struct i2c_device_id ltr390_id[] = {
- { "ltr390" },
+ { .name = "ltr390" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltr390_id);
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
index 022e0693983b..fa0d16890c8b 100644
--- a/drivers/iio/light/ltr501.c
+++ b/drivers/iio/light/ltr501.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/delay.h>
@@ -754,7 +753,7 @@ static int ltr501_get_gain_index(const struct ltr501_gain *gain, int size,
if (val == gain[i].scale && val2 == gain[i].uscale)
return i;
- return -1;
+ return -EINVAL;
}
static int __ltr501_write_raw(struct iio_dev *indio_dev,
@@ -773,7 +772,7 @@ static int __ltr501_write_raw(struct iio_dev *indio_dev,
info->als_gain_tbl_size,
val, val2);
if (i < 0)
- return -EINVAL;
+ return i;
data->als_contr &= ~info->als_gain_mask;
data->als_contr |= i << info->als_gain_shift;
@@ -785,7 +784,7 @@ static int __ltr501_write_raw(struct iio_dev *indio_dev,
info->ps_gain_tbl_size,
val, val2);
if (i < 0)
- return -EINVAL;
+ return i;
data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK;
data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT;
@@ -1538,11 +1537,8 @@ static int ltr501_probe(struct i2c_client *client)
IRQF_ONESHOT,
"ltr501_thresh_event",
indio_dev);
- if (ret) {
- dev_err(&client->dev, "request irq (%d) failed\n",
- client->irq);
+ if (ret)
return ret;
- }
} else {
indio_dev->info = data->chip_info->info_no_irq;
}
@@ -1601,10 +1597,10 @@ static const struct acpi_device_id ltr_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, ltr_acpi_match);
static const struct i2c_device_id ltr501_id[] = {
- { "ltr501", ltr501 },
- { "ltr559", ltr559 },
- { "ltr301", ltr301 },
- { "ltr303", ltr303 },
+ { .name = "ltr501", .driver_data = ltr501 },
+ { .name = "ltr559", .driver_data = ltr559 },
+ { .name = "ltr301", .driver_data = ltr301 },
+ { .name = "ltr303", .driver_data = ltr303 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltr501_id);
diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c
index 5f27f754fe1c..0a8851342039 100644
--- a/drivers/iio/light/ltrf216a.c
+++ b/drivers/iio/light/ltrf216a.c
@@ -17,7 +17,6 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/iopoll.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm.h>
@@ -248,11 +247,10 @@ static int ltrf216a_get_lux(struct ltrf216a_data *data)
return ret;
greendata = ltrf216a_read_data(data, LTRF216A_ALS_DATA_0);
+ ltrf216a_set_power_state(data, false);
if (greendata < 0)
return greendata;
- ltrf216a_set_power_state(data, false);
-
lux = greendata * data->info->lux_multiplier * LTRF216A_WIN_FAC;
return lux;
@@ -551,8 +549,8 @@ static const struct ltr_chip_info ltrf216a_chip_info = {
};
static const struct i2c_device_id ltrf216a_id[] = {
- { "ltr308", .driver_data = (kernel_ulong_t)&ltr308_chip_info },
- { "ltrf216a", .driver_data = (kernel_ulong_t)&ltrf216a_chip_info },
+ { .name = "ltr308", .driver_data = (kernel_ulong_t)&ltr308_chip_info },
+ { .name = "ltrf216a", .driver_data = (kernel_ulong_t)&ltrf216a_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltrf216a_id);
diff --git a/drivers/iio/light/lv0104cs.c b/drivers/iio/light/lv0104cs.c
index 916109ec3217..eba82c334d70 100644
--- a/drivers/iio/light/lv0104cs.c
+++ b/drivers/iio/light/lv0104cs.c
@@ -510,7 +510,7 @@ static int lv0104cs_probe(struct i2c_client *client)
}
static const struct i2c_device_id lv0104cs_id[] = {
- { "lv0104cs" },
+ { .name = "lv0104cs" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lv0104cs_id);
diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c
index 039d45af3a7f..8c344f1b3fe2 100644
--- a/drivers/iio/light/max44000.c
+++ b/drivers/iio/light/max44000.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -598,7 +597,7 @@ static int max44000_probe(struct i2c_client *client)
}
static const struct i2c_device_id max44000_id[] = {
- { "max44000" },
+ { .name = "max44000" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max44000_id);
diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c
index 8cd7f5664e5b..82b8a806c5fa 100644
--- a/drivers/iio/light/max44009.c
+++ b/drivers/iio/light/max44009.c
@@ -534,7 +534,7 @@ static const struct of_device_id max44009_of_match[] = {
MODULE_DEVICE_TABLE(of, max44009_of_match);
static const struct i2c_device_id max44009_id[] = {
- { "max44009" },
+ { .name = "max44009" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max44009_id);
diff --git a/drivers/iio/light/noa1305.c b/drivers/iio/light/noa1305.c
index 25f63da70297..6731f1d9ec1c 100644
--- a/drivers/iio/light/noa1305.c
+++ b/drivers/iio/light/noa1305.c
@@ -315,7 +315,7 @@ static const struct of_device_id noa1305_of_match[] = {
MODULE_DEVICE_TABLE(of, noa1305_of_match);
static const struct i2c_device_id noa1305_ids[] = {
- { "noa1305" },
+ { .name = "noa1305" },
{ }
};
MODULE_DEVICE_TABLE(i2c, noa1305_ids);
diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c
index 393a3d2fbe1d..a948353014ac 100644
--- a/drivers/iio/light/opt3001.c
+++ b/drivers/iio/light/opt3001.c
@@ -8,18 +8,19 @@
* Based on previous work from: Felipe Balbi <balbi@ti.com>
*/
-#include <linux/bitops.h>
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
-#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
+#include <linux/jiffies.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
-#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/wait.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
@@ -32,17 +33,16 @@
#define OPT3001_MANUFACTURER_ID 0x7e
#define OPT3001_DEVICE_ID 0x7f
-#define OPT3001_CONFIGURATION_RN_MASK (0xf << 12)
+#define OPT3001_CONFIGURATION_RN_MASK GENMASK(15, 12)
#define OPT3001_CONFIGURATION_RN_AUTO (0xc << 12)
#define OPT3001_CONFIGURATION_CT BIT(11)
-#define OPT3001_CONFIGURATION_M_MASK (3 << 9)
+#define OPT3001_CONFIGURATION_M_MASK GENMASK(10, 9)
#define OPT3001_CONFIGURATION_M_SHUTDOWN (0 << 9)
#define OPT3001_CONFIGURATION_M_SINGLE (1 << 9)
#define OPT3001_CONFIGURATION_M_CONTINUOUS (2 << 9) /* also 3 << 9 */
-#define OPT3001_CONFIGURATION_OVF BIT(8)
#define OPT3001_CONFIGURATION_CRF BIT(7)
#define OPT3001_CONFIGURATION_FH BIT(6)
#define OPT3001_CONFIGURATION_FL BIT(5)
@@ -50,7 +50,7 @@
#define OPT3001_CONFIGURATION_POL BIT(3)
#define OPT3001_CONFIGURATION_ME BIT(2)
-#define OPT3001_CONFIGURATION_FC_MASK (3 << 0)
+#define OPT3001_CONFIGURATION_FC_MASK GENMASK(1, 0)
/* The end-of-conversion enable is located in the low-limit register */
#define OPT3001_LOW_LIMIT_EOC_ENABLE 0xc000
@@ -91,7 +91,7 @@ struct opt3001_chip_info {
*/
int factor_integer;
/*
- * Factor used to align decimal part of proccessed value to six decimal
+ * Factor used to align decimal part of processed value to six decimal
* places.
*/
int factor_decimal;
@@ -101,9 +101,14 @@ struct opt3001_chip_info {
struct opt3001 {
struct i2c_client *client;
- struct device *dev;
+ /*
+ * Ensure data capture and read-modify-write sequences are
+ * not interrupted.
+ */
struct mutex lock;
+
+ /* Allows for IRQs to bypass locking mechanism */
bool ok_to_ignore_lock;
bool result_ready;
wait_queue_head_t result_ready_queue;
@@ -224,11 +229,10 @@ static const struct opt3001_scale opt3002_scales[] = {
},
};
-static int opt3001_find_scale(const struct opt3001 *opt, int val,
- int val2, u8 *exponent)
+static int opt3001_find_scale(const struct opt3001 *opt, int val, int val2,
+ u8 *exponent)
{
- int i;
- for (i = 0; i < ARRAY_SIZE(*opt->chip_info->scales); i++) {
+ for (unsigned int i = 0; i < ARRAY_SIZE(*opt->chip_info->scales); i++) {
const struct opt3001_scale *scale = &(*opt->chip_info->scales)[i];
/*
* Compare the integer and micro parts to determine value scale.
@@ -243,8 +247,8 @@ static int opt3001_find_scale(const struct opt3001 *opt, int val,
return -EINVAL;
}
-static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent,
- u16 mantissa, int *val, int *val2)
+static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent, u16 mantissa,
+ int *val, int *val2)
{
int ret;
int whole = opt->chip_info->factor_whole;
@@ -311,121 +315,143 @@ static const struct iio_chan_spec opt3002_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(1),
};
-static int opt3001_get_processed(struct opt3001 *opt, int *val, int *val2)
+static int opt3001_start_conversion(struct opt3001 *opt)
{
- int ret;
- u16 mantissa;
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
u16 reg;
- u8 exponent;
- u16 value;
- long timeout;
-
- if (opt->use_irq) {
- /*
- * Enable the end-of-conversion interrupt mechanism. Note that
- * doing so will overwrite the low-level limit value however we
- * will restore this value later on.
- */
- ret = i2c_smbus_write_word_swapped(opt->client,
- OPT3001_LOW_LIMIT,
- OPT3001_LOW_LIMIT_EOC_ENABLE);
- if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_LOW_LIMIT);
- return ret;
- }
-
- /* Allow IRQ to access the device despite lock being set */
- opt->ok_to_ignore_lock = true;
- }
+ int ret;
/* Reset data-ready indicator flag */
opt->result_ready = false;
/* Configure for single-conversion mode and start a new conversion */
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
- goto err;
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
}
reg = ret;
opt3001_set_mode(opt, &reg, OPT3001_CONFIGURATION_M_SINGLE);
- ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
- reg);
+ ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg);
+ if (ret)
+ dev_err(dev, "failed to write register %02x\n",
+ OPT3001_CONFIGURATION);
+
+ return ret;
+}
+
+static int opt3001_get_processed_irq(struct opt3001 *opt)
+{
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
+ u16 value;
+ int ret;
+
+ /*
+ * Enable the end-of-conversion interrupt mechanism. Note that doing so
+ * will overwrite the low-level limit value however we will restore this
+ * value later on.
+ */
+ ret = i2c_smbus_write_word_swapped(client,
+ OPT3001_LOW_LIMIT,
+ OPT3001_LOW_LIMIT_EOC_ENABLE);
if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_CONFIGURATION);
- goto err;
+ dev_err(dev, "failed to write register %02x\n",
+ OPT3001_LOW_LIMIT);
+ return ret;
}
- if (opt->use_irq) {
- /* Wait for the IRQ to indicate the conversion is complete */
- ret = wait_event_timeout(opt->result_ready_queue,
- opt->result_ready,
- msecs_to_jiffies(OPT3001_RESULT_READY_LONG));
- if (ret == 0)
- return -ETIMEDOUT;
- } else {
- /* Sleep for result ready time */
- timeout = (opt->int_time == OPT3001_INT_TIME_SHORT) ?
- OPT3001_RESULT_READY_SHORT : OPT3001_RESULT_READY_LONG;
- msleep(timeout);
-
- /* Check result ready flag */
- ret = i2c_smbus_read_word_swapped(opt->client,
- OPT3001_CONFIGURATION);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
- goto err;
- }
+ /* Allow IRQ to access the device despite lock being set */
+ opt->ok_to_ignore_lock = true;
- if (!(ret & OPT3001_CONFIGURATION_CRF)) {
- ret = -ETIMEDOUT;
- goto err;
- }
+ ret = opt3001_start_conversion(opt);
+ if (ret)
+ goto err;
- /* Obtain value */
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_RESULT);
- goto err;
- }
- opt->result = ret;
- opt->result_ready = true;
- }
+ if (wait_event_timeout(opt->result_ready_queue, opt->result_ready,
+ msecs_to_jiffies(OPT3001_RESULT_READY_LONG)))
+ ret = 0;
+ else
+ ret = -ETIMEDOUT;
err:
- if (opt->use_irq)
- /* Disallow IRQ to access the device while lock is active */
- opt->ok_to_ignore_lock = false;
+ opt->ok_to_ignore_lock = false;
if (ret < 0)
return ret;
- if (opt->use_irq) {
- /*
- * Disable the end-of-conversion interrupt mechanism by
- * restoring the low-level limit value (clearing
- * OPT3001_LOW_LIMIT_EOC_ENABLE). Note that selectively clearing
- * those enable bits would affect the actual limit value due to
- * bit-overlap and therefore can't be done.
- */
- value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa;
- ret = i2c_smbus_write_word_swapped(opt->client,
- OPT3001_LOW_LIMIT,
- value);
- if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_LOW_LIMIT);
- return ret;
- }
+ /*
+ * Disable the end-of-conversion interrupt mechanism by restoring the
+ * low-level limit value (clearing OPT3001_LOW_LIMIT_EOC_ENABLE). Note
+ * that selectively clearing those enable bits would affect the actual
+ * limit value due to bit-overlap and therefore can't be done.
+ */
+ value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa;
+ ret = i2c_smbus_write_word_swapped(client, OPT3001_LOW_LIMIT, value);
+ if (ret)
+ dev_err(dev, "failed to write register %02x\n",
+ OPT3001_LOW_LIMIT);
+
+ return ret;
+}
+
+static int opt3001_get_processed_noirq(struct opt3001 *opt)
+{
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
+ int ret;
+
+ ret = opt3001_start_conversion(opt);
+ if (ret)
+ return ret;
+
+ if (opt->int_time == OPT3001_INT_TIME_SHORT)
+ msleep(OPT3001_RESULT_READY_SHORT);
+ else
+ msleep(OPT3001_RESULT_READY_LONG);
+
+ /* Check result ready flag */
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
+ if (ret < 0) {
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
}
+ if (!(ret & OPT3001_CONFIGURATION_CRF))
+ return -ETIMEDOUT;
+
+ /* Obtain value */
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_RESULT);
+ if (ret < 0) {
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_RESULT);
+ return ret;
+ }
+
+ opt->result = ret;
+ opt->result_ready = true;
+
+ return 0;
+}
+
+static int opt3001_get_processed(struct opt3001 *opt, int *val, int *val2)
+{
+ u16 mantissa;
+ u8 exponent;
+ int ret;
+
+ if (opt->use_irq)
+ ret = opt3001_get_processed_irq(opt);
+ else
+ ret = opt3001_get_processed_noirq(opt);
+ if (ret)
+ return ret;
+
exponent = OPT3001_REG_EXPONENT(opt->result);
mantissa = OPT3001_REG_MANTISSA(opt->result);
@@ -444,13 +470,15 @@ static int opt3001_get_int_time(struct opt3001 *opt, int *val, int *val2)
static int opt3001_set_int_time(struct opt3001 *opt, int time)
{
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
int ret;
u16 reg;
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
return ret;
}
@@ -469,16 +497,14 @@ static int opt3001_set_int_time(struct opt3001 *opt, int time)
return -EINVAL;
}
- return i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
- reg);
+ return i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg);
}
static int opt3001_read_raw(struct iio_dev *iio,
- struct iio_chan_spec const *chan, int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct opt3001 *opt = iio_priv(iio);
- int ret;
if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
return -EBUSY;
@@ -486,31 +512,24 @@ static int opt3001_read_raw(struct iio_dev *iio,
if (chan->type != opt->chip_info->chan_type)
return -EINVAL;
- mutex_lock(&opt->lock);
+ guard(mutex)(&opt->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
- ret = opt3001_get_processed(opt, val, val2);
- break;
+ return opt3001_get_processed(opt, val, val2);
case IIO_CHAN_INFO_INT_TIME:
- ret = opt3001_get_int_time(opt, val, val2);
- break;
+ return opt3001_get_int_time(opt, val, val2);
default:
- ret = -EINVAL;
+ return -EINVAL;
}
-
- mutex_unlock(&opt->lock);
-
- return ret;
}
static int opt3001_write_raw(struct iio_dev *iio,
- struct iio_chan_spec const *chan, int val, int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct opt3001 *opt = iio_priv(iio);
- int ret;
if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
return -EBUSY;
@@ -524,47 +543,46 @@ static int opt3001_write_raw(struct iio_dev *iio,
if (val != 0)
return -EINVAL;
- mutex_lock(&opt->lock);
- ret = opt3001_set_int_time(opt, val2);
- mutex_unlock(&opt->lock);
+ guard(mutex)(&opt->lock);
- return ret;
+ return opt3001_set_int_time(opt, val2);
}
static int opt3001_read_event_value(struct iio_dev *iio,
- const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, enum iio_event_info info,
- int *val, int *val2)
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
{
struct opt3001 *opt = iio_priv(iio);
- int ret = IIO_VAL_INT_PLUS_MICRO;
- mutex_lock(&opt->lock);
+ guard(mutex)(&opt->lock);
switch (dir) {
case IIO_EV_DIR_RISING:
opt3001_to_iio_ret(opt, opt->high_thresh_exp,
- opt->high_thresh_mantissa, val, val2);
- break;
+ opt->high_thresh_mantissa, val, val2);
+ return IIO_VAL_INT_PLUS_MICRO;
case IIO_EV_DIR_FALLING:
opt3001_to_iio_ret(opt, opt->low_thresh_exp,
- opt->low_thresh_mantissa, val, val2);
- break;
+ opt->low_thresh_mantissa, val, val2);
+ return IIO_VAL_INT_PLUS_MICRO;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
-
- mutex_unlock(&opt->lock);
-
- return ret;
}
static int opt3001_write_event_value(struct iio_dev *iio,
- const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, enum iio_event_info info,
- int val, int val2)
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
{
struct opt3001 *opt = iio_priv(iio);
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
int ret;
int whole;
int integer;
@@ -579,12 +597,12 @@ static int opt3001_write_event_value(struct iio_dev *iio,
if (val < 0)
return -EINVAL;
- mutex_lock(&opt->lock);
+ guard(mutex)(&opt->lock);
ret = opt3001_find_scale(opt, val, val2, &exponent);
if (ret < 0) {
- dev_err(opt->dev, "can't find scale for %d.%06u\n", val, val2);
- goto err;
+ dev_err(dev, "can't find scale for %d.%06u\n", val, val2);
+ return ret;
}
whole = opt->chip_info->factor_whole;
@@ -607,25 +625,22 @@ static int opt3001_write_event_value(struct iio_dev *iio,
opt->low_thresh_exp = exponent;
break;
default:
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
- ret = i2c_smbus_write_word_swapped(opt->client, reg, value);
+ ret = i2c_smbus_write_word_swapped(client, reg, value);
if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n", reg);
- goto err;
+ dev_err(dev, "failed to write register %02x\n", reg);
+ return ret;
}
-err:
- mutex_unlock(&opt->lock);
-
- return ret;
+ return 0;
}
static int opt3001_read_event_config(struct iio_dev *iio,
- const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir)
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
{
struct opt3001 *opt = iio_priv(iio);
@@ -633,10 +648,14 @@ static int opt3001_read_event_config(struct iio_dev *iio,
}
static int opt3001_write_event_config(struct iio_dev *iio,
- const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, bool state)
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ bool state)
{
struct opt3001 *opt = iio_priv(iio);
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
int ret;
u16 mode;
u16 reg;
@@ -647,33 +666,29 @@ static int opt3001_write_event_config(struct iio_dev *iio,
if (!state && opt->mode == OPT3001_CONFIGURATION_M_SHUTDOWN)
return 0;
- mutex_lock(&opt->lock);
+ guard(mutex)(&opt->lock);
mode = state ? OPT3001_CONFIGURATION_M_CONTINUOUS
: OPT3001_CONFIGURATION_M_SHUTDOWN;
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
- goto err;
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
}
reg = ret;
opt3001_set_mode(opt, &reg, mode);
- ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
- reg);
+ ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg);
if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_CONFIGURATION);
- goto err;
+ dev_err(dev, "failed to write register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
}
-err:
- mutex_unlock(&opt->lock);
-
- return ret;
+ return 0;
}
static const struct iio_info opt3001_info = {
@@ -688,47 +703,69 @@ static const struct iio_info opt3001_info = {
static int opt3001_read_id(struct opt3001 *opt)
{
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
char manufacturer[2];
u16 device_id;
int ret;
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_MANUFACTURER_ID);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_MANUFACTURER_ID);
- return ret;
- }
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_MANUFACTURER_ID);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read register %02x\n",
+ OPT3001_MANUFACTURER_ID);
manufacturer[0] = ret >> 8;
manufacturer[1] = ret & 0xff;
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_DEVICE_ID);
- return ret;
- }
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_DEVICE_ID);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read register %02x\n",
+ OPT3001_DEVICE_ID);
device_id = ret;
- dev_info(opt->dev, "Found %c%c OPT%04x\n", manufacturer[0],
- manufacturer[1], device_id);
+ dev_info(dev, "Found %c%c OPT%04x\n", manufacturer[0], manufacturer[1],
+ device_id);
return 0;
}
-static int opt3001_configure(struct opt3001 *opt)
+static void opt3001_power_off(void *data)
{
+ struct opt3001 *opt = data;
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
+ u16 reg_val;
int ret;
- u16 reg;
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
- return ret;
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ return;
}
+ reg_val = ret;
+ opt3001_set_mode(opt, &reg_val, OPT3001_CONFIGURATION_M_SHUTDOWN);
+
+ ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg_val);
+ if (ret < 0)
+ dev_err(dev, "failed to write to register %02x\n",
+ OPT3001_CONFIGURATION);
+}
+
+static int opt3001_configure(struct opt3001 *opt)
+{
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
+ int ret;
+ u16 reg;
+
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+
reg = ret;
/* Enable automatic full-scale setting mode */
@@ -750,30 +787,28 @@ static int opt3001_configure(struct opt3001 *opt)
reg &= ~OPT3001_CONFIGURATION_ME;
reg &= ~OPT3001_CONFIGURATION_FC_MASK;
- ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
- reg);
- if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_CONFIGURATION);
- return ret;
- }
+ ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to write register %02x\n",
+ OPT3001_CONFIGURATION);
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_LOW_LIMIT);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_LOW_LIMIT);
- return ret;
- }
+ ret = devm_add_action_or_reset(dev, opt3001_power_off, opt);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register power off function\n");
+
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_LOW_LIMIT);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read register %02x\n",
+ OPT3001_LOW_LIMIT);
opt->low_thresh_mantissa = OPT3001_REG_MANTISSA(ret);
opt->low_thresh_exp = OPT3001_REG_EXPONENT(ret);
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_HIGH_LIMIT);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_HIGH_LIMIT);
- return ret;
- }
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_HIGH_LIMIT);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read register %02x\n",
+ OPT3001_HIGH_LIMIT);
opt->high_thresh_mantissa = OPT3001_REG_MANTISSA(ret);
opt->high_thresh_exp = OPT3001_REG_EXPONENT(ret);
@@ -785,6 +820,8 @@ static irqreturn_t opt3001_irq(int irq, void *_iio)
{
struct iio_dev *iio = _iio;
struct opt3001 *opt = iio_priv(iio);
+ struct i2c_client *client = opt->client;
+ struct device *dev = &client->dev;
int ret;
bool wake_result_ready_queue = false;
enum iio_chan_type chan_type = opt->chip_info->chan_type;
@@ -793,10 +830,10 @@ static irqreturn_t opt3001_irq(int irq, void *_iio)
if (!ok_to_ignore_lock)
mutex_lock(&opt->lock);
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
goto out;
}
@@ -804,21 +841,21 @@ static irqreturn_t opt3001_irq(int irq, void *_iio)
OPT3001_CONFIGURATION_M_CONTINUOUS) {
if (ret & OPT3001_CONFIGURATION_FH)
iio_push_event(iio,
- IIO_UNMOD_EVENT_CODE(chan_type, 0,
- IIO_EV_TYPE_THRESH,
- IIO_EV_DIR_RISING),
- iio_get_time_ns(iio));
+ IIO_UNMOD_EVENT_CODE(chan_type, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ iio_get_time_ns(iio));
if (ret & OPT3001_CONFIGURATION_FL)
iio_push_event(iio,
- IIO_UNMOD_EVENT_CODE(chan_type, 0,
- IIO_EV_TYPE_THRESH,
- IIO_EV_DIR_FALLING),
- iio_get_time_ns(iio));
+ IIO_UNMOD_EVENT_CODE(chan_type, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ iio_get_time_ns(iio));
} else if (ret & OPT3001_CONFIGURATION_CRF) {
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT);
+ ret = i2c_smbus_read_word_swapped(client, OPT3001_RESULT);
if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_RESULT);
+ dev_err(dev, "failed to read register %02x\n",
+ OPT3001_RESULT);
goto out;
}
opt->result = ret;
@@ -851,12 +888,13 @@ static int opt3001_probe(struct i2c_client *client)
opt = iio_priv(iio);
opt->client = client;
- opt->dev = dev;
opt->chip_info = i2c_get_match_data(client);
- mutex_init(&opt->lock);
+ ret = devm_mutex_init(dev, &opt->lock);
+ if (ret)
+ return ret;
+
init_waitqueue_head(&opt->result_ready_queue);
- i2c_set_clientdata(client, iio);
if (opt->chip_info->has_id) {
ret = opt3001_read_id(opt);
@@ -874,55 +912,20 @@ static int opt3001_probe(struct i2c_client *client)
iio->modes = INDIO_DIRECT_MODE;
iio->info = &opt3001_info;
- ret = devm_iio_device_register(dev, iio);
- if (ret) {
- dev_err(dev, "failed to register IIO device\n");
- return ret;
- }
-
/* Make use of INT pin only if valid IRQ no. is given */
if (irq > 0) {
- ret = request_threaded_irq(irq, NULL, opt3001_irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- "opt3001", iio);
- if (ret) {
- dev_err(dev, "failed to request IRQ #%d\n", irq);
+ ret = devm_request_threaded_irq(dev, irq, NULL, opt3001_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "opt3001", iio);
+ if (ret)
return ret;
- }
+
opt->use_irq = true;
} else {
- dev_dbg(opt->dev, "enabling interrupt-less operation\n");
- }
-
- return 0;
-}
-
-static void opt3001_remove(struct i2c_client *client)
-{
- struct iio_dev *iio = i2c_get_clientdata(client);
- struct opt3001 *opt = iio_priv(iio);
- int ret;
- u16 reg;
-
- if (opt->use_irq)
- free_irq(client->irq, iio);
-
- ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
- if (ret < 0) {
- dev_err(opt->dev, "failed to read register %02x\n",
- OPT3001_CONFIGURATION);
- return;
+ dev_dbg(dev, "enabling interrupt-less operation\n");
}
- reg = ret;
- opt3001_set_mode(opt, &reg, OPT3001_CONFIGURATION_M_SHUTDOWN);
-
- ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
- reg);
- if (ret < 0) {
- dev_err(opt->dev, "failed to write register %02x\n",
- OPT3001_CONFIGURATION);
- }
+ return devm_iio_device_register(dev, iio);
}
static const struct opt3001_chip_info opt3001_chip_information = {
@@ -948,8 +951,8 @@ static const struct opt3001_chip_info opt3002_chip_information = {
};
static const struct i2c_device_id opt3001_id[] = {
- { "opt3001", (kernel_ulong_t)&opt3001_chip_information },
- { "opt3002", (kernel_ulong_t)&opt3002_chip_information },
+ { .name = "opt3001", .driver_data = (kernel_ulong_t)&opt3001_chip_information },
+ { .name = "opt3002", .driver_data = (kernel_ulong_t)&opt3002_chip_information },
{ } /* Terminating Entry */
};
MODULE_DEVICE_TABLE(i2c, opt3001_id);
@@ -963,7 +966,6 @@ MODULE_DEVICE_TABLE(of, opt3001_of_match);
static struct i2c_driver opt3001_driver = {
.probe = opt3001_probe,
- .remove = opt3001_remove,
.id_table = opt3001_id,
.driver = {
diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c
index 95167273bb90..aa3d87995b7c 100644
--- a/drivers/iio/light/opt4001.c
+++ b/drivers/iio/light/opt4001.c
@@ -39,7 +39,7 @@
#define OPT4001_CTRL_OPER_MODE_MASK GENMASK(5, 4)
#define OPT4001_CTRL_LATCH_MASK GENMASK(3, 3)
#define OPT4001_CTRL_INT_POL_MASK GENMASK(2, 2)
-#define OPT4001_CTRL_FAULT_COUNT GENMASK(0, 1)
+#define OPT4001_CTRL_FAULT_COUNT_MASK GENMASK(1, 0)
/* OPT4001 constants */
#define OPT4001_DEVICE_ID_VAL 0x121
@@ -173,6 +173,7 @@ static int opt4001_read_lux_value(struct iio_dev *indio_dev,
u8 crc;
u8 calc_crc;
u64 lux_raw;
+ u32 rem;
int ret;
ret = regmap_read(chip->regmap, OPT4001_LIGHT1_MSB, &light1);
@@ -199,8 +200,8 @@ static int opt4001_read_lux_value(struct iio_dev *indio_dev,
lux_raw = lux_raw << exp;
lux_raw = lux_raw * chip->chip_info->mul;
- *val = div_u64_rem(lux_raw, chip->chip_info->div, val2);
- *val2 = *val2 * 100;
+ *val = div_u64_rem(lux_raw, chip->chip_info->div, &rem);
+ *val2 = rem * 100;
return IIO_VAL_INT_PLUS_NANO;
}
@@ -222,33 +223,14 @@ static int opt4001_set_conf(struct opt4001_chip *chip)
return ret;
}
-static int opt4001_power_down(struct opt4001_chip *chip)
-{
- struct device *dev = &chip->client->dev;
- int ret;
- unsigned int reg;
-
- ret = regmap_read(chip->regmap, OPT4001_DEVICE_ID, &reg);
- if (ret) {
- dev_err(dev, "Failed to read configuration\n");
- return ret;
- }
-
- /* MODE_OFF is 0x0 so just set bits to 0 */
- reg &= ~OPT4001_CTRL_OPER_MODE_MASK;
-
- ret = regmap_write(chip->regmap, OPT4001_CTRL, reg);
- if (ret)
- dev_err(dev, "Failed to set configuration to power down\n");
-
- return ret;
-}
-
static void opt4001_chip_off_action(void *data)
{
struct opt4001_chip *chip = data;
+ int ret;
- opt4001_power_down(chip);
+ ret = regmap_clear_bits(chip->regmap, OPT4001_CTRL, OPT4001_CTRL_OPER_MODE_MASK);
+ if (ret)
+ dev_err(&chip->client->dev, "Failed to power down\n");
}
static const struct iio_chan_spec opt4001_channels[] = {
@@ -287,6 +269,9 @@ static int opt4001_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
+ if (val)
+ return -EINVAL;
+
int_time = opt4001_als_time_to_index(val2);
if (int_time < 0)
return int_time;
@@ -438,8 +423,8 @@ static int opt4001_probe(struct i2c_client *client)
* opt4001 packaging
*/
static const struct i2c_device_id opt4001_id[] = {
- { "opt4001-sot-5x3", (kernel_ulong_t)&opt4001_sot_5x3_info },
- { "opt4001-picostar", (kernel_ulong_t)&opt4001_picostar_info },
+ { .name = "opt4001-sot-5x3", .driver_data = (kernel_ulong_t)&opt4001_sot_5x3_info },
+ { .name = "opt4001-picostar", .driver_data = (kernel_ulong_t)&opt4001_picostar_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, opt4001_id);
diff --git a/drivers/iio/light/opt4060.c b/drivers/iio/light/opt4060.c
index d6e915ab355d..8253a6a8bee4 100644
--- a/drivers/iio/light/opt4060.c
+++ b/drivers/iio/light/opt4060.c
@@ -632,6 +632,9 @@ static int opt4060_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
+ if (val)
+ return -EINVAL;
+
int_time = opt4060_als_time_to_index(val2);
if (int_time < 0)
return int_time;
@@ -710,6 +713,7 @@ static ssize_t opt4060_read_ev_period(struct opt4060_chip *chip, int *val,
{
int ret, pers, fault_count, int_time;
u64 uval;
+ u32 rem;
int_time = opt4060_int_time_reg[chip->int_time][0];
@@ -735,7 +739,8 @@ static ssize_t opt4060_read_ev_period(struct opt4060_chip *chip, int *val,
}
uval = mul_u32_u32(int_time, pers);
- *val = div_u64_rem(uval, MICRO, val2);
+ *val = div_u64_rem(uval, MICRO, &rem);
+ *val2 = rem;
return IIO_VAL_INT_PLUS_MICRO;
}
@@ -805,7 +810,7 @@ static int opt4060_get_thresholds(struct opt4060_chip *chip, u32 *th_lo, u32 *th
ret = regmap_read(chip->regmap, OPT4060_THRESHOLD_HIGH, &regval);
if (ret) {
- dev_err(chip->dev, "Failed to read THRESHOLD_LOW.\n");
+ dev_err(chip->dev, "Failed to read THRESHOLD_HIGH.\n");
return ret;
}
*th_hi = opt4060_calc_val_from_th_reg(regval);
@@ -1200,7 +1205,7 @@ static int opt4060_setup_trigger(struct opt4060_chip *chip, struct iio_dev *idev
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
name, idev);
if (ret)
- return dev_err_probe(chip->dev, ret, "Could not request IRQ\n");
+ return ret;
init_completion(&chip->completion);
@@ -1297,7 +1302,7 @@ static int opt4060_probe(struct i2c_client *client)
}
static const struct i2c_device_id opt4060_id[] = {
- { "opt4060", },
+ { .name = "opt4060" },
{ }
};
MODULE_DEVICE_TABLE(i2c, opt4060_id);
diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c
index 98a1f1624c75..c0f4db8d95f7 100644
--- a/drivers/iio/light/pa12203001.c
+++ b/drivers/iio/light/pa12203001.c
@@ -457,7 +457,7 @@ static const struct acpi_device_id pa12203001_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match);
static const struct i2c_device_id pa12203001_id[] = {
- { "txcpa122" },
+ { .name = "txcpa122" },
{ }
};
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index 9341c1d58cbe..7d82efc31f3a 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/i2c.h>
@@ -988,11 +987,8 @@ static int rpr0521_probe(struct i2c_client *client)
rpr0521_drdy_irq_handler, rpr0521_drdy_irq_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"rpr0521_event", indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "request irq %d for trigger0 failed\n",
- client->irq);
+ if (ret)
goto err_pm_disable;
- }
ret = devm_iio_trigger_register(indio_dev->dev.parent,
data->drdy_trigger0);
@@ -1072,7 +1068,10 @@ static int rpr0521_runtime_resume(struct device *dev)
struct rpr0521_data *data = iio_priv(indio_dev);
int ret;
- regcache_sync(data->regmap);
+ ret = regcache_sync(data->regmap);
+ if (ret < 0)
+ return ret;
+
if (data->als_ps_need_en) {
ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
if (ret < 0)
@@ -1102,7 +1101,7 @@ static const struct acpi_device_id rpr0521_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rpr0521_acpi_match);
static const struct i2c_device_id rpr0521_id[] = {
- { "rpr0521" },
+ { .name = "rpr0521" },
{ }
};
diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c
index 44fa152dbd24..22073ded8081 100644
--- a/drivers/iio/light/si1133.c
+++ b/drivers/iio/light/si1133.c
@@ -6,19 +6,27 @@
* Copyright 2018 Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>
*/
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/completion.h>
#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/math.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+#include <linux/util_macros.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/util_macros.h>
-
-#include <linux/unaligned.h>
-
#define SI1133_REG_PART_ID 0x00
#define SI1133_REG_REV_ID 0x01
#define SI1133_REG_MFR_ID 0x02
@@ -50,23 +58,23 @@
#define SI1133_MAX_CMD_CTR 0xF
#define SI1133_PARAM_REG_CHAN_LIST 0x01
-#define SI1133_PARAM_REG_ADCCONFIG(x) ((x) * 4) + 2
-#define SI1133_PARAM_REG_ADCSENS(x) ((x) * 4) + 3
-#define SI1133_PARAM_REG_ADCPOST(x) ((x) * 4) + 4
+#define SI1133_PARAM_REG_ADCCONFIG(x) (((x) * 4) + 2)
+#define SI1133_PARAM_REG_ADCSENS(x) (((x) * 4) + 3)
+#define SI1133_PARAM_REG_ADCPOST(x) (((x) * 4) + 4)
#define SI1133_ADCMUX_MASK 0x1F
-#define SI1133_ADCCONFIG_DECIM_RATE(x) (x) << 5
+#define SI1133_ADCCONFIG_DECIM_RATE(x) ((x) << 5)
#define SI1133_ADCSENS_SCALE_MASK 0x70
#define SI1133_ADCSENS_SCALE_SHIFT 4
#define SI1133_ADCSENS_HSIG_MASK BIT(7)
#define SI1133_ADCSENS_HSIG_SHIFT 7
#define SI1133_ADCSENS_HW_GAIN_MASK 0xF
-#define SI1133_ADCSENS_NB_MEAS(x) fls(x) << SI1133_ADCSENS_SCALE_SHIFT
+#define SI1133_ADCSENS_NB_MEAS(x) (fls(x) << SI1133_ADCSENS_SCALE_SHIFT)
#define SI1133_ADCPOST_24BIT_EN BIT(6)
-#define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (x & GENMASK(2, 0)) << 3
+#define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (((x) & GENMASK(2, 0)) << 3)
#define SI1133_PARAM_ADCMUX_SMALL_IR 0x0
#define SI1133_PARAM_ADCMUX_MED_IR 0x1
@@ -86,16 +94,12 @@
#define SI1133_CMD_MINSLEEP_US_LOW 5000
#define SI1133_CMD_MINSLEEP_US_HIGH 7500
#define SI1133_CMD_TIMEOUT_MS 25
-#define SI1133_CMD_LUX_TIMEOUT_MS 5000
-#define SI1133_CMD_TIMEOUT_US SI1133_CMD_TIMEOUT_MS * 1000
-#define SI1133_REG_HOSTOUT(x) (x) + 0x13
-
-#define SI1133_MEASUREMENT_FREQUENCY 1250
+#define SI1133_REG_HOSTOUT(x) ((x) + 0x13)
#define SI1133_X_ORDER_MASK 0x0070
#define SI1133_Y_ORDER_MASK 0x0007
-#define si1133_get_x_order(m) ((m) & SI1133_X_ORDER_MASK) >> 4
+#define si1133_get_x_order(m) (((m) & SI1133_X_ORDER_MASK) >> 4)
#define si1133_get_y_order(m) ((m) & SI1133_Y_ORDER_MASK)
#define SI1133_LUX_ADC_MASK 0xE
@@ -386,35 +390,42 @@ static int si1133_cmd_reset_counter(struct si1133_data *data)
static int si1133_command(struct si1133_data *data, u8 cmd)
{
+ unsigned long timeout;
struct device *dev = &data->client->dev;
u32 resp;
int err;
int expected_seq;
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
expected_seq = (data->rsp_seq + 1) & SI1133_MAX_CMD_CTR;
- if (cmd == SI1133_CMD_FORCE)
+ if (cmd == SI1133_CMD_FORCE) {
+ /* Flush pending IRQs from a previous timeout. */
+ regmap_read(data->regmap, SI1133_REG_IRQ_STATUS, &resp);
+ regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE,
+ SI1133_IRQ_CHANNEL_ENABLE);
+
reinit_completion(&data->completion);
+ }
err = regmap_write(data->regmap, SI1133_REG_COMMAND, cmd);
if (err) {
dev_warn(dev, "Failed to write command 0x%02x, ret=%d\n", cmd,
err);
- goto out;
+ return err;
}
if (cmd == SI1133_CMD_FORCE) {
/* wait for irq */
- if (!wait_for_completion_timeout(&data->completion,
- msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS))) {
- err = -ETIMEDOUT;
- goto out;
+ timeout = msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS);
+ if (!wait_for_completion_timeout(&data->completion, timeout)) {
+ regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE, 0);
+ return -ETIMEDOUT;
}
err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp);
if (err)
- goto out;
+ return err;
} else {
err = regmap_read_poll_timeout(data->regmap,
SI1133_REG_RESPONSE0, resp,
@@ -427,7 +438,12 @@ static int si1133_command(struct si1133_data *data, u8 cmd)
dev_warn(dev,
"Failed to read command 0x%02x, ret=%d\n",
cmd, err);
- goto out;
+ /*
+ * Reset counter on err to prevent software and hardware
+ * counters being out of sync.
+ */
+ si1133_cmd_reset_counter(data);
+ return err;
}
}
@@ -438,9 +454,6 @@ static int si1133_command(struct si1133_data *data, u8 cmd)
data->rsp_seq = expected_seq;
}
-out:
- mutex_unlock(&data->mutex);
-
return err;
}
@@ -1055,7 +1068,7 @@ static int si1133_probe(struct i2c_client *client)
}
static const struct i2c_device_id si1133_ids[] = {
- { "si1133" },
+ { .name = "si1133" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si1133_ids);
diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c
index ef0abc4499b7..bb7c99041819 100644
--- a/drivers/iio/light/si1145.c
+++ b/drivers/iio/light/si1145.c
@@ -1251,10 +1251,8 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev)
IRQF_TRIGGER_FALLING | IRQF_NO_THREAD,
"si1145_irq",
trig);
- if (ret < 0) {
- dev_err(&client->dev, "irq request failed\n");
+ if (ret)
return ret;
- }
ret = devm_iio_trigger_register(&client->dev, trig);
if (ret)
@@ -1334,13 +1332,13 @@ static int si1145_probe(struct i2c_client *client)
}
static const struct i2c_device_id si1145_ids[] = {
- { "si1132", SI1132 },
- { "si1141", SI1141 },
- { "si1142", SI1142 },
- { "si1143", SI1143 },
- { "si1145", SI1145 },
- { "si1146", SI1146 },
- { "si1147", SI1147 },
+ { .name = "si1132", .driver_data = SI1132 },
+ { .name = "si1141", .driver_data = SI1141 },
+ { .name = "si1142", .driver_data = SI1142 },
+ { .name = "si1143", .driver_data = SI1143 },
+ { .name = "si1145", .driver_data = SI1145 },
+ { .name = "si1146", .driver_data = SI1146 },
+ { .name = "si1147", .driver_data = SI1147 },
{ }
};
MODULE_DEVICE_TABLE(i2c, si1145_ids);
diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c
index bcd729a9924e..94d5261b2663 100644
--- a/drivers/iio/light/st_uvis25_core.c
+++ b/drivers/iio/light/st_uvis25_core.c
@@ -196,11 +196,8 @@ static int st_uvis25_allocate_trigger(struct iio_dev *iio_dev)
st_uvis25_trigger_handler_thread,
irq_type | IRQF_ONESHOT,
iio_dev->name, hw);
- if (err) {
- dev_err(dev, "failed to request trigger irq %d\n",
- hw->irq);
+ if (err)
return err;
- }
hw->trig = devm_iio_trigger_alloc(dev, "%s-trigger",
iio_dev->name);
diff --git a/drivers/iio/light/st_uvis25_i2c.c b/drivers/iio/light/st_uvis25_i2c.c
index 5d9bb4d9be63..d6b5ba139dd4 100644
--- a/drivers/iio/light/st_uvis25_i2c.c
+++ b/drivers/iio/light/st_uvis25_i2c.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@@ -46,7 +45,7 @@ static const struct of_device_id st_uvis25_i2c_of_match[] = {
MODULE_DEVICE_TABLE(of, st_uvis25_i2c_of_match);
static const struct i2c_device_id st_uvis25_i2c_id_table[] = {
- { ST_UVIS25_DEV_NAME },
+ { .name = ST_UVIS25_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, st_uvis25_i2c_id_table);
diff --git a/drivers/iio/light/st_uvis25_spi.c b/drivers/iio/light/st_uvis25_spi.c
index a5aad74ce73e..0f78a0abfafb 100644
--- a/drivers/iio/light/st_uvis25_spi.c
+++ b/drivers/iio/light/st_uvis25_spi.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@@ -47,7 +46,7 @@ static const struct of_device_id st_uvis25_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, st_uvis25_spi_of_match);
static const struct spi_device_id st_uvis25_spi_id_table[] = {
- { ST_UVIS25_DEV_NAME },
+ { .name = ST_UVIS25_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(spi, st_uvis25_spi_id_table);
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index a75a83594a7e..7c8a1d2b2ed0 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -7,15 +7,27 @@
* IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48.
*/
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/property.h>
#include <linux/regmap.h>
+#include <linux/sprintf.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
+#include <linux/iio/types.h>
+
+#include <asm/byteorder.h>
#define STK3310_REG_STATE 0x00
#define STK3310_REG_PSCTRL 0x01
@@ -115,9 +127,6 @@ static const int stk3310_it_table[][2] = {
struct stk3310_data {
struct i2c_client *client;
struct mutex lock;
- bool als_enabled;
- bool ps_enabled;
- uint32_t ps_near_level;
u64 timestamp;
struct regmap *regmap;
struct regmap_field *reg_state;
@@ -128,6 +137,12 @@ struct stk3310_data {
struct regmap_field *reg_int_ps;
struct regmap_field *reg_flag_psint;
struct regmap_field *reg_flag_nf;
+ u32 ps_thdl;
+ u32 ps_thdh;
+ u32 ps_near_level;
+ bool als_enabled;
+ bool ps_enabled;
+ bool ps_int_enabled;
};
static const struct iio_event_spec stk3310_events[] = {
@@ -255,7 +270,7 @@ static int stk3310_read_event(struct iio_dev *indio_dev,
return -EINVAL;
mutex_lock(&data->lock);
- ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
+ ret = regmap_bulk_read(data->regmap, reg, &buf, sizeof(buf));
mutex_unlock(&data->lock);
if (ret < 0) {
dev_err(&data->client->dev, "register read failed\n");
@@ -295,11 +310,18 @@ static int stk3310_write_event(struct iio_dev *indio_dev,
return -EINVAL;
buf = cpu_to_be16(val);
- ret = regmap_bulk_write(data->regmap, reg, &buf, 2);
- if (ret < 0)
+ ret = regmap_bulk_write(data->regmap, reg, &buf, sizeof(buf));
+ if (ret < 0) {
dev_err(&client->dev, "failed to set PS threshold!\n");
+ return ret;
+ }
- return ret;
+ if (reg == STK3310_REG_THDH_PS)
+ data->ps_thdh = val;
+ else
+ data->ps_thdl = val;
+
+ return 0;
}
static int stk3310_read_event_config(struct iio_dev *indio_dev,
@@ -331,11 +353,17 @@ static int stk3310_write_event_config(struct iio_dev *indio_dev,
/* Set INT_PS value */
mutex_lock(&data->lock);
ret = regmap_field_write(data->reg_int_ps, state);
- if (ret < 0)
+ if (ret < 0) {
dev_err(&client->dev, "failed to set interrupt mode\n");
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ data->ps_int_enabled = state;
+
mutex_unlock(&data->lock);
- return ret;
+ return 0;
}
static int stk3310_read_raw(struct iio_dev *indio_dev,
@@ -360,7 +388,7 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
reg = STK3310_REG_PS_DATA_MSB;
mutex_lock(&data->lock);
- ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
+ ret = regmap_bulk_read(data->regmap, reg, &buf, sizeof(buf));
if (ret < 0) {
dev_err(&client->dev, "register read failed\n");
mutex_unlock(&data->lock);
@@ -504,10 +532,15 @@ static int stk3310_init(struct iio_dev *indio_dev)
/* Enable PS interrupts */
ret = regmap_field_write(data->reg_int_ps, STK3310_PSINT_EN);
- if (ret < 0)
+ if (ret < 0) {
dev_err(&client->dev, "failed to enable interrupts!\n");
+ return ret;
+ }
- return ret;
+ data->ps_int_enabled = true;
+ data->ps_thdh = STK3310_PS_MAX_VAL;
+
+ return 0;
}
static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg)
@@ -640,11 +673,8 @@ static int stk3310_probe(struct i2c_client *client)
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"stk3310_event", indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "request irq %d failed\n",
- client->irq);
+ if (ret)
goto err_standby;
- }
}
ret = iio_device_register(indio_dev);
@@ -671,9 +701,18 @@ static void stk3310_remove(struct i2c_client *client)
static int stk3310_suspend(struct device *dev)
{
struct stk3310_data *data;
+ int ret;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+ if (data->ps_int_enabled) {
+ ret = regmap_field_write(data->reg_int_ps, 0x0);
+ if (ret < 0) {
+ dev_err(dev, "failed to disable ps int at suspend.\n");
+ return ret;
+ }
+ }
+
return stk3310_set_state(data, STK3310_STATE_STANDBY);
}
@@ -681,6 +720,8 @@ static int stk3310_resume(struct device *dev)
{
u8 state = 0;
struct stk3310_data *data;
+ __be16 buf;
+ int ret;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
if (data->ps_enabled)
@@ -688,17 +729,47 @@ static int stk3310_resume(struct device *dev)
if (data->als_enabled)
state |= STK3310_STATE_EN_ALS;
- return stk3310_set_state(data, state);
+ ret = stk3310_set_state(data, state);
+ if (ret < 0)
+ return ret;
+
+ if (data->ps_thdl != 0x0) {
+ buf = cpu_to_be16(data->ps_thdl);
+ ret = regmap_bulk_write(data->regmap, STK3310_REG_THDL_PS, &buf, sizeof(buf));
+ if (ret < 0) {
+ dev_err(dev, "failed to set reg THDL_PS at resume.\n");
+ return ret;
+ }
+ }
+
+ if (data->ps_thdh != STK3310_PS_MAX_VAL) {
+ buf = cpu_to_be16(data->ps_thdh);
+ ret = regmap_bulk_write(data->regmap, STK3310_REG_THDH_PS, &buf, sizeof(buf));
+ if (ret < 0) {
+ dev_err(dev, "failed to set reg THDH_PS at resume.\n");
+ return ret;
+ }
+ }
+
+ if (data->ps_int_enabled) {
+ ret = regmap_field_write(data->reg_int_ps, STK3310_PSINT_EN);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable ps int at resume.\n");
+ return ret;
+ }
+ }
+
+ return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend,
stk3310_resume);
static const struct i2c_device_id stk3310_i2c_id[] = {
- { "STK3013" },
- { "STK3310" },
- { "STK3311" },
- { "STK3335" },
+ { .name = "STK3013" },
+ { .name = "STK3310" },
+ { .name = "STK3311" },
+ { .name = "STK3335" },
{ }
};
MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c
index 5be461e6dbdb..458178fb629f 100644
--- a/drivers/iio/light/tcs3414.c
+++ b/drivers/iio/light/tcs3414.c
@@ -362,7 +362,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend,
tcs3414_resume);
static const struct i2c_device_id tcs3414_id[] = {
- { "tcs3414" },
+ { .name = "tcs3414" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tcs3414_id);
diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c
index 12429a3261b3..b392943e51c8 100644
--- a/drivers/iio/light/tcs3472.c
+++ b/drivers/iio/light/tcs3472.c
@@ -9,20 +9,21 @@
* TCS34727)
*
* Datasheet: http://ams.com/eng/content/download/319364/1117183/file/TCS3472_Datasheet_EN_v2.pdf
- *
- * TODO: wait time
*/
-#include <linux/module.h>
-#include <linux/i2c.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/pm.h>
+#include <linux/units.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
#include <linux/iio/trigger_consumer.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#define TCS3472_DRV_NAME "tcs3472"
@@ -51,19 +52,30 @@
#define TCS3472_STATUS_AINT BIT(4)
#define TCS3472_STATUS_AVALID BIT(0)
#define TCS3472_ENABLE_AIEN BIT(4)
+#define TCS3472_ENABLE_WEN BIT(3)
#define TCS3472_ENABLE_AEN BIT(1)
#define TCS3472_ENABLE_PON BIT(0)
+#define TCS3472_ENABLE_RUN \
+ (TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON | TCS3472_ENABLE_WEN)
#define TCS3472_CONTROL_AGAIN_MASK (BIT(0) | BIT(1))
+#define TCS3472_CONFIG_WLONG BIT(1)
+
+#define TCS3472_ATIME_TO_US(atime) (((256) - (atime)) * 2400)
struct tcs3472_data {
struct i2c_client *client;
struct mutex lock;
+ int target_freq_hz;
+ int target_freq_uhz;
u16 low_thresh;
u16 high_thresh;
u8 enable;
+ u8 enable_pre_suspend;
u8 control;
u8 atime;
u8 apers;
+ u8 wtime;
+ bool wlong;
};
static const struct iio_event_spec tcs3472_events[] = {
@@ -89,6 +101,7 @@ static const struct iio_event_spec tcs3472_events[] = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBSCALE) | \
BIT(IIO_CHAN_INFO_INT_TIME), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.channel2 = IIO_MOD_LIGHT_##_color, \
.address = _addr, \
.scan_index = _si, \
@@ -112,9 +125,65 @@ static const struct iio_chan_spec tcs3472_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(4),
};
+/*
+ * The chip's cycle time is the sum of three components:
+ * - ATIME: the programmable RGBC integration time.
+ * - The fixed RGBC initialization time (2400 us).
+ * - WTIME: the wait time, used only if WEN is set. If WLONG is active,
+ * the wait step is multiplied by 12 (2400 us -> 28800 us).
+ */
+static unsigned int tcs3472_cycle_time_us(struct tcs3472_data *data)
+{
+ unsigned int atime_us = TCS3472_ATIME_TO_US(data->atime);
+ unsigned int init_us = 2400;
+ unsigned int wtime_us;
+
+ if (!(data->enable & TCS3472_ENABLE_WEN))
+ wtime_us = 0;
+ else if (data->wlong)
+ wtime_us = (256 - data->wtime) * 28800;
+ else
+ wtime_us = (256 - data->wtime) * 2400;
+
+ return atime_us + init_us + wtime_us;
+}
+
+/*
+ * Convert a cycle time in microseconds to a frequency in Hz and microhertz.
+ *
+ * Given cycle_us = T (the cycle period in microseconds), the corresponding
+ * frequency is:
+ * f = 1e6 / T [Hz]
+ *
+ * The result is split into the IIO_VAL_INT_PLUS_MICRO format:
+ * val = floor(1e6 / T) [Hz]
+ * val2 = (1e6 mod T) * 1e6 / T [microhertz]
+ */
+static void tcs3472_cycle_to_freq(unsigned int cycle_us, int *val, int *val2)
+{
+ *val = USEC_PER_SEC / cycle_us;
+ *val2 = div_u64((u64)(USEC_PER_SEC % cycle_us) * USEC_PER_SEC,
+ cycle_us);
+}
+
static int tcs3472_req_data(struct tcs3472_data *data)
{
- int tries = 50;
+ /*
+ * The worst-case cycle time is reached with ATIME=0x00, WTIME=0x00
+ * and WLONG=1. So:
+ * 614 ms (Max Integration Time)
+ * + 2.4 ms (RGBC Init)
+ * + 7.37 s (Max Wait Time)
+ * = ~ 8 s (Total Max cycle time).
+ * Use that as a polling upper bound; in normal operation the loop
+ * exits as soon as AVALID is set. So the total number of tries in 8
+ * seconds considering a polling period of 20 ms is 400.
+ * Considering a 20% margin due to oscillator tolerance, the total
+ * duration becomes approximately 9.8 seconds, which corresponds to
+ * about 480 steps. Therefore, setting it to 500 appears to be a
+ * reasonable and safe trade-off.
+ */
+ int tries = 500;
int ret;
while (tries--) {
@@ -162,10 +231,157 @@ static int tcs3472_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
*val = 0;
- *val2 = (256 - data->atime) * 2400;
+ *val2 = TCS3472_ATIME_TO_US(data->atime);
return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ unsigned int cycle_us;
+
+ guard(mutex)(&data->lock);
+ cycle_us = tcs3472_cycle_time_us(data);
+ tcs3472_cycle_to_freq(cycle_us, val, val2);
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+ default:
+ return -EINVAL;
}
- return -EINVAL;
+}
+
+/*
+ * __tcs3472_set_sampling_freq() - implementation of sampling frequency
+ * configuration. The caller must hold data->lock.
+ */
+static int __tcs3472_set_sampling_freq(struct tcs3472_data *data,
+ int val, int val2)
+{
+ unsigned int atime_us;
+ unsigned int init_us = 2400;
+ u64 cycle_us;
+ s64 wait_us;
+ int wtime;
+ bool wlong = false;
+ u8 config;
+ int ret;
+
+ if (val < 0 || val2 < 0 || (val == 0 && val2 == 0))
+ return -EINVAL;
+
+ atime_us = TCS3472_ATIME_TO_US(data->atime);
+
+ /*
+ * cycle_us = 1 / freq, expressed in microseconds.
+ * Numerator: 1 [s] = PSEC_PER_SEC [ps]
+ * Denominator: freq [Hz] * MICROHZ_PER_HZ + val2 [uHz] = freq in [uHz]
+ * Result: ps / uHz = us
+ */
+ cycle_us = div64_u64(PSEC_PER_SEC, (u64)val * MICROHZ_PER_HZ + val2);
+
+ /*
+ * wait_us can be negative when the requested frequency is too high
+ * to be reached, or very large when the requested frequency is
+ * close to zero. Use s64 to cover the full range:
+ *
+ * cycle_us = PSEC_PER_SEC / (val * MICROHZ_PER_HZ + val2)
+ *
+ * The divisor of the formula above reaches its maximum when
+ * val = val2 = INT_MAX:
+ * INT_MAX * MICROHZ_PER_HZ + INT_MAX = ~2.15e18
+ * so cycle_us_min = floor(1e12 / 2.15e18) = 0.
+ *
+ * The divisor reaches its minimum (1) when val = 0 and val2 = 1,
+ * so cycle_us_max = 1e12 / 1 = 1e12.
+ *
+ * Therefore:
+ * wait_us_min = 0 - 2400 - 612000 = -616800
+ * wait_us_max = 1e12 - 2400 - 2400 = 999999995200
+ *
+ * Both fit comfortably in s64.
+ */
+ wait_us = (s64)cycle_us - init_us - atime_us;
+ if (wait_us < 2400) {
+ if (data->enable & TCS3472_ENABLE_WEN) {
+ u8 enable = data->enable & ~TCS3472_ENABLE_WEN;
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ TCS3472_ENABLE, enable);
+ if (ret)
+ return ret;
+
+ data->enable = enable;
+ }
+
+ data->target_freq_hz = val;
+ data->target_freq_uhz = val2;
+ return 0;
+ }
+
+ /*
+ * Wait state is needed: make sure WEN is active before programming
+ * WTIME (and possibly WLONG).
+ */
+ if (!(data->enable & TCS3472_ENABLE_WEN)) {
+ u8 enable = data->enable | TCS3472_ENABLE_WEN;
+
+ ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE,
+ enable);
+ if (ret)
+ return ret;
+
+ data->enable = enable;
+ }
+
+ wtime = 256 - DIV_ROUND_CLOSEST_ULL(wait_us, 2400);
+ if (wtime < 0) {
+ /*
+ * If wait_us is too high (so the requested frequency is too
+ * low), the resulting wait exceeds what WTIME can represent
+ * (max 614 ms without WLONG). Enable WLONG, whose step is 12x
+ * longer (28.8 ms instead of 2.4 ms), and recompute.
+ */
+ wlong = true;
+ wtime = 256 - DIV_ROUND_CLOSEST_ULL(wait_us, 28800);
+ }
+
+ if (wlong != data->wlong) {
+ ret = i2c_smbus_read_byte_data(data->client, TCS3472_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ config = ret;
+ if (wlong)
+ config |= TCS3472_CONFIG_WLONG;
+ else
+ config &= ~TCS3472_CONFIG_WLONG;
+
+ ret = i2c_smbus_write_byte_data(data->client, TCS3472_CONFIG,
+ config);
+ if (ret)
+ return ret;
+
+ data->wlong = wlong;
+ }
+
+ /*
+ * If the requested wait is so long that even WLONG cannot
+ * cover it, wtime may still be negative. Saturate to 0,
+ * which is the largest possible wait (256 * 28.8 ms = 7.37 s).
+ */
+ wtime = clamp(wtime, 0, 255);
+ ret = i2c_smbus_write_byte_data(data->client, TCS3472_WTIME, wtime);
+ if (ret)
+ return ret;
+
+ data->wtime = wtime;
+ data->target_freq_hz = val;
+ data->target_freq_uhz = val2;
+
+ return 0;
+}
+
+static int tcs3472_set_sampling_freq(struct tcs3472_data *data,
+ int val, int val2)
+{
+ guard(mutex)(&data->lock);
+ return __tcs3472_set_sampling_freq(data, val, val2);
}
static int tcs3472_write_raw(struct iio_dev *indio_dev,
@@ -173,6 +389,7 @@ static int tcs3472_write_raw(struct iio_dev *indio_dev,
int val, int val2, long mask)
{
struct tcs3472_data *data = iio_priv(indio_dev);
+ int ret;
int i;
switch (mask) {
@@ -193,17 +410,34 @@ static int tcs3472_write_raw(struct iio_dev *indio_dev,
if (val != 0)
return -EINVAL;
for (i = 0; i < 256; i++) {
- if (val2 == (256 - i) * 2400) {
- data->atime = i;
- return i2c_smbus_write_byte_data(
- data->client, TCS3472_ATIME,
- data->atime);
- }
-
+ if (val2 != (256 - i) * 2400)
+ continue;
+
+ guard(mutex)(&data->lock);
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ TCS3472_ATIME, i);
+ if (ret)
+ return ret;
+
+ data->atime = i;
+
+ /*
+ * ATIME just changed, so the cycle time changed too.
+ * Re-run the sampling frequency logic to recompute
+ * WTIME and preserve the user's last requested
+ * frequency. Lock is already held.
+ */
+ return __tcs3472_set_sampling_freq(data,
+ data->target_freq_hz,
+ data->target_freq_uhz);
}
return -EINVAL;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return tcs3472_set_sampling_freq(data, val, val2);
+ default:
+ return -EINVAL;
}
- return -EINVAL;
}
/*
@@ -220,32 +454,24 @@ static int tcs3472_read_event(struct iio_dev *indio_dev,
int *val2)
{
struct tcs3472_data *data = iio_priv(indio_dev);
- int ret;
unsigned int period;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (info) {
case IIO_EV_INFO_VALUE:
*val = (dir == IIO_EV_DIR_RISING) ?
data->high_thresh : data->low_thresh;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
case IIO_EV_INFO_PERIOD:
- period = (256 - data->atime) * 2400 *
+ period = tcs3472_cycle_time_us(data) *
tcs3472_intr_pers[data->apers];
*val = period / USEC_PER_SEC;
*val2 = period % USEC_PER_SEC;
- ret = IIO_VAL_INT_PLUS_MICRO;
- break;
+ return IIO_VAL_INT_PLUS_MICRO;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
-
- mutex_unlock(&data->lock);
-
- return ret;
}
static int tcs3472_write_event(struct iio_dev *indio_dev,
@@ -259,7 +485,8 @@ static int tcs3472_write_event(struct iio_dev *indio_dev,
int period;
int i;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
+
switch (info) {
case IIO_EV_INFO_VALUE:
switch (dir) {
@@ -270,39 +497,38 @@ static int tcs3472_write_event(struct iio_dev *indio_dev,
command = TCS3472_AILT;
break;
default:
- ret = -EINVAL;
- goto error;
+ return -EINVAL;
}
ret = i2c_smbus_write_word_data(data->client, command, val);
if (ret)
- goto error;
+ return ret;
if (dir == IIO_EV_DIR_RISING)
data->high_thresh = val;
else
data->low_thresh = val;
- break;
- case IIO_EV_INFO_PERIOD:
+
+ return 0;
+ case IIO_EV_INFO_PERIOD:{
+ unsigned int cycle_us;
+
period = val * USEC_PER_SEC + val2;
+ cycle_us = tcs3472_cycle_time_us(data);
for (i = 1; i < ARRAY_SIZE(tcs3472_intr_pers) - 1; i++) {
- if (period <= (256 - data->atime) * 2400 *
- tcs3472_intr_pers[i])
+ if (period <= cycle_us * tcs3472_intr_pers[i])
break;
}
ret = i2c_smbus_write_byte_data(data->client, TCS3472_PERS, i);
if (ret)
- goto error;
+ return ret;
data->apers = i;
- break;
+
+ return 0;
+ }
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
-error:
- mutex_unlock(&data->lock);
-
- return ret;
}
static int tcs3472_read_event_config(struct iio_dev *indio_dev,
@@ -310,13 +536,10 @@ static int tcs3472_read_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir)
{
struct tcs3472_data *data = iio_priv(indio_dev);
- int ret;
- mutex_lock(&data->lock);
- ret = !!(data->enable & TCS3472_ENABLE_AIEN);
- mutex_unlock(&data->lock);
+ guard(mutex)(&data->lock);
- return ret;
+ return (data->enable & TCS3472_ENABLE_AIEN) ? 1 : 0;
}
static int tcs3472_write_event_config(struct iio_dev *indio_dev,
@@ -327,7 +550,7 @@ static int tcs3472_write_event_config(struct iio_dev *indio_dev,
int ret = 0;
u8 enable_old;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
enable_old = data->enable;
@@ -339,12 +562,13 @@ static int tcs3472_write_event_config(struct iio_dev *indio_dev,
if (enable_old != data->enable) {
ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE,
data->enable);
- if (ret)
+ if (ret) {
data->enable = enable_old;
+ return ret;
+ }
}
- mutex_unlock(&data->lock);
- return ret;
+ return 0;
}
static irqreturn_t tcs3472_event_handler(int irq, void *priv)
@@ -440,20 +664,46 @@ static const struct iio_info tcs3472_info = {
.attrs = &tcs3472_attribute_group,
};
+static int tcs3472_powerdown(struct tcs3472_data *data)
+{
+ int ret;
+
+ guard(mutex)(&data->lock);
+
+ data->enable_pre_suspend = data->enable;
+
+ ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE,
+ data->enable & ~TCS3472_ENABLE_RUN);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void tcs3472_powerdown_action(void *data)
+{
+ tcs3472_powerdown(data);
+}
+
static int tcs3472_probe(struct i2c_client *client)
{
+ struct device *dev = &client->dev;
struct tcs3472_data *data;
struct iio_dev *indio_dev;
+ unsigned int cycle_us;
int ret;
+ u8 enable;
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
- if (indio_dev == NULL)
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
- mutex_init(&data->lock);
+ ret = devm_mutex_init(dev, &data->lock);
+ if (ret)
+ return ret;
indio_dev->info = &tcs3472_info;
indio_dev->name = TCS3472_DRV_NAME;
@@ -466,9 +716,9 @@ static int tcs3472_probe(struct i2c_client *client)
return ret;
if (ret == 0x44)
- dev_info(&client->dev, "TCS34721/34725 found\n");
+ dev_info(dev, "TCS34721/34725 found\n");
else if (ret == 0x4d)
- dev_info(&client->dev, "TCS34723/34727 found\n");
+ dev_info(dev, "TCS34723/34727 found\n");
else
return -ENODEV;
@@ -482,6 +732,16 @@ static int tcs3472_probe(struct i2c_client *client)
return ret;
data->atime = ret;
+ ret = i2c_smbus_read_byte_data(data->client, TCS3472_WTIME);
+ if (ret < 0)
+ return ret;
+ data->wtime = ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, TCS3472_CONFIG);
+ if (ret < 0)
+ return ret;
+ data->wlong = (ret & TCS3472_CONFIG_WLONG) ? 1 : 0;
+
ret = i2c_smbus_read_word_data(data->client, TCS3472_AILT);
if (ret < 0)
return ret;
@@ -502,69 +762,51 @@ static int tcs3472_probe(struct i2c_client *client)
if (ret < 0)
return ret;
- /* enable device */
- data->enable = ret | TCS3472_ENABLE_PON | TCS3472_ENABLE_AEN;
- data->enable &= ~TCS3472_ENABLE_AIEN;
- ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE,
- data->enable);
+ /*
+ * Enable the chip in its full running state, including WEN. The
+ * actual wait time is controlled by the WTIME and WLONG registers,
+ * which retain their power-on defaults until userspace writes to
+ * sampling_frequency.
+ */
+ enable = (ret | TCS3472_ENABLE_RUN) & ~TCS3472_ENABLE_AIEN;
+
+ ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, enable);
if (ret < 0)
return ret;
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
- tcs3472_trigger_handler, NULL);
+ data->enable = enable;
+
+ /*
+ * Initialize target frequency from the chip's current state so that
+ * subsequent integration_time changes via IIO_CHAN_INFO_INT_TIME can
+ * preserve a meaningful sampling rate, even before userspace writes
+ * sampling_frequency for the first time.
+ */
+ cycle_us = tcs3472_cycle_time_us(data);
+ tcs3472_cycle_to_freq(cycle_us, &data->target_freq_hz,
+ &data->target_freq_uhz);
+
+ ret = devm_add_action_or_reset(dev, tcs3472_powerdown_action, data);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ tcs3472_trigger_handler, NULL);
if (ret < 0)
return ret;
if (client->irq) {
- ret = request_threaded_irq(client->irq, NULL,
- tcs3472_event_handler,
- IRQF_TRIGGER_FALLING | IRQF_SHARED |
- IRQF_ONESHOT,
- client->name, indio_dev);
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ tcs3472_event_handler,
+ IRQF_TRIGGER_FALLING |
+ IRQF_SHARED |
+ IRQF_ONESHOT,
+ client->name, indio_dev);
if (ret)
- goto buffer_cleanup;
+ return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret < 0)
- goto free_irq;
-
- return 0;
-
-free_irq:
- if (client->irq)
- free_irq(client->irq, indio_dev);
-buffer_cleanup:
- iio_triggered_buffer_cleanup(indio_dev);
- return ret;
-}
-
-static int tcs3472_powerdown(struct tcs3472_data *data)
-{
- int ret;
- u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON;
-
- mutex_lock(&data->lock);
-
- ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE,
- data->enable & ~enable_mask);
- if (!ret)
- data->enable &= ~enable_mask;
-
- mutex_unlock(&data->lock);
-
- return ret;
-}
-
-static void tcs3472_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
- iio_device_unregister(indio_dev);
- if (client->irq)
- free_irq(client->irq, indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- tcs3472_powerdown(iio_priv(indio_dev));
+ return devm_iio_device_register(dev, indio_dev);
}
static int tcs3472_suspend(struct device *dev)
@@ -579,25 +821,30 @@ static int tcs3472_resume(struct device *dev)
struct tcs3472_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
int ret;
- u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
+ /*
+ * Restore the full ENABLE register from the snapshot taken in
+ * tcs3472_powerdown(). This preserves the user's last
+ * sampling_frequency configuration (in particular the WEN bit)
+ * across suspend/resume.
+ */
ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE,
- data->enable | enable_mask);
- if (!ret)
- data->enable |= enable_mask;
+ data->enable_pre_suspend);
+ if (ret)
+ return ret;
- mutex_unlock(&data->lock);
+ data->enable = data->enable_pre_suspend;
- return ret;
+ return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend,
tcs3472_resume);
static const struct i2c_device_id tcs3472_id[] = {
- { "tcs3472" },
+ { .name = "tcs3472" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tcs3472_id);
@@ -608,7 +855,6 @@ static struct i2c_driver tcs3472_driver = {
.pm = pm_sleep_ptr(&tcs3472_pm_ops),
},
.probe = tcs3472_probe,
- .remove = tcs3472_remove,
.id_table = tcs3472_id,
};
module_i2c_driver(tcs3472_driver);
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index f2af1cd7c2d1..7bef0c3118c2 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -18,7 +18,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/math.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm.h>
@@ -755,7 +754,7 @@ static int tsl2563_probe(struct i2c_client *client)
"tsl2563_event",
indio_dev);
if (err)
- return dev_err_probe(dev, err, "irq request error\n");
+ return err;
}
err = tsl2563_configure(chip);
@@ -839,10 +838,10 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tsl2563_pm_ops, tsl2563_suspend,
tsl2563_resume);
static const struct i2c_device_id tsl2563_id[] = {
- { "tsl2560", 0 },
- { "tsl2561", 1 },
- { "tsl2562", 2 },
- { "tsl2563", 3 },
+ { .name = "tsl2560" },
+ { .name = "tsl2561" },
+ { .name = "tsl2562" },
+ { .name = "tsl2563" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tsl2563_id);
diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c
index 8801a491de77..53fd423aa7ae 100644
--- a/drivers/iio/light/tsl2583.c
+++ b/drivers/iio/light/tsl2583.c
@@ -456,12 +456,8 @@ static int tsl2583_chip_init_and_power_on(struct iio_dev *indio_dev)
usleep_range(3000, 3500);
- ret = tsl2583_set_power_state(chip, TSL2583_CNTL_PWR_ON |
- TSL2583_CNTL_ADC_ENBL);
- if (ret < 0)
- return ret;
-
- return ret;
+ return tsl2583_set_power_state(chip,
+ TSL2583_CNTL_PWR_ON | TSL2583_CNTL_ADC_ENBL);
}
/* Sysfs Interface Functions */
@@ -475,7 +471,7 @@ static ssize_t in_illuminance_input_target_show(struct device *dev,
int ret;
mutex_lock(&chip->als_mutex);
- ret = sprintf(buf, "%d\n", chip->als_settings.als_cal_target);
+ ret = sysfs_emit(buf, "%d\n", chip->als_settings.als_cal_target);
mutex_unlock(&chip->als_mutex);
return ret;
@@ -533,10 +529,10 @@ static ssize_t in_illuminance_lux_table_show(struct device *dev,
int offset = 0;
for (i = 0; i < ARRAY_SIZE(chip->als_settings.als_device_lux); i++) {
- offset += sprintf(buf + offset, "%u,%u,%u,",
- chip->als_settings.als_device_lux[i].ratio,
- chip->als_settings.als_device_lux[i].ch0,
- chip->als_settings.als_device_lux[i].ch1);
+ offset += sysfs_emit_at(buf, offset, "%u,%u,%u,",
+ chip->als_settings.als_device_lux[i].ratio,
+ chip->als_settings.als_device_lux[i].ch0,
+ chip->als_settings.als_device_lux[i].ch1);
if (chip->als_settings.als_device_lux[i].ratio == 0) {
/*
* We just printed the first "0" entry.
@@ -547,7 +543,7 @@ static ssize_t in_illuminance_lux_table_show(struct device *dev,
}
}
- offset += sprintf(buf + offset, "\n");
+ offset += sysfs_emit_at(buf, offset, "\n");
return offset;
}
@@ -639,14 +635,6 @@ static const struct iio_chan_spec tsl2583_channels[] = {
},
};
-static int tsl2583_set_pm_runtime_busy(struct tsl2583_chip *chip, bool on)
-{
- if (on)
- return pm_runtime_resume_and_get(&chip->client->dev);
-
- return pm_runtime_put_autosuspend(&chip->client->dev);
-}
-
static int tsl2583_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -654,7 +642,7 @@ static int tsl2583_read_raw(struct iio_dev *indio_dev,
struct tsl2583_chip *chip = iio_priv(indio_dev);
int ret, pm_ret;
- ret = tsl2583_set_pm_runtime_busy(chip, true);
+ ret = pm_runtime_resume_and_get(&chip->client->dev);
if (ret < 0)
return ret;
@@ -722,16 +710,16 @@ read_done:
mutex_unlock(&chip->als_mutex);
if (ret < 0) {
- tsl2583_set_pm_runtime_busy(chip, false);
+ pm_runtime_put_autosuspend(&chip->client->dev);
return ret;
}
/*
* Preserve the ret variable if the call to
- * tsl2583_set_pm_runtime_busy() is successful so the reading
+ * pm_runtime_put_autosuspend() is successful so the reading
* (if applicable) is returned to user space.
*/
- pm_ret = tsl2583_set_pm_runtime_busy(chip, false);
+ pm_ret = pm_runtime_put_autosuspend(&chip->client->dev);
if (pm_ret < 0)
return pm_ret;
@@ -745,7 +733,7 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev,
struct tsl2583_chip *chip = iio_priv(indio_dev);
int ret;
- ret = tsl2583_set_pm_runtime_busy(chip, true);
+ ret = pm_runtime_resume_and_get(&chip->client->dev);
if (ret < 0)
return ret;
@@ -786,15 +774,15 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev,
mutex_unlock(&chip->als_mutex);
if (ret < 0) {
- tsl2583_set_pm_runtime_busy(chip, false);
+ pm_runtime_put_autosuspend(&chip->client->dev);
return ret;
}
- ret = tsl2583_set_pm_runtime_busy(chip, false);
+ ret = pm_runtime_put_autosuspend(&chip->client->dev);
if (ret < 0)
return ret;
- return ret;
+ return 0;
}
static const struct iio_info tsl2583_info = {
@@ -913,9 +901,9 @@ static DEFINE_RUNTIME_DEV_PM_OPS(tsl2583_pm_ops, tsl2583_suspend,
tsl2583_resume, NULL);
static const struct i2c_device_id tsl2583_idtable[] = {
- { "tsl2580", 0 },
- { "tsl2581", 1 },
- { "tsl2583", 2 },
+ { .name = "tsl2580" },
+ { .name = "tsl2581" },
+ { .name = "tsl2583" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tsl2583_idtable);
diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c
index c5557867ea43..ef3ed9635a1e 100644
--- a/drivers/iio/light/tsl2591.c
+++ b/drivers/iio/light/tsl2591.c
@@ -192,6 +192,24 @@ static const int tsl2591_calibscale_available[] = {
1, 25, 428, 9876,
};
+static const u8 tsl2591_persist_table[] = {
+ [TSL2591_PRST_ALS_INT_CYCLE_ANY] = 1,
+ [TSL2591_PRST_ALS_INT_CYCLE_2] = 2,
+ [TSL2591_PRST_ALS_INT_CYCLE_3] = 3,
+ [TSL2591_PRST_ALS_INT_CYCLE_5] = 5,
+ [TSL2591_PRST_ALS_INT_CYCLE_10] = 10,
+ [TSL2591_PRST_ALS_INT_CYCLE_15] = 15,
+ [TSL2591_PRST_ALS_INT_CYCLE_20] = 20,
+ [TSL2591_PRST_ALS_INT_CYCLE_25] = 25,
+ [TSL2591_PRST_ALS_INT_CYCLE_30] = 30,
+ [TSL2591_PRST_ALS_INT_CYCLE_35] = 35,
+ [TSL2591_PRST_ALS_INT_CYCLE_40] = 40,
+ [TSL2591_PRST_ALS_INT_CYCLE_45] = 45,
+ [TSL2591_PRST_ALS_INT_CYCLE_50] = 50,
+ [TSL2591_PRST_ALS_INT_CYCLE_55] = 55,
+ [TSL2591_PRST_ALS_INT_CYCLE_60] = 60,
+};
+
static int tsl2591_set_als_lower_threshold(struct tsl2591_chip *chip,
u16 als_lower_threshold);
static int tsl2591_set_als_upper_threshold(struct tsl2591_chip *chip,
@@ -231,78 +249,22 @@ static int tsl2591_multiplier_to_gain(const u32 multiplier)
static int tsl2591_persist_cycle_to_lit(const u8 als_persist)
{
- switch (als_persist) {
- case TSL2591_PRST_ALS_INT_CYCLE_ANY:
- return 1;
- case TSL2591_PRST_ALS_INT_CYCLE_2:
- return 2;
- case TSL2591_PRST_ALS_INT_CYCLE_3:
- return 3;
- case TSL2591_PRST_ALS_INT_CYCLE_5:
- return 5;
- case TSL2591_PRST_ALS_INT_CYCLE_10:
- return 10;
- case TSL2591_PRST_ALS_INT_CYCLE_15:
- return 15;
- case TSL2591_PRST_ALS_INT_CYCLE_20:
- return 20;
- case TSL2591_PRST_ALS_INT_CYCLE_25:
- return 25;
- case TSL2591_PRST_ALS_INT_CYCLE_30:
- return 30;
- case TSL2591_PRST_ALS_INT_CYCLE_35:
- return 35;
- case TSL2591_PRST_ALS_INT_CYCLE_40:
- return 40;
- case TSL2591_PRST_ALS_INT_CYCLE_45:
- return 45;
- case TSL2591_PRST_ALS_INT_CYCLE_50:
- return 50;
- case TSL2591_PRST_ALS_INT_CYCLE_55:
- return 55;
- case TSL2591_PRST_ALS_INT_CYCLE_60:
- return 60;
- default:
+ if (als_persist >= ARRAY_SIZE(tsl2591_persist_table) ||
+ !tsl2591_persist_table[als_persist])
return -EINVAL;
- }
+
+ return tsl2591_persist_table[als_persist];
}
static int tsl2591_persist_lit_to_cycle(const u8 als_persist)
{
- switch (als_persist) {
- case 1:
- return TSL2591_PRST_ALS_INT_CYCLE_ANY;
- case 2:
- return TSL2591_PRST_ALS_INT_CYCLE_2;
- case 3:
- return TSL2591_PRST_ALS_INT_CYCLE_3;
- case 5:
- return TSL2591_PRST_ALS_INT_CYCLE_5;
- case 10:
- return TSL2591_PRST_ALS_INT_CYCLE_10;
- case 15:
- return TSL2591_PRST_ALS_INT_CYCLE_15;
- case 20:
- return TSL2591_PRST_ALS_INT_CYCLE_20;
- case 25:
- return TSL2591_PRST_ALS_INT_CYCLE_25;
- case 30:
- return TSL2591_PRST_ALS_INT_CYCLE_30;
- case 35:
- return TSL2591_PRST_ALS_INT_CYCLE_35;
- case 40:
- return TSL2591_PRST_ALS_INT_CYCLE_40;
- case 45:
- return TSL2591_PRST_ALS_INT_CYCLE_45;
- case 50:
- return TSL2591_PRST_ALS_INT_CYCLE_50;
- case 55:
- return TSL2591_PRST_ALS_INT_CYCLE_55;
- case 60:
- return TSL2591_PRST_ALS_INT_CYCLE_60;
- default:
- return -EINVAL;
+ for (unsigned int i = TSL2591_PRST_ALS_INT_CYCLE_ANY;
+ i < ARRAY_SIZE(tsl2591_persist_table); i++) {
+ if (als_persist == tsl2591_persist_table[i])
+ return i;
}
+
+ return -EINVAL;
}
static int tsl2591_compatible_int_time(struct tsl2591_chip *chip,
@@ -346,31 +308,6 @@ static int tsl2591_compatible_gain(struct tsl2591_chip *chip, const u8 als_gain)
}
}
-static int tsl2591_compatible_als_persist_cycle(struct tsl2591_chip *chip,
- const u32 als_persist)
-{
- switch (als_persist) {
- case TSL2591_PRST_ALS_INT_CYCLE_ANY:
- case TSL2591_PRST_ALS_INT_CYCLE_2:
- case TSL2591_PRST_ALS_INT_CYCLE_3:
- case TSL2591_PRST_ALS_INT_CYCLE_5:
- case TSL2591_PRST_ALS_INT_CYCLE_10:
- case TSL2591_PRST_ALS_INT_CYCLE_15:
- case TSL2591_PRST_ALS_INT_CYCLE_20:
- case TSL2591_PRST_ALS_INT_CYCLE_25:
- case TSL2591_PRST_ALS_INT_CYCLE_30:
- case TSL2591_PRST_ALS_INT_CYCLE_35:
- case TSL2591_PRST_ALS_INT_CYCLE_40:
- case TSL2591_PRST_ALS_INT_CYCLE_45:
- case TSL2591_PRST_ALS_INT_CYCLE_50:
- case TSL2591_PRST_ALS_INT_CYCLE_55:
- case TSL2591_PRST_ALS_INT_CYCLE_60:
- return 0;
- default:
- return -EINVAL;
- }
-}
-
static int tsl2591_check_als_valid(struct i2c_client *client)
{
int ret;
@@ -952,10 +889,6 @@ static int tsl2591_write_event_value(struct iio_dev *indio_dev,
goto err_unlock;
}
- ret = tsl2591_compatible_als_persist_cycle(chip, als_persist);
- if (ret < 0)
- goto err_unlock;
-
ret = tsl2591_set_als_persist_cycle(chip, als_persist);
if (ret < 0)
goto err_unlock;
@@ -1137,10 +1070,8 @@ static int tsl2591_probe(struct i2c_client *client)
NULL, tsl2591_event_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"tsl2591_irq", indio_dev);
- if (ret) {
- dev_err_probe(&client->dev, ret, "IRQ request error\n");
- return -EINVAL;
- }
+ if (ret)
+ return ret;
indio_dev->info = &tsl2591_info;
} else {
indio_dev->info = &tsl2591_info_no_irq;
diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c
index 0b171106441a..4486a1d9d84d 100644
--- a/drivers/iio/light/tsl2772.c
+++ b/drivers/iio/light/tsl2772.c
@@ -127,6 +127,7 @@ enum {
tmd2672,
tsl2772,
tmd2772,
+ apds9900,
apds9930,
};
@@ -190,7 +191,7 @@ struct tsl2772_chip {
};
/*
- * Different devices require different coefficents, and these numbers were
+ * Different devices require different coefficients, and these numbers were
* derived from the 'Lux Equation' section of the various device datasheets.
* All of these coefficients assume a Glass Attenuation (GA) factor of 1.
* The coefficients are multiplied by 1000 to avoid floating point operations.
@@ -221,6 +222,12 @@ static const struct tsl2772_lux tmd2x72_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = {
{ 0, 0 },
};
+static const struct tsl2772_lux apds9900_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = {
+ { 52000, 115960 },
+ { 36400, 73840 },
+ { 0, 0 },
+};
+
static const struct tsl2772_lux apds9930_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = {
{ 52000, 96824 },
{ 38792, 67132 },
@@ -238,6 +245,7 @@ static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = {
[tmd2672] = tmd2x72_lux_table,
[tsl2772] = tsl2x72_lux_table,
[tmd2772] = tmd2x72_lux_table,
+ [apds9900] = apds9900_lux_table,
[apds9930] = apds9930_lux_table,
};
@@ -289,6 +297,7 @@ static const int tsl2772_int_time_avail[][6] = {
[tmd2672] = { 0, 2730, 0, 2730, 0, 699000 },
[tsl2772] = { 0, 2730, 0, 2730, 0, 699000 },
[tmd2772] = { 0, 2730, 0, 2730, 0, 699000 },
+ [apds9900] = { 0, 2720, 0, 2720, 0, 696000 },
[apds9930] = { 0, 2730, 0, 2730, 0, 699000 },
};
@@ -316,6 +325,7 @@ static const u8 device_channel_config[] = {
[tmd2672] = PRX2,
[tsl2772] = ALSPRX2,
[tmd2772] = ALSPRX2,
+ [apds9900] = ALSPRX,
[apds9930] = ALSPRX2,
};
@@ -530,6 +540,7 @@ static int tsl2772_get_prox(struct iio_dev *indio_dev)
case tmd2672:
case tsl2772:
case tmd2772:
+ case apds9900:
case apds9930:
if (!(ret & TSL2772_STA_PRX_VALID)) {
ret = -EINVAL;
@@ -1263,7 +1274,7 @@ static int tsl2772_read_raw(struct iio_dev *indio_dev,
}
break;
case IIO_CHAN_INFO_CALIBSCALE:
- if (chan->type == IIO_LIGHT)
+ if (chan->type == IIO_INTENSITY)
*val = tsl2772_als_gain[chip->settings.als_gain];
else
*val = tsl2772_prox_gain[chip->settings.prox_gain];
@@ -1367,6 +1378,7 @@ static int tsl2772_device_id_verif(int id, int target)
return (id & 0xf0) == TRITON_ID;
case tmd2671:
case tmd2771:
+ case apds9900:
return (id & 0xf0) == HALIBUT_ID;
case tsl2572:
case tsl2672:
@@ -1837,11 +1849,8 @@ static int tsl2772_probe(struct i2c_client *clientp)
IRQF_ONESHOT,
"TSL2772_event",
indio_dev);
- if (ret) {
- dev_err(&clientp->dev,
- "%s: irq request failed\n", __func__);
+ if (ret)
return ret;
- }
} else {
indio_dev->channels = chip->chip_info->channel_without_events;
}
@@ -1888,17 +1897,19 @@ static int tsl2772_resume(struct device *dev)
}
static const struct i2c_device_id tsl2772_idtable[] = {
- { "tsl2571", tsl2571 },
- { "tsl2671", tsl2671 },
- { "tmd2671", tmd2671 },
- { "tsl2771", tsl2771 },
- { "tmd2771", tmd2771 },
- { "tsl2572", tsl2572 },
- { "tsl2672", tsl2672 },
- { "tmd2672", tmd2672 },
- { "tsl2772", tsl2772 },
- { "tmd2772", tmd2772 },
- { "apds9930", apds9930 },
+ { .name = "tsl2571", .driver_data = tsl2571 },
+ { .name = "tsl2671", .driver_data = tsl2671 },
+ { .name = "tmd2671", .driver_data = tmd2671 },
+ { .name = "tsl2771", .driver_data = tsl2771 },
+ { .name = "tmd2771", .driver_data = tmd2771 },
+ { .name = "tsl2572", .driver_data = tsl2572 },
+ { .name = "tsl2672", .driver_data = tsl2672 },
+ { .name = "tmd2672", .driver_data = tmd2672 },
+ { .name = "tsl2772", .driver_data = tsl2772 },
+ { .name = "tmd2772", .driver_data = tmd2772 },
+ { .name = "apds9900", .driver_data = apds9900 },
+ { .name = "apds9901", .driver_data = apds9900 },
+ { .name = "apds9930", .driver_data = apds9930 },
{ }
};
@@ -1915,6 +1926,8 @@ static const struct of_device_id tsl2772_of_match[] = {
{ .compatible = "amstaos,tmd2672" },
{ .compatible = "amstaos,tsl2772" },
{ .compatible = "amstaos,tmd2772" },
+ { .compatible = "avago,apds9900" },
+ { .compatible = "avago,apds9901" },
{ .compatible = "avago,apds9930" },
{ }
};
diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c
index a5788c09ad02..2f91ed8a9876 100644
--- a/drivers/iio/light/tsl4531.c
+++ b/drivers/iio/light/tsl4531.c
@@ -227,7 +227,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend,
tsl4531_resume);
static const struct i2c_device_id tsl4531_id[] = {
- { "tsl4531" },
+ { .name = "tsl4531" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tsl4531_id);
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c
index d2f5a44892a8..ab518311fd79 100644
--- a/drivers/iio/light/us5182d.c
+++ b/drivers/iio/light/us5182d.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/events.h>
@@ -949,7 +948,7 @@ static const struct acpi_device_id us5182d_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match);
static const struct i2c_device_id us5182d_id[] = {
- { "usd5182" },
+ { .name = "usd5182" },
{ }
};
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index a36c23813679..336468d59ea7 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -18,12 +18,14 @@
*/
#include <linux/bitfield.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/err.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
-#include <linux/pm_runtime.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <linux/units.h>
#include <linux/iio/buffer.h>
@@ -184,13 +186,6 @@ static const int vcnl4040_ps_oversampling_ratio[] = {1, 2, 4, 8};
#define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */
-enum vcnl4000_device_ids {
- VCNL4000,
- VCNL4010,
- VCNL4040,
- VCNL4200,
-};
-
struct vcnl4200_channel {
u8 reg;
ktime_t last_measurement;
@@ -200,7 +195,6 @@ struct vcnl4200_channel {
struct vcnl4000_data {
struct i2c_client *client;
- enum vcnl4000_device_ids id;
int rev;
int al_scale;
int ps_scale;
@@ -232,18 +226,9 @@ struct vcnl4000_chip_spec {
const int(*als_it_times)[][2];
const int num_als_it_times;
const unsigned int ulux_step;
+ const int prod_id;
};
-static const struct i2c_device_id vcnl4000_id[] = {
- { "vcnl4000", VCNL4000 },
- { "vcnl4010", VCNL4010 },
- { "vcnl4020", VCNL4010 },
- { "vcnl4040", VCNL4040 },
- { "vcnl4200", VCNL4200 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
-
static int vcnl4000_set_power_state(struct vcnl4000_data *data, bool on)
{
/* no suspend op */
@@ -261,12 +246,12 @@ static int vcnl4000_init(struct vcnl4000_data *data)
prod_id = ret >> 4;
switch (prod_id) {
case VCNL4000_PROD_ID:
- if (data->id != VCNL4000)
+ if (data->chip_spec->prod_id != VCNL4000_PROD_ID)
dev_warn(&data->client->dev,
"wrong device id, use vcnl4000");
break;
case VCNL4010_PROD_ID:
- if (data->id != VCNL4010)
+ if (data->chip_spec->prod_id != VCNL4010_PROD_ID)
dev_warn(&data->client->dev,
"wrong device id, use vcnl4010/4020");
break;
@@ -277,53 +262,43 @@ static int vcnl4000_init(struct vcnl4000_data *data)
data->rev = ret & 0xf;
data->al_scale = 250000;
- return data->chip_spec->set_power_state(data, true);
+ return 0;
};
static ssize_t vcnl4000_write_als_enable(struct vcnl4000_data *data, bool en)
{
int ret;
- mutex_lock(&data->vcnl4000_lock);
+ guard(mutex)(&data->vcnl4000_lock);
ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
if (ret < 0)
- goto out;
+ return ret;
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;
+ return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, ret);
}
static ssize_t vcnl4000_write_ps_enable(struct vcnl4000_data *data, bool en)
{
int ret;
- mutex_lock(&data->vcnl4000_lock);
+ guard(mutex)(&data->vcnl4000_lock);
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
if (ret < 0)
- goto out;
+ return ret;
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;
+ return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, ret);
}
static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
@@ -353,17 +328,19 @@ static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
static int vcnl4200_init(struct vcnl4000_data *data)
{
+ struct i2c_client *client = data->client;
+ struct device *dev = &client->dev;
int ret, id;
u16 regval;
- ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
+ ret = i2c_smbus_read_word_data(client, VCNL4200_DEV_ID);
if (ret < 0)
return ret;
id = ret & 0xff;
if (id != VCNL4200_PROD_ID) {
- ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID);
+ ret = i2c_smbus_read_word_data(client, VCNL4040_DEV_ID);
if (ret < 0)
return ret;
@@ -373,7 +350,7 @@ static int vcnl4200_init(struct vcnl4000_data *data)
return -ENODEV;
}
- dev_dbg(&data->client->dev, "device id 0x%x", id);
+ dev_dbg(dev, "device id 0x%x", id);
data->rev = (ret >> 8) & 0xf;
data->ps_int = 0;
@@ -397,32 +374,32 @@ static int vcnl4200_init(struct vcnl4000_data *data)
}
data->al_scale = data->chip_spec->ulux_step;
data->ps_scale = 16;
- mutex_init(&data->vcnl4200_al.lock);
- mutex_init(&data->vcnl4200_ps.lock);
+
+ ret = devm_mutex_init(dev, &data->vcnl4200_al.lock);
+ if (ret)
+ return ret;
+
+ ret = devm_mutex_init(dev, &data->vcnl4200_ps.lock);
+ if (ret)
+ return ret;
/* Use 16 bits proximity sensor readings */
- ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+ ret = i2c_smbus_read_word_data(client, VCNL4200_PS_CONF1);
if (ret < 0)
return ret;
regval = ret | VCNL4040_PS_CONF2_PS_HD;
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
- regval);
+ ret = i2c_smbus_write_word_data(client, VCNL4200_PS_CONF1, regval);
if (ret < 0)
return ret;
/* Align proximity sensor sample rate to 16 bits data width */
- ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
+ ret = i2c_smbus_read_word_data(client, VCNL4200_PS_CONF3);
if (ret < 0)
return ret;
regval = ret | VCNL4040_CONF3_PS_SAMPLE_16BITS;
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,
- regval);
- if (ret < 0)
- return ret;
-
- ret = data->chip_spec->set_power_state(data, true);
+ ret = i2c_smbus_write_word_data(client, VCNL4200_PS_CONF3, regval);
if (ret < 0)
return ret;
@@ -456,18 +433,18 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
int tries = 20;
int ret;
- mutex_lock(&data->vcnl4000_lock);
+ guard(mutex)(&data->vcnl4000_lock);
ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
req_mask);
if (ret < 0)
- goto fail;
+ return ret;
/* wait for data to become ready */
while (tries--) {
ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
if (ret < 0)
- goto fail;
+ return ret;
if (ret & rdy_mask)
break;
msleep(20); /* measurement takes up to 100 ms */
@@ -476,21 +453,10 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
if (tries < 0) {
dev_err(&data->client->dev,
"vcnl4000_measure() failed, data not ready\n");
- ret = -EIO;
- goto fail;
+ return -EIO;
}
- ret = vcnl4000_read_data(data, data_reg, val);
- if (ret < 0)
- goto fail;
-
- mutex_unlock(&data->vcnl4000_lock);
-
- return 0;
-
-fail:
- mutex_unlock(&data->vcnl4000_lock);
- return ret;
+ return vcnl4000_read_data(data, data_reg, val);
}
static int vcnl4200_measure(struct vcnl4000_data *data,
@@ -500,16 +466,14 @@ static int vcnl4200_measure(struct vcnl4000_data *data,
s64 delta;
ktime_t next_measurement;
- mutex_lock(&chan->lock);
-
- next_measurement = ktime_add(chan->last_measurement,
- chan->sampling_rate);
- delta = ktime_us_delta(next_measurement, ktime_get());
- if (delta > 0)
- usleep_range(delta, delta + 500);
- chan->last_measurement = ktime_get();
-
- mutex_unlock(&chan->lock);
+ scoped_guard(mutex, &chan->lock) {
+ next_measurement = ktime_add(chan->last_measurement,
+ chan->sampling_rate);
+ delta = ktime_us_delta(next_measurement, ktime_get());
+ if (delta > 0)
+ usleep_range(delta, delta + 500);
+ chan->last_measurement = ktime_get();
+ }
ret = i2c_smbus_read_word_data(data->client, chan->reg);
if (ret < 0)
@@ -573,16 +537,6 @@ static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data)
return !!(ret & VCNL4000_SELF_TIMED_EN);
}
-static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
-{
- struct device *dev = &data->client->dev;
-
- if (on)
- return pm_runtime_resume_and_get(dev);
-
- return pm_runtime_put_autosuspend(dev);
-}
-
static int vcnl4040_read_als_it(struct vcnl4000_data *data, int *val, int *val2)
{
int ret;
@@ -620,21 +574,15 @@ static ssize_t vcnl4040_write_als_it(struct vcnl4000_data *data, int val)
(*data->chip_spec->als_it_times)[0][1]),
val);
- mutex_lock(&data->vcnl4000_lock);
+ guard(mutex)(&data->vcnl4000_lock);
ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
if (ret < 0)
- goto out_unlock;
+ return ret;
regval = FIELD_PREP(VCNL4040_ALS_CONF_IT, i);
regval |= (ret & ~VCNL4040_ALS_CONF_IT);
- ret = i2c_smbus_write_word_data(data->client,
- VCNL4200_AL_CONF,
- regval);
-
-out_unlock:
- mutex_unlock(&data->vcnl4000_lock);
- return ret;
+ return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, regval);
}
static int vcnl4040_read_ps_it(struct vcnl4000_data *data, int *val, int *val2)
@@ -674,20 +622,15 @@ static ssize_t vcnl4040_write_ps_it(struct vcnl4000_data *data, int val)
data->vcnl4200_ps.sampling_rate = ktime_set(0, val * 60 * NSEC_PER_USEC);
- mutex_lock(&data->vcnl4000_lock);
+ guard(mutex)(&data->vcnl4000_lock);
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
if (ret < 0)
- goto out;
+ return ret;
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;
+ return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, regval);
}
static ssize_t vcnl4040_read_als_period(struct vcnl4000_data *data, int *val, int *val2)
@@ -735,20 +678,15 @@ static ssize_t vcnl4040_write_als_period(struct vcnl4000_data *data, int val, in
break;
}
- mutex_lock(&data->vcnl4000_lock);
+ guard(mutex)(&data->vcnl4000_lock);
ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
if (ret < 0)
- goto out_unlock;
+ return ret;
regval = FIELD_PREP(VCNL4040_ALS_CONF_PERS, i);
regval |= (ret & ~VCNL4040_ALS_CONF_PERS);
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF,
- regval);
-
-out_unlock:
- mutex_unlock(&data->vcnl4000_lock);
- return ret;
+ return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, regval);
}
static ssize_t vcnl4040_read_ps_period(struct vcnl4000_data *data, int *val, int *val2)
@@ -797,20 +735,15 @@ static ssize_t vcnl4040_write_ps_period(struct vcnl4000_data *data, int val, int
}
}
- mutex_lock(&data->vcnl4000_lock);
+ guard(mutex)(&data->vcnl4000_lock);
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
if (ret < 0)
- goto out_unlock;
+ return ret;
regval = FIELD_PREP(VCNL4040_CONF1_PS_PERS, i);
regval |= (ret & ~VCNL4040_CONF1_PS_PERS);
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
- regval);
-
-out_unlock:
- mutex_unlock(&data->vcnl4000_lock);
- return ret;
+ return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, regval);
}
static ssize_t vcnl4040_read_ps_oversampling_ratio(struct vcnl4000_data *data, int *val)
@@ -844,20 +777,15 @@ static ssize_t vcnl4040_write_ps_oversampling_ratio(struct vcnl4000_data *data,
if (i >= ARRAY_SIZE(vcnl4040_ps_oversampling_ratio))
return -EINVAL;
- mutex_lock(&data->vcnl4000_lock);
+ guard(mutex)(&data->vcnl4000_lock);
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
if (ret < 0)
- goto out_unlock;
+ return ret;
regval = FIELD_PREP(VCNL4040_PS_CONF3_MPS, i);
regval |= (ret & ~VCNL4040_PS_CONF3_MPS);
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,
- regval);
-
-out_unlock:
- mutex_unlock(&data->vcnl4000_lock);
- return ret;
+ return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, regval);
}
static ssize_t vcnl4040_read_ps_calibbias(struct vcnl4000_data *data, int *val, int *val2)
@@ -892,20 +820,15 @@ static ssize_t vcnl4040_write_ps_calibbias(struct vcnl4000_data *data, int val)
if (i >= ARRAY_SIZE(vcnl4040_ps_calibbias_ua))
return -EINVAL;
- mutex_lock(&data->vcnl4000_lock);
+ guard(mutex)(&data->vcnl4000_lock);
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
if (ret < 0)
- goto out_unlock;
+ return ret;
regval = (ret & ~VCNL4040_PS_MS_LED_I);
regval |= FIELD_PREP(VCNL4040_PS_MS_LED_I, i);
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,
- regval);
-
-out_unlock:
- mutex_unlock(&data->vcnl4000_lock);
- return ret;
+ return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, regval);
}
static int vcnl4000_read_raw(struct iio_dev *indio_dev,
@@ -917,7 +840,7 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = vcnl4000_set_pm_runtime_state(data, true);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
if (ret < 0)
return ret;
@@ -936,7 +859,7 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
default:
ret = -EINVAL;
}
- vcnl4000_set_pm_runtime_state(data, false);
+ pm_runtime_put_autosuspend(&data->client->dev);
return ret;
case IIO_CHAN_INFO_SCALE:
if (chan->type != IIO_LIGHT)
@@ -1490,17 +1413,17 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir,
bool state)
{
- int ret = -EINVAL;
+ int ret;
u16 val, mask;
struct vcnl4000_data *data = iio_priv(indio_dev);
- mutex_lock(&data->vcnl4000_lock);
+ guard(mutex)(&data->vcnl4000_lock);
switch (chan->type) {
case IIO_LIGHT:
ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
if (ret < 0)
- goto out;
+ return ret;
mask = VCNL4040_ALS_CONF_INT_EN;
if (state)
@@ -1509,13 +1432,11 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev,
val = (ret & ~mask);
data->als_int = FIELD_GET(VCNL4040_ALS_CONF_INT_EN, val);
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF,
- val);
- break;
+ return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, val);
case IIO_PROXIMITY:
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
if (ret < 0)
- goto out;
+ return ret;
if (dir == IIO_EV_DIR_RISING)
mask = VCNL4040_PS_IF_AWAY;
@@ -1525,17 +1446,10 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev,
val = state ? (ret | mask) : (ret & ~mask);
data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, val);
- ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
- val);
- break;
+ return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val);
default:
- break;
+ return -EINVAL;
}
-
-out:
- mutex_unlock(&data->vcnl4000_lock);
-
- return ret;
}
static irqreturn_t vcnl4040_irq_thread(int irq, void *p)
@@ -1842,6 +1756,22 @@ static const struct iio_chan_spec vcnl4040_channels[] = {
}
};
+static const struct iio_chan_spec cm36672p_channels[] = {
+ {
+ .type = IIO_PROXIMITY,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
+ .ext_info = vcnl4000_ext_info,
+ .event_spec = vcnl4040_event_spec,
+ .num_event_specs = ARRAY_SIZE(vcnl4040_event_spec),
+ },
+};
+
static const struct iio_info vcnl4000_info = {
.read_raw = vcnl4000_read_raw,
};
@@ -1866,64 +1796,84 @@ static const struct iio_info vcnl4040_info = {
.read_avail = vcnl4040_read_avail,
};
-static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
- [VCNL4000] = {
- .prod = "VCNL4000",
- .init = vcnl4000_init,
- .measure_light = vcnl4000_measure_light,
- .measure_proximity = vcnl4000_measure_proximity,
- .set_power_state = vcnl4000_set_power_state,
- .channels = vcnl4000_channels,
- .num_channels = ARRAY_SIZE(vcnl4000_channels),
- .info = &vcnl4000_info,
- },
- [VCNL4010] = {
- .prod = "VCNL4010/4020",
- .init = vcnl4000_init,
- .measure_light = vcnl4000_measure_light,
- .measure_proximity = vcnl4000_measure_proximity,
- .set_power_state = vcnl4000_set_power_state,
- .channels = vcnl4010_channels,
- .num_channels = ARRAY_SIZE(vcnl4010_channels),
- .info = &vcnl4010_info,
- .irq_thread = vcnl4010_irq_thread,
- .trig_buffer_func = vcnl4010_trigger_handler,
- .buffer_setup_ops = &vcnl4010_buffer_ops,
- },
- [VCNL4040] = {
- .prod = "VCNL4040",
- .init = vcnl4200_init,
- .measure_light = vcnl4200_measure_light,
- .measure_proximity = vcnl4200_measure_proximity,
- .set_power_state = vcnl4200_set_power_state,
- .channels = vcnl4040_channels,
- .num_channels = ARRAY_SIZE(vcnl4040_channels),
- .info = &vcnl4040_info,
- .irq_thread = vcnl4040_irq_thread,
- .int_reg = VCNL4040_INT_FLAGS,
- .ps_it_times = &vcnl4040_ps_it_times,
- .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times),
- .als_it_times = &vcnl4040_als_it_times,
- .num_als_it_times = ARRAY_SIZE(vcnl4040_als_it_times),
- .ulux_step = 100000,
- },
- [VCNL4200] = {
- .prod = "VCNL4200",
- .init = vcnl4200_init,
- .measure_light = vcnl4200_measure_light,
- .measure_proximity = vcnl4200_measure_proximity,
- .set_power_state = vcnl4200_set_power_state,
- .channels = vcnl4040_channels,
- .num_channels = ARRAY_SIZE(vcnl4000_channels),
- .info = &vcnl4040_info,
- .irq_thread = vcnl4040_irq_thread,
- .int_reg = VCNL4200_INT_FLAGS,
- .ps_it_times = &vcnl4200_ps_it_times,
- .num_ps_it_times = ARRAY_SIZE(vcnl4200_ps_it_times),
- .als_it_times = &vcnl4200_als_it_times,
- .num_als_it_times = ARRAY_SIZE(vcnl4200_als_it_times),
- .ulux_step = 24000,
- },
+static const struct vcnl4000_chip_spec cm36672p_spec = {
+ .prod = "CM36672P",
+ .init = vcnl4200_init,
+ .measure_proximity = vcnl4200_measure_proximity,
+ .set_power_state = vcnl4200_set_power_state,
+ .channels = cm36672p_channels,
+ .num_channels = ARRAY_SIZE(cm36672p_channels),
+ .info = &vcnl4040_info,
+ .irq_thread = vcnl4040_irq_thread,
+ .int_reg = VCNL4040_INT_FLAGS,
+ .ps_it_times = &vcnl4040_ps_it_times,
+ .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times),
+ .prod_id = VCNL4040_PROD_ID,
+};
+
+static const struct vcnl4000_chip_spec vcnl4000_spec = {
+ .prod = "VCNL4000",
+ .init = vcnl4000_init,
+ .measure_light = vcnl4000_measure_light,
+ .measure_proximity = vcnl4000_measure_proximity,
+ .set_power_state = vcnl4000_set_power_state,
+ .channels = vcnl4000_channels,
+ .num_channels = ARRAY_SIZE(vcnl4000_channels),
+ .info = &vcnl4000_info,
+ .prod_id = VCNL4000_PROD_ID,
+};
+
+static const struct vcnl4000_chip_spec vcnl4010_spec = {
+ .prod = "VCNL4010/4020",
+ .init = vcnl4000_init,
+ .measure_light = vcnl4000_measure_light,
+ .measure_proximity = vcnl4000_measure_proximity,
+ .set_power_state = vcnl4000_set_power_state,
+ .channels = vcnl4010_channels,
+ .num_channels = ARRAY_SIZE(vcnl4010_channels),
+ .info = &vcnl4010_info,
+ .irq_thread = vcnl4010_irq_thread,
+ .trig_buffer_func = vcnl4010_trigger_handler,
+ .buffer_setup_ops = &vcnl4010_buffer_ops,
+ .prod_id = VCNL4010_PROD_ID,
+};
+
+static const struct vcnl4000_chip_spec vcnl4040_spec = {
+ .prod = "VCNL4040",
+ .init = vcnl4200_init,
+ .measure_light = vcnl4200_measure_light,
+ .measure_proximity = vcnl4200_measure_proximity,
+ .set_power_state = vcnl4200_set_power_state,
+ .channels = vcnl4040_channels,
+ .num_channels = ARRAY_SIZE(vcnl4040_channels),
+ .info = &vcnl4040_info,
+ .irq_thread = vcnl4040_irq_thread,
+ .int_reg = VCNL4040_INT_FLAGS,
+ .ps_it_times = &vcnl4040_ps_it_times,
+ .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times),
+ .als_it_times = &vcnl4040_als_it_times,
+ .num_als_it_times = ARRAY_SIZE(vcnl4040_als_it_times),
+ .ulux_step = 100000,
+ .prod_id = VCNL4040_PROD_ID,
+};
+
+static const struct vcnl4000_chip_spec vcnl4200_spec = {
+ .prod = "VCNL4200",
+ .init = vcnl4200_init,
+ .measure_light = vcnl4200_measure_light,
+ .measure_proximity = vcnl4200_measure_proximity,
+ .set_power_state = vcnl4200_set_power_state,
+ .channels = vcnl4040_channels,
+ .num_channels = ARRAY_SIZE(vcnl4000_channels),
+ .info = &vcnl4040_info,
+ .irq_thread = vcnl4040_irq_thread,
+ .int_reg = VCNL4200_INT_FLAGS,
+ .ps_it_times = &vcnl4200_ps_it_times,
+ .num_ps_it_times = ARRAY_SIZE(vcnl4200_ps_it_times),
+ .als_it_times = &vcnl4200_als_it_times,
+ .num_als_it_times = ARRAY_SIZE(vcnl4200_als_it_times),
+ .ulux_step = 24000,
+ .prod_id = VCNL4200_PROD_ID,
};
static const struct iio_trigger_ops vcnl4010_trigger_ops = {
@@ -1948,35 +1898,60 @@ static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)
return devm_iio_trigger_register(&client->dev, trigger);
}
+static void vcnl4000_cleanup(void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct vcnl4000_data *chip = iio_priv(indio_dev);
+ struct device *dev = &chip->client->dev;
+ int ret;
+
+ ret = chip->chip_spec->set_power_state(chip, false);
+ if (ret)
+ dev_warn(dev, "Failed to power down (%pe)", ERR_PTR(ret));
+}
+
static int vcnl4000_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ static const char * const regulator_names[] = { "vdd", "vio", "vled" };
+ struct device *dev = &client->dev;
struct vcnl4000_data *data;
struct iio_dev *indio_dev;
int ret;
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
- data->id = id->driver_data;
- data->chip_spec = &vcnl4000_chip_spec_cfg[data->id];
+ data->chip_spec = i2c_get_match_data(client);
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
+ regulator_names);
+ if (ret)
+ return ret;
- mutex_init(&data->vcnl4000_lock);
+ ret = devm_mutex_init(dev, &data->vcnl4000_lock);
+ if (ret)
+ return ret;
ret = data->chip_spec->init(data);
if (ret < 0)
return ret;
- dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n",
+ ret = data->chip_spec->set_power_state(data, true);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, vcnl4000_cleanup, indio_dev);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "%s Ambient light/proximity sensor, Rev: %02x\n",
data->chip_spec->prod, data->rev);
- if (device_property_read_u32(&client->dev, "proximity-near-level",
- &data->near_level))
- data->near_level = 0;
+ device_property_read_u32(dev, "proximity-near-level", &data->near_level);
indio_dev->info = data->chip_spec->info;
indio_dev->channels = data->chip_spec->channels;
@@ -1986,94 +1961,55 @@ static int vcnl4000_probe(struct i2c_client *client)
if (data->chip_spec->trig_buffer_func &&
data->chip_spec->buffer_setup_ops) {
- ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
- NULL,
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
data->chip_spec->trig_buffer_func,
data->chip_spec->buffer_setup_ops);
- if (ret < 0) {
- dev_err(&client->dev,
- "unable to setup iio triggered buffer\n");
+ if (ret < 0)
return ret;
- }
}
if (client->irq && data->chip_spec->irq_thread) {
- ret = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, data->chip_spec->irq_thread,
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ data->chip_spec->irq_thread,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"vcnl4000_irq",
indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "irq request failed\n");
+ if (ret < 0)
return ret;
- }
ret = vcnl4010_probe_trigger(indio_dev);
if (ret < 0)
return ret;
}
- ret = pm_runtime_set_active(&client->dev);
- if (ret < 0)
- goto fail_poweroff;
+ ret = devm_pm_runtime_set_active_enabled(dev);
+ if (ret)
+ return ret;
- ret = iio_device_register(indio_dev);
- if (ret < 0)
- goto fail_poweroff;
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return ret;
- pm_runtime_enable(&client->dev);
- pm_runtime_set_autosuspend_delay(&client->dev, VCNL4000_SLEEP_DELAY_MS);
- pm_runtime_use_autosuspend(&client->dev);
+ pm_runtime_set_autosuspend_delay(dev, VCNL4000_SLEEP_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
return 0;
-fail_poweroff:
- data->chip_spec->set_power_state(data, false);
- return ret;
}
static const struct of_device_id vcnl_4000_of_match[] = {
- {
- .compatible = "vishay,vcnl4000",
- .data = (void *)VCNL4000,
- },
- {
- .compatible = "vishay,vcnl4010",
- .data = (void *)VCNL4010,
- },
- {
- .compatible = "vishay,vcnl4020",
- .data = (void *)VCNL4010,
- },
- {
- .compatible = "vishay,vcnl4040",
- .data = (void *)VCNL4040,
- },
- {
- .compatible = "vishay,vcnl4200",
- .data = (void *)VCNL4200,
- },
+ { .compatible = "capella,cm36672p", .data = &cm36672p_spec },
+ /* Capella CM36686 is fully compatible with Vishay VCNL4040 */
+ { .compatible = "capella,cm36686", .data = &vcnl4040_spec },
+ { .compatible = "vishay,vcnl4000", .data = &vcnl4000_spec },
+ { .compatible = "vishay,vcnl4010", .data = &vcnl4010_spec },
+ { .compatible = "vishay,vcnl4020", .data = &vcnl4010_spec },
+ { .compatible = "vishay,vcnl4040", .data = &vcnl4040_spec },
+ { .compatible = "vishay,vcnl4200", .data = &vcnl4200_spec },
{ }
};
MODULE_DEVICE_TABLE(of, vcnl_4000_of_match);
-static void vcnl4000_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct vcnl4000_data *data = iio_priv(indio_dev);
- int ret;
-
- pm_runtime_dont_use_autosuspend(&client->dev);
- pm_runtime_disable(&client->dev);
- iio_device_unregister(indio_dev);
- pm_runtime_set_suspended(&client->dev);
-
- ret = data->chip_spec->set_power_state(data, false);
- if (ret)
- dev_warn(&client->dev, "Failed to power down (%pe)\n",
- ERR_PTR(ret));
-}
-
static int vcnl4000_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -2093,6 +2029,18 @@ static int vcnl4000_runtime_resume(struct device *dev)
static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4000_pm_ops, vcnl4000_runtime_suspend,
vcnl4000_runtime_resume, NULL);
+static const struct i2c_device_id vcnl4000_id[] = {
+ { .name = "cm36672p", .driver_data = (kernel_ulong_t)&cm36672p_spec },
+ { .name = "cm36686", .driver_data = (kernel_ulong_t)&vcnl4040_spec },
+ { .name = "vcnl4000", .driver_data = (kernel_ulong_t)&vcnl4000_spec },
+ { .name = "vcnl4010", .driver_data = (kernel_ulong_t)&vcnl4010_spec },
+ { .name = "vcnl4020", .driver_data = (kernel_ulong_t)&vcnl4010_spec },
+ { .name = "vcnl4040", .driver_data = (kernel_ulong_t)&vcnl4040_spec },
+ { .name = "vcnl4200", .driver_data = (kernel_ulong_t)&vcnl4200_spec },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
+
static struct i2c_driver vcnl4000_driver = {
.driver = {
.name = VCNL4000_DRV_NAME,
@@ -2101,7 +2049,6 @@ static struct i2c_driver vcnl4000_driver = {
},
.probe = vcnl4000_probe,
.id_table = vcnl4000_id,
- .remove = vcnl4000_remove,
};
module_i2c_driver(vcnl4000_driver);
diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c
index 963747927425..ce1bd42b0c7c 100644
--- a/drivers/iio/light/vcnl4035.c
+++ b/drivers/iio/light/vcnl4035.c
@@ -103,17 +103,23 @@ static irqreturn_t vcnl4035_trigger_consumer_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct vcnl4035_data *data = iio_priv(indio_dev);
/* Ensure naturally aligned timestamp */
- u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)] __aligned(8) = { };
+ struct {
+ u16 als_data;
+ aligned_s64 timestamp;
+ } buffer = { };
+ unsigned int val;
int ret;
- ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer);
+ ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, &val);
if (ret < 0) {
dev_err(&data->client->dev,
"Trigger consumer can't read from sensor.\n");
goto fail_read;
}
- iio_push_to_buffers_with_timestamp(indio_dev, buffer,
- iio_get_time_ns(indio_dev));
+
+ buffer.als_data = val;
+ iio_push_to_buffers_with_timestamp(indio_dev, &buffer,
+ iio_get_time_ns(indio_dev));
fail_read:
iio_trigger_notify_done(indio_dev->trig);
@@ -139,16 +145,6 @@ static const struct iio_trigger_ops vcnl4035_trigger_ops = {
.set_trigger_state = vcnl4035_als_drdy_set_state,
};
-static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on)
-{
- struct device *dev = &data->client->dev;
-
- if (on)
- return pm_runtime_resume_and_get(dev);
-
- return pm_runtime_put_autosuspend(dev);
-}
-
static int vcnl4035_read_info_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
@@ -196,11 +192,11 @@ static int vcnl4035_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = vcnl4035_set_pm_runtime_state(data, true);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
if (ret < 0)
return ret;
ret = vcnl4035_read_info_raw(indio_dev, chan, val);
- vcnl4035_set_pm_runtime_state(data, false);
+ pm_runtime_put_autosuspend(&data->client->dev);
return ret;
case IIO_CHAN_INFO_INT_TIME:
*val = 50;
@@ -231,7 +227,7 @@ static int vcnl4035_write_raw(struct iio_dev *indio_dev,
if (val <= 0 || val > 800)
return -EINVAL;
- ret = vcnl4035_set_pm_runtime_state(data, true);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
if (ret < 0)
return ret;
@@ -241,7 +237,7 @@ static int vcnl4035_write_raw(struct iio_dev *indio_dev,
if (!ret)
data->als_it_val = val / 100;
- vcnl4035_set_pm_runtime_state(data, false);
+ pm_runtime_put_autosuspend(&data->client->dev);
return ret;
default:
return -EINVAL;
@@ -381,7 +377,7 @@ static const struct iio_chan_spec vcnl4035_channels[] = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
- .endianness = IIO_LE,
+ .endianness = IIO_CPU,
},
},
{
@@ -395,7 +391,7 @@ static const struct iio_chan_spec vcnl4035_channels[] = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
- .endianness = IIO_LE,
+ .endianness = IIO_CPU,
},
},
};
@@ -641,7 +637,10 @@ static int vcnl4035_runtime_resume(struct device *dev)
struct vcnl4035_data *data = iio_priv(indio_dev);
int ret;
- regcache_sync(data->regmap);
+ ret = regcache_sync(data->regmap);
+ if (ret < 0)
+ return ret;
+
ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
if (ret < 0)
return ret;
@@ -656,7 +655,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4035_pm_ops, vcnl4035_runtime_suspend,
vcnl4035_runtime_resume, NULL);
static const struct i2c_device_id vcnl4035_id[] = {
- { "vcnl4035" },
+ { .name = "vcnl4035" },
{ }
};
MODULE_DEVICE_TABLE(i2c, vcnl4035_id);
diff --git a/drivers/iio/light/veml3235.c b/drivers/iio/light/veml3235.c
index 9309ad83ca9e..d8a39223009b 100644
--- a/drivers/iio/light/veml3235.c
+++ b/drivers/iio/light/veml3235.c
@@ -525,7 +525,7 @@ static const struct of_device_id veml3235_of_match[] = {
MODULE_DEVICE_TABLE(of, veml3235_of_match);
static const struct i2c_device_id veml3235_id[] = {
- { "veml3235" },
+ { .name = "veml3235" },
{ }
};
MODULE_DEVICE_TABLE(i2c, veml3235_id);
diff --git a/drivers/iio/light/veml3328.c b/drivers/iio/light/veml3328.c
new file mode 100644
index 000000000000..7ff1753925c4
--- /dev/null
+++ b/drivers/iio/light/veml3328.c
@@ -0,0 +1,422 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Vishay VEML3328 RGBCIR light sensor driver
+ *
+ * Copyright (c) 2026 Joshua Crofts <joshua.crofts1@gmail.com>
+ *
+ * Datasheet: https://www.vishay.com/docs/84968/veml3328.pdf
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <linux/iio/iio.h>
+
+#define VEML3328_REG_CONF 0x00
+#define VEML3328_REG_ID 0x0c
+#define VEML3328_REG_DATA_C 0x04
+#define VEML3328_REG_DATA_R 0x05
+#define VEML3328_REG_DATA_G 0x06
+#define VEML3328_REG_DATA_B 0x07
+#define VEML3328_REG_DATA_IR 0x08
+
+#define VEML3328_CONF_IT_MASK GENMASK(5, 4)
+#define VEML3328_CONF_GAIN_MASK GENMASK(11, 10)
+
+#define VEML3328_MAX_IT_TIME (400 * USEC_PER_MSEC)
+
+#define VEML3328_ID_VAL 0x28
+
+#define VEML3328_SHUTDOWN (BIT(0) | BIT(15))
+
+struct veml3328_data {
+ struct regmap *regmap;
+ /* Ensure read-modify-write sequences are not interrupted. */
+ struct mutex lock;
+};
+
+static const struct regmap_config veml3328_regmap_config = {
+ .name = "veml3328",
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = VEML3328_REG_ID,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+#define VEML3328_CHAN_SPEC(_color, _addr) { \
+ .type = IIO_INTENSITY, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_LIGHT_##_color, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), \
+ .address = _addr, \
+}
+
+static const struct iio_chan_spec veml3328_channels[] = {
+ {
+ .type = IIO_LIGHT,
+
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
+ .address = VEML3328_REG_DATA_G,
+ },
+ VEML3328_CHAN_SPEC(CLEAR, VEML3328_REG_DATA_C),
+ VEML3328_CHAN_SPEC(RED, VEML3328_REG_DATA_R),
+ VEML3328_CHAN_SPEC(GREEN, VEML3328_REG_DATA_G),
+ VEML3328_CHAN_SPEC(BLUE, VEML3328_REG_DATA_B),
+ VEML3328_CHAN_SPEC(IR, VEML3328_REG_DATA_IR),
+};
+
+/*
+ * Precomputed scale values (micro units).
+ * Formula for calculation: 0.384 * (50000 / IT_us) * (1 / Gain)
+ * Gain indexes: 0 (x0.5), 1 (x1), 2 (x2), 3 (x4)
+ * IT indexes: 0 (50ms), 1 (100ms), 2 (200ms), 3 (400ms)
+ */
+static const int veml3328_scale_vals[4][8] = {
+ { 0, 768000, 0, 384000, 0, 192000, 0, 96000 },
+ { 0, 384000, 0, 192000, 0, 96000, 0, 48000 },
+ { 0, 192000, 0, 96000, 0, 48000, 0, 24000 },
+ { 0, 96000, 0, 48000, 0, 24000, 0, 12000 },
+};
+
+/* integration times in microseconds */
+static const int veml3328_it_times[][2] = {
+ { 0, 50 * USEC_PER_MSEC },
+ { 0, 100 * USEC_PER_MSEC },
+ { 0, 200 * USEC_PER_MSEC },
+ { 0, 400 * USEC_PER_MSEC },
+};
+
+static int veml3328_power_down(struct veml3328_data *data)
+{
+ return regmap_set_bits(data->regmap, VEML3328_REG_CONF,
+ VEML3328_SHUTDOWN);
+}
+
+static int veml3328_power_up(struct veml3328_data *data)
+{
+ int ret;
+
+ ret = regmap_clear_bits(data->regmap, VEML3328_REG_CONF,
+ VEML3328_SHUTDOWN);
+ if (ret)
+ return ret;
+
+ /*
+ * Sleep for maximum integration time to ensure sensor is powered on
+ * correctly.
+ */
+ fsleep(VEML3328_MAX_IT_TIME);
+
+ return 0;
+}
+
+static void veml3328_power_down_action(void *data)
+{
+ veml3328_power_down(data);
+}
+
+static int veml3328_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct veml3328_data *data = iio_priv(indio_dev);
+ struct regmap *regmap = data->regmap;
+ struct device *dev = regmap_get_device(regmap);
+ unsigned int reg_val;
+ int it_inx, gain_inx;
+ int ret;
+
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = regmap_read(regmap, chan->address, &reg_val);
+ if (ret)
+ return ret;
+
+ *val = reg_val;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_INT_TIME:
+ ret = regmap_read(regmap, VEML3328_REG_CONF, &reg_val);
+ if (ret)
+ return ret;
+
+ it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val);
+ if (it_inx >= ARRAY_SIZE(veml3328_it_times))
+ return -EINVAL;
+
+ *val = veml3328_it_times[it_inx][0];
+ *val2 = veml3328_it_times[it_inx][1];
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = regmap_read(regmap, VEML3328_REG_CONF, &reg_val);
+ if (ret)
+ return ret;
+
+ it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val);
+ gain_inx = FIELD_GET(VEML3328_CONF_GAIN_MASK, reg_val);
+
+ if (it_inx >= ARRAY_SIZE(veml3328_it_times) || gain_inx >= 4)
+ return -EINVAL;
+
+ /* Stride by 2 through the flattened array to match (val, val2) */
+ *val = veml3328_scale_vals[it_inx][gain_inx * 2];
+ *val2 = veml3328_scale_vals[it_inx][gain_inx * 2 + 1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int veml3328_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct veml3328_data *data = iio_priv(indio_dev);
+ struct regmap *regmap = data->regmap;
+ struct device *dev = regmap_get_device(data->regmap);
+ unsigned int reg_val;
+ int ret, it_inx;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ *length = ARRAY_SIZE(veml3328_it_times) * 2;
+ *vals = (const int *)veml3328_it_times;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+
+ case IIO_CHAN_INFO_SCALE: {
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(regmap, VEML3328_REG_CONF, &reg_val);
+ if (ret)
+ return ret;
+
+ it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val);
+ if (it_inx >= ARRAY_SIZE(veml3328_it_times))
+ return -EINVAL;
+
+ *length = 8;
+ *vals = (const int *)veml3328_scale_vals[it_inx];
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int veml3328_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct veml3328_data *data = iio_priv(indio_dev);
+ struct regmap *regmap = data->regmap;
+ struct device *dev = regmap_get_device(regmap);
+ unsigned int reg_val;
+ int i, it_inx;
+ int ret;
+
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&data->lock);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ if (val != 0)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(veml3328_it_times); i++) {
+ if (veml3328_it_times[i][1] == val2)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(veml3328_it_times))
+ return -EINVAL;
+
+ return regmap_update_bits(regmap, VEML3328_REG_CONF,
+ VEML3328_CONF_IT_MASK,
+ FIELD_PREP(VEML3328_CONF_IT_MASK, i));
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = regmap_read(regmap, VEML3328_REG_CONF, &reg_val);
+ if (ret)
+ return ret;
+
+ it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val);
+ if (it_inx >= ARRAY_SIZE(veml3328_it_times))
+ return -EINVAL;
+
+ for (i = 0; i < 4; i++) {
+ if (val == veml3328_scale_vals[it_inx][i * 2] &&
+ val2 == veml3328_scale_vals[it_inx][i * 2 + 1])
+ break;
+ }
+
+ if (i == 4)
+ return -EINVAL;
+
+ return regmap_update_bits(regmap, VEML3328_REG_CONF,
+ VEML3328_CONF_GAIN_MASK,
+ FIELD_PREP(VEML3328_CONF_GAIN_MASK, i));
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info veml3328_info = {
+ .read_raw = veml3328_read_raw,
+ .write_raw = veml3328_write_raw,
+ .read_avail = veml3328_read_avail,
+};
+
+static int veml3328_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct veml3328_data *data;
+ struct iio_dev *indio_dev;
+ unsigned int reg_val;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+
+ data->regmap = devm_regmap_init_i2c(client, &veml3328_regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(dev, PTR_ERR(data->regmap),
+ "Failed to initialize regmap\n");
+
+ ret = devm_mutex_init(dev, &data->lock);
+ if (ret)
+ return ret;
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable regulator\n");
+
+ ret = regmap_read(data->regmap, VEML3328_REG_ID, &reg_val);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read ID register\n");
+
+ if ((reg_val & 0xff) != VEML3328_ID_VAL)
+ dev_warn(dev, "Unknown device ID: 0x%02x\n", reg_val & 0xff);
+
+ ret = veml3328_power_up(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to power on sensor\n");
+
+ ret = devm_add_action_or_reset(dev, veml3328_power_down_action, data);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register teardown\n");
+
+ indio_dev->name = "veml3328";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &veml3328_info;
+ indio_dev->channels = veml3328_channels;
+ indio_dev->num_channels = ARRAY_SIZE(veml3328_channels);
+
+ pm_runtime_set_active(dev);
+ pm_runtime_set_autosuspend_delay(dev, 2000);
+ pm_runtime_use_autosuspend(dev);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static int veml3328_runtime_suspend(struct device *dev)
+{
+ struct veml3328_data *data = iio_priv(dev_get_drvdata(dev));
+ int ret;
+
+ ret = veml3328_power_down(data);
+ if (ret)
+ dev_err(dev, "Failed to suspend: %d\n", ret);
+
+ return ret;
+}
+
+static int veml3328_runtime_resume(struct device *dev)
+{
+ struct veml3328_data *data = iio_priv(dev_get_drvdata(dev));
+ int ret;
+
+ ret = veml3328_power_up(data);
+ if (ret)
+ dev_err(dev, "Failed to resume: %d\n", ret);
+
+ return ret;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(veml3328_pm_ops,
+ veml3328_runtime_suspend,
+ veml3328_runtime_resume,
+ NULL);
+
+static const struct of_device_id veml3328_of_match[] = {
+ { .compatible = "vishay,veml3328" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, veml3328_of_match);
+
+static const struct i2c_device_id veml3328_id[] = {
+ { .name = "veml3328" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, veml3328_id);
+
+static struct i2c_driver veml3328_driver = {
+ .driver = {
+ .name = "veml3328",
+ .of_match_table = veml3328_of_match,
+ .pm = pm_ptr(&veml3328_pm_ops),
+ },
+ .probe = veml3328_probe,
+ .id_table = veml3328_id,
+};
+module_i2c_driver(veml3328_driver);
+
+MODULE_AUTHOR("Joshua Crofts <joshua.crofts1@gmail.com>");
+MODULE_DESCRIPTION("VEML3328 RGBCIR Light Sensor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c
index 6bcacae3863c..ec9c127e7d8a 100644
--- a/drivers/iio/light/veml6030.c
+++ b/drivers/iio/light/veml6030.c
@@ -521,13 +521,9 @@ static int veml6030_write_persistence(struct iio_dev *indio_dev,
static int veml6030_set_scale(struct iio_dev *indio_dev, int val, int val2)
{
- int ret, gain_sel, it_idx, it_sel;
+ int ret, gain_sel, it_sel;
struct veml6030_data *data = iio_priv(indio_dev);
- ret = regmap_field_read(data->rf.it, &it_idx);
- if (ret)
- return ret;
-
ret = iio_gts_find_gain_time_sel_for_scale(&data->gts, val, val2,
&gain_sel, &it_sel);
if (ret)
@@ -875,9 +871,11 @@ static irqreturn_t veml6030_event_handler(int irq, void *private)
else
evtdir = IIO_EV_DIR_FALLING;
- iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_INTENSITY,
- 0, IIO_EV_TYPE_THRESH, evtdir),
- iio_get_time_ns(indio_dev));
+ iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+ 0,
+ IIO_EV_TYPE_THRESH,
+ evtdir),
+ iio_get_time_ns(indio_dev));
return IRQ_HANDLED;
}
@@ -923,9 +921,7 @@ static int veml6030_set_info(struct iio_dev *indio_dev)
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
indio_dev->name, indio_dev);
if (ret < 0)
- return dev_err_probe(&client->dev, ret,
- "irq %d request failed\n",
- client->irq);
+ return ret;
indio_dev->info = &veml6030_info;
} else {
@@ -1218,9 +1214,9 @@ static const struct of_device_id veml6030_of_match[] = {
MODULE_DEVICE_TABLE(of, veml6030_of_match);
static const struct i2c_device_id veml6030_id[] = {
- { "veml6030", (kernel_ulong_t)&veml6030_chip},
- { "veml6035", (kernel_ulong_t)&veml6035_chip},
- { "veml7700", (kernel_ulong_t)&veml7700_chip},
+ { .name = "veml6030", .driver_data = (kernel_ulong_t)&veml6030_chip },
+ { .name = "veml6035", .driver_data = (kernel_ulong_t)&veml6035_chip },
+ { .name = "veml7700", .driver_data = (kernel_ulong_t)&veml7700_chip },
{ }
};
MODULE_DEVICE_TABLE(i2c, veml6030_id);
diff --git a/drivers/iio/light/veml6040.c b/drivers/iio/light/veml6040.c
index f563f9f0ee67..0960784b8866 100644
--- a/drivers/iio/light/veml6040.c
+++ b/drivers/iio/light/veml6040.c
@@ -254,7 +254,7 @@ static int veml6040_probe(struct i2c_client *client)
}
static const struct i2c_device_id veml6040_id_table[] = {
- {"veml6040"},
+ { .name = "veml6040" },
{ }
};
MODULE_DEVICE_TABLE(i2c, veml6040_id_table);
diff --git a/drivers/iio/light/veml6046x00.c b/drivers/iio/light/veml6046x00.c
index e60f24d46e7b..b40b70679640 100644
--- a/drivers/iio/light/veml6046x00.c
+++ b/drivers/iio/light/veml6046x00.c
@@ -13,7 +13,6 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/time.h>
@@ -1009,7 +1008,7 @@ static const struct of_device_id veml6046x00_of_match[] = {
MODULE_DEVICE_TABLE(of, veml6046x00_of_match);
static const struct i2c_device_id veml6046x00_id[] = {
- { "veml6046x00" },
+ { .name = "veml6046x00" },
{ }
};
MODULE_DEVICE_TABLE(i2c, veml6046x00_id);
diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c
index 6d4483c85f30..c99336bd919f 100644
--- a/drivers/iio/light/veml6070.c
+++ b/drivers/iio/light/veml6070.c
@@ -134,9 +134,7 @@ static int veml6070_read(struct veml6070_data *data)
if (ret < 0)
return ret;
- ret = (msb << 8) | lsb;
-
- return 0;
+ return (msb << 8) | lsb;
}
static const struct iio_chan_spec veml6070_channels[] = {
@@ -247,13 +245,6 @@ static const struct iio_info veml6070_info = {
.write_raw = veml6070_write_raw,
};
-static void veml6070_i2c_unreg(void *p)
-{
- struct veml6070_data *data = p;
-
- i2c_unregister_device(data->client2);
-}
-
static int veml6070_probe(struct i2c_client *client)
{
struct veml6070_data *data;
@@ -283,7 +274,8 @@ static int veml6070_probe(struct i2c_client *client)
if (ret < 0)
return ret;
- data->client2 = i2c_new_dummy_device(client->adapter, VEML6070_ADDR_DATA_LSB);
+ data->client2 = devm_i2c_new_dummy_device(&client->dev, client->adapter,
+ VEML6070_ADDR_DATA_LSB);
if (IS_ERR(data->client2))
return dev_err_probe(&client->dev, PTR_ERR(data->client2),
"i2c device for second chip address failed\n");
@@ -294,15 +286,11 @@ static int veml6070_probe(struct i2c_client *client)
if (ret < 0)
return ret;
- ret = devm_add_action_or_reset(&client->dev, veml6070_i2c_unreg, data);
- if (ret < 0)
- return ret;
-
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id veml6070_id[] = {
- { "veml6070" },
+ { .name = "veml6070" },
{ }
};
MODULE_DEVICE_TABLE(i2c, veml6070_id);
diff --git a/drivers/iio/light/veml6075.c b/drivers/iio/light/veml6075.c
index edbb43407054..59187244aba0 100644
--- a/drivers/iio/light/veml6075.c
+++ b/drivers/iio/light/veml6075.c
@@ -100,7 +100,7 @@ static const struct iio_chan_spec veml6075_channels[] = {
static int veml6075_request_measurement(struct veml6075_data *data)
{
- int ret, conf, int_time;
+ int ret, conf, int_time, int_index;
ret = regmap_read(data->regmap, VEML6075_CMD_CONF, &conf);
if (ret < 0)
@@ -117,7 +117,11 @@ static int veml6075_request_measurement(struct veml6075_data *data)
* time for all possible configurations. Using a 1.50 factor simplifies
* operations and ensures reliability under all circumstances.
*/
- int_time = veml6075_it_ms[FIELD_GET(VEML6075_CONF_IT, conf)];
+ int_index = FIELD_GET(VEML6075_CONF_IT, conf);
+ if (int_index >= ARRAY_SIZE(veml6075_it_ms))
+ return -EINVAL;
+
+ int_time = veml6075_it_ms[int_index];
msleep(int_time + (int_time / 2));
/* shutdown again, data registers are still accessible */
@@ -451,7 +455,7 @@ static int veml6075_probe(struct i2c_client *client)
}
static const struct i2c_device_id veml6075_id[] = {
- { "veml6075" },
+ { .name = "veml6075" },
{ }
};
MODULE_DEVICE_TABLE(i2c, veml6075_id);
diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c
index c1314b144367..aef8a5333442 100644
--- a/drivers/iio/light/vl6180.c
+++ b/drivers/iio/light/vl6180.c
@@ -16,7 +16,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/err.h>
@@ -722,7 +721,7 @@ static int vl6180_probe(struct i2c_client *client)
IRQF_ONESHOT,
indio_dev->name, indio_dev);
if (ret)
- return dev_err_probe(&client->dev, ret, "devm_request_irq error\n");
+ return ret;
init_completion(&data->completion);
@@ -750,7 +749,7 @@ static const struct of_device_id vl6180_of_match[] = {
MODULE_DEVICE_TABLE(of, vl6180_of_match);
static const struct i2c_device_id vl6180_id[] = {
- { "vl6180" },
+ { .name = "vl6180" },
{ }
};
MODULE_DEVICE_TABLE(i2c, vl6180_id);
diff --git a/drivers/iio/light/zopt2201.c b/drivers/iio/light/zopt2201.c
index 1dba1b949cc3..b53be5f7354e 100644
--- a/drivers/iio/light/zopt2201.c
+++ b/drivers/iio/light/zopt2201.c
@@ -10,17 +10,17 @@
* TODO: interrupt support, ALS/UVB raw mode
*/
-#include <linux/module.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/i2c.h>
+#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/err.h>
-#include <linux/delay.h>
+#include <linux/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/unaligned.h>
-
#define ZOPT2201_DRV_NAME "zopt2201"
/* Registers */
@@ -186,10 +186,10 @@ static int zopt2201_read(struct zopt2201_data *data, u8 reg)
u8 buf[3];
int ret;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
ret = zopt2201_enable_mode(data, reg == ZOPT2201_UVB_DATA);
if (ret < 0)
- goto fail;
+ return ret;
while (tries--) {
unsigned long t = zopt2201_resolution[data->res].us;
@@ -200,30 +200,25 @@ static int zopt2201_read(struct zopt2201_data *data, u8 reg)
msleep(t / 1000);
ret = i2c_smbus_read_byte_data(client, ZOPT2201_MAIN_STATUS);
if (ret < 0)
- goto fail;
+ return ret;
if (ret & ZOPT2201_MAIN_STATUS_DRDY)
break;
}
if (tries < 0) {
ret = -ETIMEDOUT;
- goto fail;
+ return ret;
}
ret = i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf);
if (ret < 0)
- goto fail;
+ return ret;
ret = i2c_smbus_write_byte_data(client, ZOPT2201_MAIN_CTRL, 0x00);
if (ret < 0)
- goto fail;
- mutex_unlock(&data->lock);
+ return ret;
return get_unaligned_le24(&buf[0]);
-
-fail:
- mutex_unlock(&data->lock);
- return ret;
}
static const struct iio_chan_spec zopt2201_channels[] = {
@@ -317,17 +312,15 @@ static int zopt2201_set_resolution(struct zopt2201_data *data, u8 res)
static int zopt2201_write_resolution(struct zopt2201_data *data,
int val, int val2)
{
- int i, ret;
+ int i;
if (val != 0)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++)
if (val2 == zopt2201_resolution[i].us) {
- mutex_lock(&data->lock);
- ret = zopt2201_set_resolution(data, i);
- mutex_unlock(&data->lock);
- return ret;
+ guard(mutex)(&data->lock);
+ return zopt2201_set_resolution(data, i);
}
return -EINVAL;
@@ -351,16 +344,12 @@ static int zopt2201_write_scale_by_idx(struct zopt2201_data *data, int idx,
{
int ret;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
ret = zopt2201_set_resolution(data, zopt2201_scale_array[idx].res);
if (ret < 0)
- goto unlock;
-
- ret = zopt2201_set_gain(data, zopt2201_scale_array[idx].gain);
+ return ret;
-unlock:
- mutex_unlock(&data->lock);
- return ret;
+ return zopt2201_set_gain(data, zopt2201_scale_array[idx].gain);
}
static int zopt2201_write_scale_als(struct zopt2201_data *data,
@@ -527,7 +516,7 @@ static int zopt2201_probe(struct i2c_client *client)
}
static const struct i2c_device_id zopt2201_id[] = {
- { "zopt2201" },
+ { .name = "zopt2201" },
{ }
};
MODULE_DEVICE_TABLE(i2c, zopt2201_id);
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index fb313e591e85..d359003b248e 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -151,6 +151,17 @@ config MMC5633
To compile this driver as a module, choose M here: the module
will be called mmc5633
+config MMC5983
+ tristate "MEMSIC MMC5983 3-axis magnetic sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say yes here to build support for the MEMSIC MMC5983 3-axis
+ magnetic sensor.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mmc5983
+
config IIO_ST_MAGN_3AXIS
tristate "STMicroelectronics magnetometers 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
@@ -198,6 +209,28 @@ config INFINEON_TLV493D
To compile this driver as a module, choose M here: the module
will be called tlv493d.
+config QMC5883L
+ tristate "QST QMC5883L 3-Axis Magnetic Sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say Y here to add support driver for QST QMC5883L 3-Axis
+ Magnetic Sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called qmc5883l.
+
+config QMC6308
+ tristate "QST QMC6308 3-Axis Magnetic Sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say Y here to add support for the QST QMC6308 3-Axis
+ Magnetic Sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called qmc6308.
+
config SENSORS_HMC5843
tristate
select IIO_BUFFER
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index 5bd227f8c120..8f2205975c1b 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MAG3110) += mag3110.o
obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
obj-$(CONFIG_MMC35240) += mmc35240.o
obj-$(CONFIG_MMC5633) += mmc5633.o
+obj-$(CONFIG_MMC5983) += mmc5983.o
obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o
st_magn-y := st_magn_core.o
@@ -26,6 +27,9 @@ obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
obj-$(CONFIG_INFINEON_TLV493D) += tlv493d.o
+obj-$(CONFIG_QMC5883L) += qmc5883l.o
+obj-$(CONFIG_QMC6308) += qmc6308.o
+
obj-$(CONFIG_SENSORS_HMC5843) += hmc5843_core.o
obj-$(CONFIG_SENSORS_HMC5843_I2C) += hmc5843_i2c.o
obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o
diff --git a/drivers/iio/magnetometer/af8133j.c b/drivers/iio/magnetometer/af8133j.c
index b1768c3aa8f3..352f53edad9a 100644
--- a/drivers/iio/magnetometer/af8133j.c
+++ b/drivers/iio/magnetometer/af8133j.c
@@ -504,7 +504,7 @@ static const struct of_device_id af8133j_of_match[] = {
MODULE_DEVICE_TABLE(of, af8133j_of_match);
static const struct i2c_device_id af8133j_id[] = {
- { "af8133j" },
+ { .name = "af8133j" },
{ }
};
MODULE_DEVICE_TABLE(i2c, af8133j_id);
diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c
index 68ece700c7ce..375023db2758 100644
--- a/drivers/iio/magnetometer/ak8974.c
+++ b/drivers/iio/magnetometer/ak8974.c
@@ -12,7 +12,6 @@
* Author: Linus Walleij <linus.walleij@linaro.org>
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
@@ -380,11 +379,7 @@ static int ak8974_getresult(struct ak8974 *ak8974, __le16 *result)
return -ERANGE;
}
- ret = regmap_bulk_read(ak8974->map, AK8974_DATA_X, result, 6);
- if (ret)
- return ret;
-
- return ret;
+ return regmap_bulk_read(ak8974->map, AK8974_DATA_X, result, 6);
}
static irqreturn_t ak8974_drdy_irq(int irq, void *d)
@@ -577,7 +572,7 @@ static int ak8974_measure_channel(struct ak8974 *ak8974, unsigned long address,
/*
* This explicit cast to (s16) is necessary as the measurement
* is done in 2's complement with positive and negative values.
- * The follwing assignment to *val will then convert the signed
+ * The following assignment to *val will then convert the signed
* s16 value to a signed int value.
*/
*val = (s16)le16_to_cpu(hw_values[address]);
@@ -927,11 +922,8 @@ static int ak8974_probe(struct i2c_client *i2c)
irq_trig,
ak8974->name,
ak8974);
- if (ret) {
- dev_err(&i2c->dev, "unable to request DRDY IRQ "
- "- proceeding without IRQ\n");
+ if (ret)
goto no_irq;
- }
ak8974->drdy_irq = true;
}
@@ -1017,10 +1009,10 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ak8974_dev_pm_ops, ak8974_runtime_suspend,
ak8974_runtime_resume, NULL);
static const struct i2c_device_id ak8974_id[] = {
- { "ami305" },
- { "ami306" },
- { "ak8974" },
- { "hscdtd008a" },
+ { .name = "ami305" },
+ { .name = "ami306" },
+ { .name = "ak8974" },
+ { .name = "hscdtd008a" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ak8974_id);
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index d30315ad85de..8b0c07f82602 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -7,24 +7,30 @@
* Copyright (c) 2010, NVIDIA Corporation.
*/
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/jiffies.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/gpio/consumer.h>
-#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <asm/byteorder.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/trigger.h>
+#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
@@ -128,13 +134,6 @@
#define AK09912_MAX_REGS AK09912_REG_ASAZ
/*
- * Miscellaneous values.
- */
-#define AK8975_MAX_CONVERSION_TIMEOUT 500
-#define AK8975_CONVERSION_DONE_POLL_TIME 10
-#define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000)
-
-/*
* Precalculate scale factor (in Gauss units) for each axis and
* store in the device data.
*
@@ -456,7 +455,8 @@ static int ak8975_power_on(const struct ak8975_data *data)
* and the minimum wait time before mode setting is 100us, in
* total 300us. Add some margin and say minimum 500us here.
*/
- usleep_range(500, 1000);
+ fsleep(500);
+
return 0;
}
@@ -473,9 +473,10 @@ static void ak8975_power_off(const struct ak8975_data *data)
* Return 0 if the i2c device is the one we expect.
* return a negative error number otherwise
*/
-static int ak8975_who_i_am(struct i2c_client *client,
+static int ak8975_who_i_am(const struct ak8975_data *data,
enum asahi_compass_chipset type)
{
+ struct i2c_client *client = data->client;
u8 wia_val[2];
int ret;
@@ -489,12 +490,18 @@ static int ak8975_who_i_am(struct i2c_client *client,
* AK8975 | DEVICE_ID | NA
* AK8963 | DEVICE_ID | NA
*/
- ret = i2c_smbus_read_i2c_block_data_or_emulated(
- client, AK09912_REG_WIA1, 2, wia_val);
+ ret = i2c_smbus_read_i2c_block_data_or_emulated(client,
+ AK09912_REG_WIA1,
+ sizeof(wia_val),
+ wia_val);
if (ret < 0) {
dev_err(&client->dev, "Error reading WIA\n");
return ret;
}
+ if (ret != sizeof(wia_val)) {
+ dev_err(&client->dev, "Error reading WIA\n");
+ return -EIO;
+ }
if (wia_val[0] != AK8975_DEVICE_ID)
return -ENODEV;
@@ -541,12 +548,12 @@ static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
data->def->ctrl_modes[mode];
ret = i2c_smbus_write_byte_data(data->client,
data->def->ctrl_regs[CNTL], regval);
- if (ret < 0) {
+ if (ret < 0)
return ret;
- }
+
data->cntl_cache = regval;
- /* After mode change wait atleast 100us */
- usleep_range(100, 500);
+ /* After mode change wait at least 100us */
+ fsleep(100);
return 0;
}
@@ -570,8 +577,8 @@ static irqreturn_t ak8975_irq_handler(int irq, void *data)
static int ak8975_setup_irq(struct ak8975_data *data)
{
struct i2c_client *client = data->client;
- int rc;
int irq;
+ int ret;
init_waitqueue_head(&data->data_ready_queue);
clear_bit(0, &data->flags);
@@ -580,28 +587,24 @@ static int ak8975_setup_irq(struct ak8975_data *data)
else
irq = gpiod_to_irq(data->eoc_gpiod);
- rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
- IRQF_TRIGGER_RISING,
- dev_name(&client->dev), data);
- if (rc < 0) {
- dev_err(&client->dev, "irq %d request failed: %d\n", irq, rc);
- return rc;
- }
+ ret = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
+ IRQF_TRIGGER_RISING,
+ dev_name(&client->dev), data);
+ if (ret)
+ return ret;
data->eoc_irq = irq;
- return rc;
+ return 0;
}
-
/*
* Perform some start-of-day setup, including reading the asa calibration
* values and caching them.
*/
-static int ak8975_setup(struct i2c_client *client)
+static int ak8975_setup(struct ak8975_data *data)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct ak8975_data *data = iio_priv(indio_dev);
+ struct i2c_client *client = data->client;
int ret;
/* Write the fused rom access mode. */
@@ -612,13 +615,18 @@ static int ak8975_setup(struct i2c_client *client)
}
/* Get asa data and store in the device data. */
- ret = i2c_smbus_read_i2c_block_data_or_emulated(
- client, data->def->ctrl_regs[ASA_BASE],
- 3, data->asa);
+ ret = i2c_smbus_read_i2c_block_data_or_emulated(client,
+ data->def->ctrl_regs[ASA_BASE],
+ sizeof(data->asa),
+ data->asa);
if (ret < 0) {
dev_err(&client->dev, "Not able to read asa data\n");
return ret;
}
+ if (ret != sizeof(data->asa)) {
+ dev_err(&client->dev, "Error reading asa data\n");
+ return -EIO;
+ }
/* After reading fuse ROM data set power-down mode */
ret = ak8975_set_mode(data, POWER_DOWN);
@@ -643,22 +651,23 @@ static int ak8975_setup(struct i2c_client *client)
return 0;
}
-static int wait_conversion_complete_gpio(struct ak8975_data *data)
+static int wait_conversion_complete_gpio(struct ak8975_data *data,
+ unsigned int poll_ms,
+ unsigned int timeout_ms)
{
struct i2c_client *client = data->client;
- u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
int ret;
+ int val;
/* Wait for the conversion to complete. */
- while (timeout_ms) {
- msleep(AK8975_CONVERSION_DONE_POLL_TIME);
- if (gpiod_get_value(data->eoc_gpiod))
- break;
- timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
- }
- if (!timeout_ms) {
- dev_err(&client->dev, "Conversion timeout happened\n");
- return -EINVAL;
+ ret = readx_poll_timeout(gpiod_get_value, data->eoc_gpiod, val, val != 0,
+ poll_ms * USEC_PER_MSEC,
+ timeout_ms * USEC_PER_MSEC);
+ if (ret)
+ return ret;
+ if (val < 0) {
+ dev_err(&client->dev, "Error in reading GPIOD\n");
+ return val;
}
ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
@@ -668,54 +677,49 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data)
return ret;
}
-static int wait_conversion_complete_polled(struct ak8975_data *data)
+static int wait_conversion_complete_polled(struct ak8975_data *data,
+ unsigned int poll_ms,
+ unsigned int timeout_ms)
{
struct i2c_client *client = data->client;
- u8 read_status;
- u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
int ret;
+ int val;
/* Wait for the conversion to complete. */
- while (timeout_ms) {
- msleep(AK8975_CONVERSION_DONE_POLL_TIME);
- ret = i2c_smbus_read_byte_data(client,
- data->def->ctrl_regs[ST1]);
- if (ret < 0) {
- dev_err(&client->dev, "Error in reading ST1\n");
- return ret;
- }
- read_status = ret;
- if (read_status)
- break;
- timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
- }
- if (!timeout_ms) {
- dev_err(&client->dev, "Conversion timeout happened\n");
- return -EINVAL;
- }
+ ret = read_poll_timeout(i2c_smbus_read_byte_data, val, val != 0,
+ poll_ms * USEC_PER_MSEC,
+ timeout_ms * USEC_PER_MSEC,
+ true,
+ client, data->def->ctrl_regs[ST1]);
+ if (ret)
+ return ret;
+ if (val < 0)
+ dev_err(&client->dev, "Error in reading ST1\n");
- return read_status;
+ return val;
}
-/* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */
-static int wait_conversion_complete_interrupt(struct ak8975_data *data)
+/* Returns 0 if the end of conversion interrupt occurred or -ETIMEDOUT otherwise */
+static int wait_conversion_complete_interrupt(struct ak8975_data *data,
+ unsigned int timeout_ms)
{
int ret;
ret = wait_event_timeout(data->data_ready_queue,
test_bit(0, &data->flags),
- AK8975_DATA_READY_TIMEOUT);
+ msecs_to_jiffies(timeout_ms));
clear_bit(0, &data->flags);
- return ret > 0 ? 0 : -ETIME;
+ return ret > 0 ? 0 : -ETIMEDOUT;
}
-static int ak8975_start_read_axis(struct ak8975_data *data,
- const struct i2c_client *client)
+static int ak8975_start_read_axis(struct ak8975_data *data)
{
- /* Set up the device for taking a sample. */
- int ret = ak8975_set_mode(data, MODE_ONCE);
+ struct i2c_client *client = data->client;
+ int ret;
+ /* Set up the device for taking a sample. */
+ ret = ak8975_set_mode(data, MODE_ONCE);
if (ret < 0) {
dev_err(&client->dev, "Error in setting operating mode\n");
return ret;
@@ -723,11 +727,11 @@ static int ak8975_start_read_axis(struct ak8975_data *data,
/* Wait for the conversion to complete. */
if (data->eoc_irq)
- ret = wait_conversion_complete_interrupt(data);
+ ret = wait_conversion_complete_interrupt(data, 100);
else if (data->eoc_gpiod)
- ret = wait_conversion_complete_gpio(data);
+ ret = wait_conversion_complete_gpio(data, 10, 500);
else
- ret = wait_conversion_complete_polled(data);
+ ret = wait_conversion_complete_polled(data, 10, 500);
if (ret < 0)
return ret;
@@ -742,24 +746,28 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
const struct i2c_client *client = data->client;
const struct ak_def *def = data->def;
__le16 rval;
- u16 buff;
int ret;
pm_runtime_get_sync(&data->client->dev);
mutex_lock(&data->lock);
- ret = ak8975_start_read_axis(data, client);
+ ret = ak8975_start_read_axis(data);
if (ret)
goto exit;
- ret = i2c_smbus_read_i2c_block_data_or_emulated(
- client, def->data_regs[index],
- sizeof(rval), (u8*)&rval);
+ ret = i2c_smbus_read_i2c_block_data_or_emulated(client,
+ def->data_regs[index],
+ sizeof(rval),
+ (u8 *)&rval);
if (ret < 0)
goto exit;
+ if (ret != sizeof(rval)) {
+ ret = -EIO;
+ goto exit;
+ }
- /* Read out ST2 for release lock on measurment data. */
+ /* Read out ST2 for release lock on measurement data. */
ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST2]);
if (ret < 0) {
dev_err(&client->dev, "Error in reading ST2\n");
@@ -778,12 +786,13 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
pm_runtime_put_autosuspend(&data->client->dev);
/* Swap bytes and convert to valid range. */
- buff = le16_to_cpu(rval);
- *val = clamp_t(s16, buff, -def->range, def->range);
+ *val = clamp_t(s16, le16_to_cpu(rval), -def->range, def->range);
+
return IIO_VAL_INT;
exit:
mutex_unlock(&data->lock);
+ pm_runtime_put_autosuspend(&data->client->dev);
dev_err(&client->dev, "Error in reading axis\n");
return ret;
}
@@ -859,7 +868,7 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev)
mutex_lock(&data->lock);
- ret = ak8975_start_read_axis(data, client);
+ ret = ak8975_start_read_axis(data);
if (ret)
goto unlock;
@@ -869,10 +878,12 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev)
*/
ret = i2c_smbus_read_i2c_block_data_or_emulated(client,
def->data_regs[0],
- 3 * sizeof(fval[0]),
+ sizeof(fval),
(u8 *)fval);
if (ret < 0)
goto unlock;
+ if (ret != sizeof(fval))
+ goto unlock;
mutex_unlock(&data->lock);
@@ -901,6 +912,28 @@ static irqreturn_t ak8975_handle_trigger(int irq, void *p)
return IRQ_HANDLED;
}
+static int ak8975_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct ak8975_data *data = iio_priv(indio_dev);
+ struct device *dev = &data->client->dev;
+
+ return pm_runtime_resume_and_get(dev);
+}
+
+static int ak8975_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct ak8975_data *data = iio_priv(indio_dev);
+ struct device *dev = &data->client->dev;
+
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ak8975_buffer_setup_ops = {
+ .preenable = ak8975_buffer_preenable,
+ .postdisable = ak8975_buffer_postdisable,
+};
static int ak8975_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
@@ -908,8 +941,8 @@ static int ak8975_probe(struct i2c_client *client)
struct iio_dev *indio_dev;
struct gpio_desc *eoc_gpiod;
struct gpio_desc *reset_gpiod;
- int err;
const char *name = NULL;
+ int ret;
/*
* Grab and set up the supplied GPIO.
@@ -919,8 +952,7 @@ static int ak8975_probe(struct i2c_client *client)
eoc_gpiod = devm_gpiod_get_optional(&client->dev, NULL, GPIOD_IN);
if (IS_ERR(eoc_gpiod))
return PTR_ERR(eoc_gpiod);
- if (eoc_gpiod)
- gpiod_set_consumer_name(eoc_gpiod, "ak_8975");
+ gpiod_set_consumer_name(eoc_gpiod, "ak_8975");
/*
* According to AK09911 datasheet, if reset GPIO is provided then
@@ -945,9 +977,9 @@ static int ak8975_probe(struct i2c_client *client)
data->reset_gpiod = reset_gpiod;
data->eoc_irq = 0;
- err = iio_read_mount_matrix(&client->dev, &data->orientation);
- if (err)
- return err;
+ ret = iio_read_mount_matrix(&client->dev, &data->orientation);
+ if (ret)
+ return ret;
/* id will be NULL when enumerated via ACPI */
data->def = i2c_get_match_data(client);
@@ -968,20 +1000,20 @@ static int ak8975_probe(struct i2c_client *client)
if (IS_ERR(data->vid))
return PTR_ERR(data->vid);
- err = ak8975_power_on(data);
- if (err)
- return err;
+ ret = ak8975_power_on(data);
+ if (ret)
+ return ret;
- err = ak8975_who_i_am(client, data->def->type);
- if (err < 0) {
+ ret = ak8975_who_i_am(data, data->def->type);
+ if (ret) {
dev_err(&client->dev, "Unexpected device\n");
goto power_off;
}
dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
/* Perform some basic start-of-day setup of the device. */
- err = ak8975_setup(client);
- if (err < 0) {
+ ret = ak8975_setup(data);
+ if (ret) {
dev_err(&client->dev, "%s initialization fails\n", name);
goto power_off;
}
@@ -994,15 +1026,15 @@ static int ak8975_probe(struct i2c_client *client)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->name = name;
- err = iio_triggered_buffer_setup(indio_dev, NULL, ak8975_handle_trigger,
- NULL);
- if (err) {
+ ret = iio_triggered_buffer_setup(indio_dev, NULL, ak8975_handle_trigger,
+ &ak8975_buffer_setup_ops);
+ if (ret) {
dev_err(&client->dev, "triggered buffer setup failed\n");
goto power_off;
}
- err = iio_device_register(indio_dev);
- if (err) {
+ ret = iio_device_register(indio_dev);
+ if (ret) {
dev_err(&client->dev, "device register failed\n");
goto cleanup_buffer;
}
@@ -1025,7 +1057,7 @@ cleanup_buffer:
iio_triggered_buffer_cleanup(indio_dev);
power_off:
ak8975_power_off(data);
- return err;
+ return ret;
}
static void ak8975_remove(struct i2c_client *client)
@@ -1099,13 +1131,13 @@ static const struct acpi_device_id ak_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
static const struct i2c_device_id ak8975_id[] = {
- {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] },
- {"ak8963", (kernel_ulong_t)&ak_def_array[AK8963] },
- {"ak8975", (kernel_ulong_t)&ak_def_array[AK8975] },
- {"ak09911", (kernel_ulong_t)&ak_def_array[AK09911] },
- {"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] },
- {"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] },
- {"ak09918", (kernel_ulong_t)&ak_def_array[AK09918] },
+ { .name = "AK8963", .driver_data = (kernel_ulong_t)&ak_def_array[AK8963] },
+ { .name = "ak8963", .driver_data = (kernel_ulong_t)&ak_def_array[AK8963] },
+ { .name = "ak8975", .driver_data = (kernel_ulong_t)&ak_def_array[AK8975] },
+ { .name = "ak09911", .driver_data = (kernel_ulong_t)&ak_def_array[AK09911] },
+ { .name = "ak09912", .driver_data = (kernel_ulong_t)&ak_def_array[AK09912] },
+ { .name = "ak09916", .driver_data = (kernel_ulong_t)&ak_def_array[AK09916] },
+ { .name = "ak09918", .driver_data = (kernel_ulong_t)&ak_def_array[AK09918] },
{ }
};
MODULE_DEVICE_TABLE(i2c, ak8975_id);
diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c
index a022e1805dff..32dff9cdd0f7 100644
--- a/drivers/iio/magnetometer/bmc150_magn.c
+++ b/drivers/iio/magnetometer/bmc150_magn.c
@@ -9,22 +9,25 @@
* (C) Copyright 2011~2014 Bosch Sensortec GmbH All Rights Reserved
*/
-#include <linux/module.h>
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
+#include <linux/module.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
#include <linux/iio/buffer.h>
#include <linux/iio/events.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 <linux/regmap.h>
-#include <linux/regulator/consumer.h>
#include "bmc150_magn.h"
@@ -148,14 +151,16 @@ struct bmc150_magn_data {
static const struct {
int freq;
u8 reg_val;
-} bmc150_magn_samp_freq_table[] = { {2, 0x01},
- {6, 0x02},
- {8, 0x03},
- {10, 0x00},
- {15, 0x04},
- {20, 0x05},
- {25, 0x06},
- {30, 0x07} };
+} bmc150_magn_samp_freq_table[] = {
+ { 2, 0x01 },
+ { 6, 0x02 },
+ { 8, 0x03 },
+ { 10, 0x00 },
+ { 15, 0x04 },
+ { 20, 0x05 },
+ { 25, 0x06 },
+ { 30, 0x07 },
+};
enum bmc150_magn_presets {
LOW_POWER_PRESET,
@@ -169,10 +174,10 @@ static const struct bmc150_magn_preset {
u8 rep_z;
u8 odr;
} bmc150_magn_presets_table[] = {
- [LOW_POWER_PRESET] = {3, 3, 10},
- [REGULAR_PRESET] = {9, 15, 10},
- [ENHANCED_REGULAR_PRESET] = {15, 27, 10},
- [HIGH_ACCURACY_PRESET] = {47, 83, 20},
+ [LOW_POWER_PRESET] = { 3, 3, 10 },
+ [REGULAR_PRESET] = { 9, 15, 10 },
+ [ENHANCED_REGULAR_PRESET] = { 15, 27, 10 },
+ [HIGH_ACCURACY_PRESET] = { 47, 83, 20 },
};
#define BMC150_MAGN_DEFAULT_PRESET REGULAR_PRESET
@@ -242,19 +247,26 @@ static int bmc150_magn_set_power_mode(struct bmc150_magn_data *data,
return regmap_update_bits(data->regmap,
BMC150_MAGN_REG_OPMODE_ODR,
BMC150_MAGN_MASK_OPMODE,
- BMC150_MAGN_MODE_SLEEP <<
- BMC150_MAGN_SHIFT_OPMODE);
+ FIELD_PREP(BMC150_MAGN_MASK_OPMODE,
+ BMC150_MAGN_MODE_SLEEP));
case BMC150_MAGN_POWER_MODE_NORMAL:
return regmap_update_bits(data->regmap,
BMC150_MAGN_REG_OPMODE_ODR,
BMC150_MAGN_MASK_OPMODE,
- BMC150_MAGN_MODE_NORMAL <<
- BMC150_MAGN_SHIFT_OPMODE);
+ FIELD_PREP(BMC150_MAGN_MASK_OPMODE,
+ BMC150_MAGN_MODE_NORMAL));
}
return -EINVAL;
}
+static int bmc150_magn_set_power_mode_locked(struct bmc150_magn_data *data,
+ enum bmc150_magn_power_modes mode)
+{
+ guard(mutex)(&data->mutex);
+ return bmc150_magn_set_power_mode(data, mode, true);
+}
+
static int bmc150_magn_set_power_state(struct bmc150_magn_data *data, bool on)
{
int ret = 0;
@@ -280,7 +292,7 @@ static int bmc150_magn_get_odr(struct bmc150_magn_data *data, int *val)
ret = regmap_read(data->regmap, BMC150_MAGN_REG_OPMODE_ODR, &reg_val);
if (ret < 0)
return ret;
- odr_val = (reg_val & BMC150_MAGN_MASK_ODR) >> BMC150_MAGN_SHIFT_ODR;
+ odr_val = FIELD_GET(BMC150_MAGN_MASK_ODR, reg_val);
for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++)
if (bmc150_magn_samp_freq_table[i].reg_val == odr_val) {
@@ -293,21 +305,17 @@ static int bmc150_magn_get_odr(struct bmc150_magn_data *data, int *val)
static int bmc150_magn_set_odr(struct bmc150_magn_data *data, int val)
{
- int ret;
u8 i;
for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++) {
- if (bmc150_magn_samp_freq_table[i].freq == val) {
- ret = regmap_update_bits(data->regmap,
- BMC150_MAGN_REG_OPMODE_ODR,
- BMC150_MAGN_MASK_ODR,
- bmc150_magn_samp_freq_table[i].
- reg_val <<
- BMC150_MAGN_SHIFT_ODR);
- if (ret < 0)
- return ret;
- return 0;
- }
+ if (bmc150_magn_samp_freq_table[i].freq != val)
+ continue;
+
+ return regmap_update_bits(data->regmap,
+ BMC150_MAGN_REG_OPMODE_ODR,
+ BMC150_MAGN_MASK_ODR,
+ FIELD_PREP(BMC150_MAGN_MASK_ODR,
+ bmc150_magn_samp_freq_table[i].reg_val));
}
return -EINVAL;
@@ -453,33 +461,29 @@ static int bmc150_magn_read_raw(struct iio_dev *indio_dev,
s32 values[AXIS_XYZ_MAX];
switch (mask) {
- case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_RAW: {
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
- mutex_lock(&data->mutex);
+
+ guard(mutex)(&data->mutex);
ret = bmc150_magn_set_power_state(data, true);
- if (ret < 0) {
- mutex_unlock(&data->mutex);
+ if (ret < 0)
return ret;
- }
ret = bmc150_magn_read_xyz(data, values);
if (ret < 0) {
bmc150_magn_set_power_state(data, false);
- mutex_unlock(&data->mutex);
return ret;
}
*val = values[chan->scan_index];
ret = bmc150_magn_set_power_state(data, false);
- if (ret < 0) {
- mutex_unlock(&data->mutex);
+ if (ret < 0)
return ret;
- }
- mutex_unlock(&data->mutex);
return IIO_VAL_INT;
+ }
case IIO_CHAN_INFO_SCALE:
/*
* The API/driver performs an off-chip temperature
@@ -527,48 +531,39 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case IIO_CHAN_INFO_SAMP_FREQ:
+ case IIO_CHAN_INFO_SAMP_FREQ: {
if (val > data->max_odr)
return -EINVAL;
- mutex_lock(&data->mutex);
- ret = bmc150_magn_set_odr(data, val);
- mutex_unlock(&data->mutex);
- return ret;
+ guard(mutex)(&data->mutex);
+ return bmc150_magn_set_odr(data, val);
+ }
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
switch (chan->channel2) {
case IIO_MOD_X:
- case IIO_MOD_Y:
+ case IIO_MOD_Y: {
if (val < 1 || val > 511)
return -EINVAL;
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
ret = bmc150_magn_set_max_odr(data, val, 0, 0);
- if (ret < 0) {
- mutex_unlock(&data->mutex);
+ if (ret < 0)
return ret;
- }
- ret = regmap_update_bits(data->regmap,
+ return regmap_update_bits(data->regmap,
BMC150_MAGN_REG_REP_XY,
BMC150_MAGN_REG_REP_DATAMASK,
- BMC150_MAGN_REPXY_TO_REGVAL
- (val));
- mutex_unlock(&data->mutex);
- return ret;
- case IIO_MOD_Z:
+ BMC150_MAGN_REPXY_TO_REGVAL(val));
+ }
+ case IIO_MOD_Z: {
if (val < 1 || val > 256)
return -EINVAL;
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
ret = bmc150_magn_set_max_odr(data, 0, val, 0);
- if (ret < 0) {
- mutex_unlock(&data->mutex);
+ if (ret < 0)
return ret;
- }
- ret = regmap_update_bits(data->regmap,
+ return regmap_update_bits(data->regmap,
BMC150_MAGN_REG_REP_Z,
BMC150_MAGN_REG_REP_DATAMASK,
- BMC150_MAGN_REPZ_TO_REGVAL
- (val));
- mutex_unlock(&data->mutex);
- return ret;
+ BMC150_MAGN_REPZ_TO_REGVAL(val));
+ }
default:
return -EINVAL;
}
@@ -655,8 +650,9 @@ static const struct iio_info bmc150_magn_info = {
};
static const unsigned long bmc150_magn_scan_masks[] = {
- BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
- 0};
+ BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
+ 0
+};
static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
{
@@ -695,7 +691,7 @@ static int bmc150_magn_init(struct bmc150_magn_data *data)
* 3ms power-on time according to datasheet, let's better
* be safe than sorry and set this delay to 5ms.
*/
- msleep(5);
+ fsleep(5 * USEC_PER_MSEC);
ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND,
false);
@@ -782,9 +778,8 @@ static void bmc150_magn_trig_reen(struct iio_trigger *trig)
if (!data->dready_trigger_on)
return;
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
ret = bmc150_magn_reset_intr(data);
- mutex_unlock(&data->mutex);
if (ret)
dev_err(data->dev, "Failed to reset interrupt\n");
}
@@ -794,32 +789,28 @@ static int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig,
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct bmc150_magn_data *data = iio_priv(indio_dev);
- int ret = 0;
+ int ret;
+
+ guard(mutex)(&data->mutex);
- mutex_lock(&data->mutex);
if (state == data->dready_trigger_on)
- goto err_unlock;
+ return 0;
ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_INT_DRDY,
BMC150_MAGN_MASK_DRDY_EN,
- state << BMC150_MAGN_SHIFT_DRDY_EN);
+ FIELD_PREP(BMC150_MAGN_MASK_DRDY_EN, state));
if (ret < 0)
- goto err_unlock;
+ return ret;
data->dready_trigger_on = state;
if (state) {
ret = bmc150_magn_reset_intr(data);
if (ret < 0)
- goto err_unlock;
+ return ret;
}
- mutex_unlock(&data->mutex);
return 0;
-
-err_unlock:
- mutex_unlock(&data->mutex);
- return ret;
}
static const struct iio_trigger_ops bmc150_magn_trigger_ops = {
@@ -977,9 +968,7 @@ void bmc150_magn_remove(struct device *dev)
if (data->dready_trig)
iio_trigger_unregister(data->dready_trig);
- mutex_lock(&data->mutex);
- bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true);
- mutex_unlock(&data->mutex);
+ bmc150_magn_set_power_mode_locked(data, BMC150_MAGN_POWER_MODE_SUSPEND);
regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
}
@@ -992,10 +981,8 @@ static int bmc150_magn_runtime_suspend(struct device *dev)
struct bmc150_magn_data *data = iio_priv(indio_dev);
int ret;
- mutex_lock(&data->mutex);
- ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SLEEP,
- true);
- mutex_unlock(&data->mutex);
+ ret = bmc150_magn_set_power_mode_locked(data,
+ BMC150_MAGN_POWER_MODE_SLEEP);
if (ret < 0) {
dev_err(dev, "powering off device failed\n");
return ret;
@@ -1021,28 +1008,18 @@ static int bmc150_magn_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_magn_data *data = iio_priv(indio_dev);
- int ret;
- mutex_lock(&data->mutex);
- ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SLEEP,
- true);
- mutex_unlock(&data->mutex);
-
- return ret;
+ return bmc150_magn_set_power_mode_locked(data,
+ BMC150_MAGN_POWER_MODE_SLEEP);
}
static int bmc150_magn_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_magn_data *data = iio_priv(indio_dev);
- int ret;
- mutex_lock(&data->mutex);
- ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_NORMAL,
- true);
- mutex_unlock(&data->mutex);
-
- return ret;
+ return bmc150_magn_set_power_mode_locked(data,
+ BMC150_MAGN_POWER_MODE_NORMAL);
}
#endif
diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c
index b110791f688a..28f2bee217d1 100644
--- a/drivers/iio/magnetometer/bmc150_magn_i2c.c
+++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c
@@ -8,7 +8,6 @@
* Copyright (c) 2016, Intel Corporation.
*/
#include <linux/device.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -39,9 +38,9 @@ static void bmc150_magn_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id bmc150_magn_i2c_id[] = {
- { "bmc150_magn" },
- { "bmc156_magn" },
- { "bmm150_magn" },
+ { .name = "bmc150_magn" },
+ { .name = "bmc156_magn" },
+ { .name = "bmm150_magn" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bmc150_magn_i2c_id);
diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c
index 896b1d280731..27ab845fb257 100644
--- a/drivers/iio/magnetometer/bmc150_magn_spi.c
+++ b/drivers/iio/magnetometer/bmc150_magn_spi.c
@@ -8,7 +8,6 @@
* Copyright (c) 2016, Intel Corporation.
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
@@ -34,9 +33,9 @@ static void bmc150_magn_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id bmc150_magn_spi_id[] = {
- {"bmc150_magn", 0},
- {"bmc156_magn", 0},
- {"bmm150_magn", 0},
+ { .name = "bmc150_magn" },
+ { .name = "bmc156_magn" },
+ { .name = "bmm150_magn" },
{ }
};
MODULE_DEVICE_TABLE(spi, bmc150_magn_spi_id);
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index c673f9323e47..ad18f233ee16 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -3,10 +3,10 @@
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*/
+#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
@@ -132,22 +132,10 @@ static const struct iio_chan_spec magn_3d_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(7)
};
-/* Adjust channel real bits based on report descriptor */
-static void magn_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
- int channel, int size)
-{
- channels[channel].scan_type.sign = 's';
- /* Real storage bits will change based on the report desc. */
- channels[channel].scan_type.realbits = size * 8;
- /* Maximum size of a sample to capture is u32 */
- channels[channel].scan_type.storagebits = sizeof(u32) * 8;
-}
-
/* Channel read_raw handler */
static int magn_3d_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct magn_3d_state *magn_state = iio_priv(indio_dev);
int report_id = -1;
@@ -177,8 +165,7 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
false);
return -EINVAL;
}
- hid_sensor_power_state(&magn_state->magn_flux_attributes,
- false);
+ hid_sensor_power_state(&magn_state->magn_flux_attributes, false);
ret_type = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
@@ -239,10 +226,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int magn_3d_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct magn_3d_state *magn_state = iio_priv(indio_dev);
int ret = 0;
@@ -280,8 +265,7 @@ static const struct iio_info magn_3d_info = {
/* Callback handler to send event after all samples are received and captured */
static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct magn_3d_state *magn_state = iio_priv(indio_dev);
@@ -302,9 +286,9 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct magn_3d_state *magn_state = iio_priv(indio_dev);
@@ -337,7 +321,7 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
iio_val = magn_state->magn_val_addr[offset];
- if (iio_val != NULL)
+ if (iio_val)
*iio_val = *((u32 *)raw_data);
else
ret = -EINVAL;
@@ -350,7 +334,7 @@ static int magn_3d_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
struct iio_chan_spec **channels,
int *chan_count,
- unsigned usage_id,
+ u32 usage_id,
struct magn_3d_state *st)
{
int i;
@@ -378,18 +362,17 @@ static int magn_3d_parse_report(struct platform_device *pdev,
return -EINVAL;
}
- dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n",
- attr_count);
+ dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n", attr_count);
dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %x:%x\n",
- st->magn[0].index,
- st->magn[0].report_id,
- st->magn[1].index, st->magn[1].report_id,
- st->magn[2].index, st->magn[2].report_id);
+ st->magn[0].index,
+ st->magn[0].report_id,
+ st->magn[1].index, st->magn[1].report_id,
+ st->magn[2].index, st->magn[2].report_id);
/* Setup IIO channel array */
_channels = devm_kcalloc(&pdev->dev, attr_count,
- sizeof(struct iio_chan_spec),
- GFP_KERNEL);
+ sizeof(struct iio_chan_spec),
+ GFP_KERNEL);
if (!_channels) {
dev_err(&pdev->dev,
"failed to allocate space for iio channels\n");
@@ -418,9 +401,11 @@ static int magn_3d_parse_report(struct platform_device *pdev,
if (i != CHANNEL_SCAN_INDEX_TIMESTAMP) {
/* Set magn_val_addr to iio value address */
st->magn_val_addr[i] = &st->iio_vals[*chan_count];
- magn_3d_adjust_channel_bit_mask(_channels,
- *chan_count,
- st->magn[i].size);
+ _channels[*chan_count].scan_type = (struct iio_scan_type) {
+ .format = 's',
+ .realbits = BYTES_TO_BITS(st->magn[i].size),
+ .storagebits = BITS_PER_TYPE(u32),
+ };
}
(*chan_count)++;
}
@@ -434,8 +419,7 @@ static int magn_3d_parse_report(struct platform_device *pdev,
*channels = _channels;
- dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n",
- *chan_count);
+ dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n", *chan_count);
st->magn_flux_attr.scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_COMPASS_3D,
@@ -476,7 +460,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct magn_3d_state));
- if (indio_dev == NULL)
+ if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -499,8 +483,8 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
magn_state->rot_attributes.sensitivity.index = -1;
ret = magn_3d_parse_report(pdev, hsdev,
- &channels, &chan_count,
- HID_USAGE_SENSOR_COMPASS_3D, magn_state);
+ &channels, &chan_count,
+ HID_USAGE_SENSOR_COMPASS_3D, magn_state);
if (ret) {
dev_err(&pdev->dev, "failed to parse report\n");
return ret;
@@ -515,32 +499,32 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
atomic_set(&magn_state->magn_flux_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &magn_state->magn_flux_attributes);
+ &magn_state->magn_flux_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
magn_state->callbacks.send_event = magn_3d_proc_event;
magn_state->callbacks.capture_sample = magn_3d_capture_sample;
magn_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D,
- &magn_state->callbacks);
+ &magn_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes);
return ret;
@@ -553,8 +537,8 @@ static void hid_magn_3d_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct magn_3d_state *magn_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes);
}
diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c
index b41709959e2b..4c454b0057b1 100644
--- a/drivers/iio/magnetometer/hmc5843_i2c.c
+++ b/drivers/iio/magnetometer/hmc5843_i2c.c
@@ -71,10 +71,10 @@ static void hmc5843_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id hmc5843_id[] = {
- { "hmc5843", HMC5843_ID },
- { "hmc5883", HMC5883_ID },
- { "hmc5883l", HMC5883L_ID },
- { "hmc5983", HMC5983_ID },
+ { .name = "hmc5843", .driver_data = HMC5843_ID },
+ { .name = "hmc5883", .driver_data = HMC5883_ID },
+ { .name = "hmc5883l", .driver_data = HMC5883L_ID },
+ { .name = "hmc5983", .driver_data = HMC5983_ID },
{ }
};
MODULE_DEVICE_TABLE(i2c, hmc5843_id);
diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c
index 6a55c1559b0d..29dee5dce2ae 100644
--- a/drivers/iio/magnetometer/hmc5843_spi.c
+++ b/drivers/iio/magnetometer/hmc5843_spi.c
@@ -56,7 +56,6 @@ static int hmc5843_spi_probe(struct spi_device *spi)
{
int ret;
struct regmap *regmap;
- const struct spi_device_id *id = spi_get_device_id(spi);
spi->mode = SPI_MODE_3;
spi->max_speed_hz = 8000000;
@@ -69,8 +68,7 @@ static int hmc5843_spi_probe(struct spi_device *spi)
return PTR_ERR(regmap);
return hmc5843_common_probe(&spi->dev,
- regmap,
- id->driver_data, id->name);
+ regmap, HMC5983_ID, "hmc5983");
}
static void hmc5843_spi_remove(struct spi_device *spi)
@@ -79,7 +77,7 @@ static void hmc5843_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id hmc5843_id[] = {
- { "hmc5983", HMC5983_ID },
+ { .name = "hmc5983" },
{ }
};
MODULE_DEVICE_TABLE(spi, hmc5843_id);
diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c
index ff09250a06e7..479a12ece8f6 100644
--- a/drivers/iio/magnetometer/mag3110.c
+++ b/drivers/iio/magnetometer/mag3110.c
@@ -619,7 +619,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mag3110_pm_ops, mag3110_suspend,
mag3110_resume);
static const struct i2c_device_id mag3110_id[] = {
- { "mag3110" },
+ { .name = "mag3110" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mag3110_id);
diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c
index f3d48d03f7c3..6f40cba4b1ba 100644
--- a/drivers/iio/magnetometer/mmc35240.c
+++ b/drivers/iio/magnetometer/mmc35240.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/delay.h>
@@ -560,7 +559,7 @@ static const struct acpi_device_id mmc35240_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match);
static const struct i2c_device_id mmc35240_id[] = {
- { "mmc35240" },
+ { .name = "mmc35240" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mmc35240_id);
diff --git a/drivers/iio/magnetometer/mmc5633.c b/drivers/iio/magnetometer/mmc5633.c
index 9d8e27486963..f4dae7ba1335 100644
--- a/drivers/iio/magnetometer/mmc5633.c
+++ b/drivers/iio/magnetometer/mmc5633.c
@@ -24,7 +24,6 @@
#include <linux/init.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/regmap.h>
@@ -532,8 +531,8 @@ static const struct of_device_id mmc5633_of_match[] = {
MODULE_DEVICE_TABLE(of, mmc5633_of_match);
static const struct i2c_device_id mmc5633_i2c_id[] = {
- { "mmc5603" },
- { "mmc5633" },
+ { .name = "mmc5603" },
+ { .name = "mmc5633" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mmc5633_i2c_id);
diff --git a/drivers/iio/magnetometer/mmc5983.c b/drivers/iio/magnetometer/mmc5983.c
new file mode 100644
index 000000000000..d10a6288e147
--- /dev/null
+++ b/drivers/iio/magnetometer/mmc5983.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MMC5983 - MEMSIC 3-axis Magnetic Sensor
+ *
+ * Copyright (c) 2026, Vlad Kulikov <vlad.kulikov.c@gmail.com>
+ *
+ * IIO driver for MMC5983
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#define MMC5983_REG_XOUT0 0x00
+#define MMC5983_REG_XOUT1 0x01
+#define MMC5983_REG_YOUT0 0x02
+#define MMC5983_REG_YOUT1 0x03
+#define MMC5983_REG_ZOUT0 0x04
+#define MMC5983_REG_ZOUT1 0x05
+#define MMC5983_REG_XYZOUT2 0x06
+
+#define MMC5983_REG_STATUS 0x08
+
+#define MMC5983_REG_CTRL0 0x09
+#define MMC5983_REG_CTRL1 0x0A
+#define MMC5983_REG_CTRL2 0x0B
+#define MMC5983_REG_CTRL3 0x0C
+
+#define MMC5983_REG_ID 0x2F
+
+#define MMC5983_PRODUCT_ID 0x30
+
+#define MMC5983_STATUS_MEAS_M_DONE_BIT BIT(0)
+#define MMC5983_STATUS_OTP_RD_DONE_BIT BIT(4)
+
+#define MMC5983_CTRL0_TM_M_BIT BIT(0)
+#define MMC5983_CTRL0_SET_BIT BIT(3)
+#define MMC5983_CTRL0_RESET_BIT BIT(4)
+#define MMC5983_CTRL0_OTP_RD_BIT BIT(6)
+
+#define MMC5983_CTRL1_SW_RST_BIT BIT(7)
+
+enum mmc5983_axis {
+ MMC5983_AXIS_X,
+ MMC5983_AXIS_Y,
+ MMC5983_AXIS_Z,
+};
+
+struct mmc5983_data {
+ struct regmap *regmap;
+ /* Protects chip access during SET/RESET measurement sequence */
+ struct mutex mutex;
+};
+
+#define MMC5983_CHANNEL(_axis) { \
+ .type = IIO_MAGN, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##_axis, \
+ .address = MMC5983_AXIS_##_axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+static const struct iio_chan_spec mmc5983_channels[] = {
+ MMC5983_CHANNEL(X),
+ MMC5983_CHANNEL(Y),
+ MMC5983_CHANNEL(Z),
+};
+
+static int mmc5983_pulse_coil(struct mmc5983_data *data, unsigned int coil_bit)
+{
+ int ret;
+
+ ret = regmap_write(data->regmap, MMC5983_REG_CTRL0, coil_bit);
+ if (ret)
+ return ret;
+
+ /*
+ * Datasheet page 15: SET/RESET coil pulse is 500 ns.
+ * Vendor sample code waits 500 us before the next operation.
+ */
+ fsleep(500);
+
+ return 0;
+}
+
+static int mmc5983_take_measurement(struct mmc5983_data *data, int m[3])
+{
+ unsigned int status;
+ u8 buf[7];
+ int ret;
+
+ ret = regmap_write(data->regmap, MMC5983_REG_CTRL0,
+ MMC5983_CTRL0_TM_M_BIT);
+ if (ret)
+ return ret;
+
+ /*
+ * Datasheet page 15: measurement time is 8 ms at BW=00 (default,
+ * slowest setting). Use a 50 ms timeout for margin.
+ */
+ ret = regmap_read_poll_timeout(data->regmap, MMC5983_REG_STATUS,
+ status,
+ status & MMC5983_STATUS_MEAS_M_DONE_BIT,
+ 10 * USEC_PER_MSEC,
+ 50 * USEC_PER_MSEC);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_read(data->regmap, MMC5983_REG_XOUT0, buf,
+ sizeof(buf));
+ if (ret)
+ return ret;
+
+ m[0] = (buf[0] << 10) | (buf[1] << 2) | ((buf[6] >> 6) & 0x3);
+ m[1] = (buf[2] << 10) | (buf[3] << 2) | ((buf[6] >> 4) & 0x3);
+ m[2] = (buf[4] << 10) | (buf[5] << 2) | ((buf[6] >> 2) & 0x3);
+
+ return 0;
+}
+
+static int mmc5983_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *val,
+ int *val2, long mask)
+{
+ struct mmc5983_data *data = iio_priv(indio_dev);
+ int m1[3], m2[3];
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW: {
+ guard(mutex)(&data->mutex);
+
+ /* SET: magnetize sensor elements in forward direction */
+ ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_SET_BIT);
+ if (ret)
+ return ret;
+
+ ret = mmc5983_take_measurement(data, m1);
+ if (ret)
+ return ret;
+
+ /* RESET: magnetize sensor elements in reverse direction */
+ ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_RESET_BIT);
+ if (ret)
+ return ret;
+
+ ret = mmc5983_take_measurement(data, m2);
+ if (ret)
+ return ret;
+
+ *val = (m1[chan->address] - m2[chan->address]) / 2;
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = 61035;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info mmc5983_info = {
+ .read_raw = mmc5983_read_raw,
+};
+
+static bool mmc5983_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MMC5983_REG_CTRL0:
+ case MMC5983_REG_CTRL1:
+ case MMC5983_REG_CTRL2:
+ case MMC5983_REG_CTRL3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool mmc5983_is_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MMC5983_REG_XOUT0:
+ case MMC5983_REG_XOUT1:
+ case MMC5983_REG_YOUT0:
+ case MMC5983_REG_YOUT1:
+ case MMC5983_REG_ZOUT0:
+ case MMC5983_REG_ZOUT1:
+ case MMC5983_REG_XYZOUT2:
+ case MMC5983_REG_STATUS:
+ case MMC5983_REG_CTRL0:
+ case MMC5983_REG_CTRL1:
+ case MMC5983_REG_CTRL2:
+ case MMC5983_REG_CTRL3:
+ case MMC5983_REG_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool mmc5983_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MMC5983_REG_XOUT0:
+ case MMC5983_REG_XOUT1:
+ case MMC5983_REG_YOUT0:
+ case MMC5983_REG_YOUT1:
+ case MMC5983_REG_ZOUT0:
+ case MMC5983_REG_ZOUT1:
+ case MMC5983_REG_XYZOUT2:
+ case MMC5983_REG_STATUS:
+ case MMC5983_REG_CTRL0:
+ case MMC5983_REG_CTRL1:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config mmc5983_regmap_config = {
+ .name = "mmc5983_regmap",
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MMC5983_REG_ID,
+ .writeable_reg = mmc5983_is_writeable_reg,
+ .readable_reg = mmc5983_is_readable_reg,
+ .volatile_reg = mmc5983_is_volatile_reg,
+};
+
+static int mmc5983_init(struct mmc5983_data *data)
+{
+ struct regmap *regmap = data->regmap;
+ struct device *dev = regmap_get_device(regmap);
+ unsigned int reg_id, status;
+ int ret;
+
+ ret = regmap_read(regmap, MMC5983_REG_ID, &reg_id);
+ if (ret)
+ return dev_err_probe(dev, ret, "Error reading product id\n");
+
+ if (reg_id != MMC5983_PRODUCT_ID)
+ dev_info(dev, "unexpected product id 0x%02x\n", reg_id);
+
+ ret = regmap_write(regmap, MMC5983_REG_CTRL1, MMC5983_CTRL1_SW_RST_BIT);
+ if (ret)
+ return ret;
+
+ /* Datasheet page 15: power-on time after SW_RST is 10 ms */
+ fsleep(10 * USEC_PER_MSEC);
+
+ ret = regmap_write(regmap, MMC5983_REG_CTRL0, MMC5983_CTRL0_OTP_RD_BIT);
+ if (ret)
+ return ret;
+
+ /*
+ * Datasheet page 15: OTP read completes and self-clears. No separate
+ * OTP refresh timeout is specified, so use the 10 ms power-on time as
+ * a conservative upper bound.
+ */
+ ret = regmap_read_poll_timeout(regmap, MMC5983_REG_STATUS, status,
+ status & MMC5983_STATUS_OTP_RD_DONE_BIT,
+ USEC_PER_MSEC,
+ 10 * USEC_PER_MSEC);
+ if (ret)
+ return ret;
+
+ /* SET: magnetize sensor elements in forward direction */
+ ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_SET_BIT);
+ if (ret)
+ return ret;
+
+ /* RESET: magnetize sensor elements in reverse direction */
+ return mmc5983_pulse_coil(data, MMC5983_CTRL0_RESET_BIT);
+}
+
+static int mmc5983_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct mmc5983_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);
+
+ ret = devm_mutex_init(dev, &data->mutex);
+ if (ret)
+ return ret;
+
+ data->regmap = devm_regmap_init_i2c(i2c, &mmc5983_regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(dev, PTR_ERR(data->regmap),
+ "failed to allocate register map\n");
+
+ indio_dev->info = &mmc5983_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->name = "mmc5983";
+ indio_dev->channels = mmc5983_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mmc5983_channels);
+
+ ret = mmc5983_init(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "mmc5983 chip init failed\n");
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id mmc5983_of_match[] = {
+ { .compatible = "memsic,mmc5983" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mmc5983_of_match);
+
+static const struct i2c_device_id mmc5983_id[] = {
+ { .name = "mmc5983" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mmc5983_id);
+
+static struct i2c_driver mmc5983_driver = {
+ .driver = {
+ .name = "mmc5983",
+ .of_match_table = mmc5983_of_match,
+ },
+ .probe = mmc5983_probe,
+ .id_table = mmc5983_id,
+};
+module_i2c_driver(mmc5983_driver);
+
+MODULE_AUTHOR("Vladislav Kulikov <vlad.kulikov.c@gmail.com>");
+MODULE_DESCRIPTION("MEMSIC MMC5983 magnetic sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/magnetometer/qmc5883l.c b/drivers/iio/magnetometer/qmc5883l.c
new file mode 100644
index 000000000000..c3469715dc63
--- /dev/null
+++ b/drivers/iio/magnetometer/qmc5883l.c
@@ -0,0 +1,516 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * Support for QST QMC5883L 3-Axis Magnetic Sensor on I2C bus.
+ *
+ * Copyright (C) 2026 Siratul Islam <siratul.islam@linux.dev>
+ *
+ * Datasheet available at
+ * <https://www.qstcorp.com/upload/pdf/202512/13-52-04%20QMC5883L%20Datasheet%20Rev.%20B.pdf>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/iio/iio.h>
+
+#define QMC5883L_REG_X_LSB 0x00
+#define QMC5883L_REG_STATUS1 0x06
+#define QMC5883L_REG_CTRL1 0x09
+#define QMC5883L_REG_CTRL2 0x0A
+#define QMC5883L_REG_SET_RESET 0x0B
+#define QMC5883L_REG_ID 0x0D
+
+#define QMC5883L_CHIP_ID 0xFF
+
+#define QMC5883L_MODE_MASK GENMASK(1, 0)
+#define QMC5883L_ODR_MASK GENMASK(3, 2)
+#define QMC5883L_RNG_MASK GENMASK(5, 4)
+#define QMC5883L_OSR_MASK GENMASK(7, 6)
+
+#define QMC5883L_MODE_STANDBY 0x00
+#define QMC5883L_MODE_CONT 0x01
+
+#define QMC5883L_ODR_10HZ 0x00
+#define QMC5883L_ODR_50HZ 0x01
+#define QMC5883L_ODR_100HZ 0x02
+#define QMC5883L_ODR_200HZ 0x03
+
+#define QMC5883L_RNG_2G 0x00
+#define QMC5883L_RNG_8G 0x01
+
+#define QMC5883L_OSR_512 0x00
+#define QMC5883L_OSR_256 0x01
+#define QMC5883L_OSR_128 0x02
+#define QMC5883L_OSR_64 0x03
+
+#define QMC5883L_STATUS_DRDY BIT(0)
+#define QMC5883L_STATUS_OVL BIT(1)
+
+#define QMC5883L_SET_RESET_VAL BIT(0)
+#define QMC5883L_INT_DISABLE BIT(0)
+#define QMC5883L_SOFT_RESET BIT(7)
+
+#define QMC5883L_PORT_US 350
+
+struct qmc5883l_data {
+ struct regmap *regmap;
+ /*
+ * Protect data->range/odr/osr.
+ * Protect poll and read during measurement.
+ */
+ struct mutex mutex;
+ u8 range;
+ u8 odr;
+ u8 osr;
+};
+
+enum qmc5883l_chan {
+ QMC5883L_AXIS_X,
+ QMC5883L_AXIS_Y,
+ QMC5883L_AXIS_Z,
+};
+
+static const int qmc5883l_odr_avail[] = { 10, 50, 100, 200 };
+
+static const int qmc5883l_osr_avail[] = { 512, 256, 128, 64 };
+
+static const int qmc5883l_scales[][2] = {
+ [QMC5883L_RNG_2G] = { 0, 83333 },
+ [QMC5883L_RNG_8G] = { 0, 333333 },
+};
+
+static int qmc5883l_take_measurement(struct iio_dev *indio_dev, int index,
+ int *val)
+{
+ struct qmc5883l_data *data = iio_priv(indio_dev);
+ struct regmap *map = data->regmap;
+ unsigned int status;
+ __le16 buf[3];
+ int ret;
+
+ guard(mutex) (&data->mutex);
+
+ /* 50ms headroom over the slowest ODR (10Hz) */
+ ret = regmap_read_poll_timeout(map, QMC5883L_REG_STATUS1,
+ status, (status & QMC5883L_STATUS_DRDY),
+ 2 * USEC_PER_MSEC, 150 * USEC_PER_MSEC);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_read(map, QMC5883L_REG_X_LSB, buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ if (status & QMC5883L_STATUS_OVL)
+ return -ERANGE;
+
+ *val = (s16)le16_to_cpu(buf[index]);
+
+ return 0;
+}
+
+static int qmc5883l_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct qmc5883l_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = qmc5883l_take_measurement(indio_dev, chan->address, val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE: {
+ guard(mutex)(&data->mutex);
+
+ *val = qmc5883l_scales[data->range][0];
+ *val2 = qmc5883l_scales[data->range][1];
+
+ return IIO_VAL_INT_PLUS_NANO;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ guard(mutex)(&data->mutex);
+
+ switch (data->odr) {
+ case QMC5883L_ODR_200HZ:
+ *val = 200;
+ break;
+ case QMC5883L_ODR_100HZ:
+ *val = 100;
+ break;
+ case QMC5883L_ODR_50HZ:
+ *val = 50;
+ break;
+ case QMC5883L_ODR_10HZ:
+ *val = 10;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: {
+ guard(mutex)(&data->mutex);
+
+ switch (data->osr) {
+ case QMC5883L_OSR_64:
+ *val = 64;
+ break;
+ case QMC5883L_OSR_128:
+ *val = 128;
+ break;
+ case QMC5883L_OSR_256:
+ *val = 256;
+ break;
+ case QMC5883L_OSR_512:
+ *val = 512;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return IIO_VAL_INT;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int qmc5883l_write_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int val, int val2, long mask)
+{
+ struct qmc5883l_data *data = iio_priv(indio_dev);
+ u8 rng, osr, odr;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE: {
+ if (val != 0)
+ return -EINVAL;
+
+ if (val2 == qmc5883l_scales[QMC5883L_RNG_2G][1])
+ rng = QMC5883L_RNG_2G;
+ else if (val2 == qmc5883l_scales[QMC5883L_RNG_8G][1])
+ rng = QMC5883L_RNG_8G;
+ else
+ return -EINVAL;
+
+ guard(mutex)(&data->mutex);
+
+ ret = regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1,
+ QMC5883L_RNG_MASK,
+ FIELD_PREP(QMC5883L_RNG_MASK, rng));
+ if (ret)
+ return ret;
+
+ data->range = rng;
+
+ return 0;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ switch (val) {
+ case 200:
+ odr = QMC5883L_ODR_200HZ;
+ break;
+ case 100:
+ odr = QMC5883L_ODR_100HZ;
+ break;
+ case 50:
+ odr = QMC5883L_ODR_50HZ;
+ break;
+ case 10:
+ odr = QMC5883L_ODR_10HZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ guard(mutex)(&data->mutex);
+
+ ret = regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1,
+ QMC5883L_ODR_MASK,
+ FIELD_PREP(QMC5883L_ODR_MASK, odr));
+ if (ret)
+ return ret;
+
+ data->odr = odr;
+
+ return 0;
+ }
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: {
+ switch (val) {
+ case 64:
+ osr = QMC5883L_OSR_64;
+ break;
+ case 128:
+ osr = QMC5883L_OSR_128;
+ break;
+ case 256:
+ osr = QMC5883L_OSR_256;
+ break;
+ case 512:
+ osr = QMC5883L_OSR_512;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ guard(mutex)(&data->mutex);
+
+ ret = regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1,
+ QMC5883L_OSR_MASK,
+ FIELD_PREP(QMC5883L_OSR_MASK, osr));
+ if (ret)
+ return ret;
+
+ data->osr = osr;
+
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int qmc5883l_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 = qmc5883l_odr_avail;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(qmc5883l_odr_avail);
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = qmc5883l_osr_avail;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(qmc5883l_osr_avail);
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (const int *)qmc5883l_scales;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ *length = ARRAY_SIZE(qmc5883l_scales) * 2;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int qmc5883l_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return IIO_VAL_INT;
+ }
+}
+
+static const struct iio_info qmc5883l_info = {
+ .read_raw = qmc5883l_read_raw,
+ .write_raw = qmc5883l_write_raw,
+ .read_avail = qmc5883l_read_avail,
+ .write_raw_get_fmt = qmc5883l_write_raw_get_fmt,
+};
+
+static int qmc5883l_init(struct qmc5883l_data *data)
+{
+ struct regmap *map = data->regmap;
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(map, QMC5883L_REG_ID, &reg);
+ if (ret)
+ return ret;
+
+ /* Not failing because rev 1.0 had this register reserved */
+ if (reg != QMC5883L_CHIP_ID)
+ dev_warn(regmap_get_device(map),
+ "Unknown chip id: 0x%02x, continuing\n", reg);
+
+ ret = regmap_write(map, QMC5883L_REG_CTRL2, QMC5883L_SOFT_RESET);
+ if (ret)
+ return ret;
+
+ /* Use POR completion time as a conservative bound */
+ fsleep(QMC5883L_PORT_US);
+
+ /* DRDY pin not used in this version of the driver */
+ ret = regmap_write(map, QMC5883L_REG_CTRL2, QMC5883L_INT_DISABLE);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(map, QMC5883L_REG_SET_RESET, QMC5883L_SET_RESET_VAL);
+ if (ret)
+ return ret;
+
+ data->odr = QMC5883L_ODR_50HZ;
+ data->range = QMC5883L_RNG_2G;
+ data->osr = QMC5883L_OSR_64;
+
+ return regmap_write(map, QMC5883L_REG_CTRL1,
+ FIELD_PREP(QMC5883L_MODE_MASK, QMC5883L_MODE_CONT) |
+ FIELD_PREP(QMC5883L_ODR_MASK, data->odr) |
+ FIELD_PREP(QMC5883L_RNG_MASK, data->range) |
+ FIELD_PREP(QMC5883L_OSR_MASK, data->osr));
+}
+
+static void qmc5883l_power_down_action(void *priv)
+{
+ struct qmc5883l_data *data = priv;
+
+ regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1,
+ QMC5883L_MODE_MASK,
+ FIELD_PREP(QMC5883L_MODE_MASK, QMC5883L_MODE_STANDBY));
+}
+
+static bool qmc5883l_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return reg <= QMC5883L_REG_STATUS1;
+}
+
+static bool qmc5883l_writable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case QMC5883L_REG_CTRL1:
+ case QMC5883L_REG_CTRL2:
+ case QMC5883L_REG_SET_RESET:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config qmc5883l_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = QMC5883L_REG_ID,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = qmc5883l_volatile_reg,
+ .writeable_reg = qmc5883l_writable_reg,
+};
+
+#define QMC5883L_CHANNEL(_axis) \
+ { \
+ .type = IIO_MAGN, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##_axis, \
+ .address = QMC5883L_AXIS_##_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) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ }
+
+static const struct iio_chan_spec qmc5883l_channels[] = {
+ QMC5883L_CHANNEL(X),
+ QMC5883L_CHANNEL(Y),
+ QMC5883L_CHANNEL(Z),
+};
+
+static int qmc5883l_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct qmc5883l_data *data;
+ struct iio_dev *indio_dev;
+ struct regmap *map;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ map = devm_regmap_init_i2c(client, &qmc5883l_regmap_config);
+ if (IS_ERR(map))
+ return dev_err_probe(dev, PTR_ERR(map),
+ "regmap initialization failed\n");
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable VDD regulator\n");
+
+ ret = devm_regulator_get_enable(dev, "vddio");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable VDDIO regulator\n");
+
+ /* POR completion time max per datasheet Table 7 */
+ fsleep(QMC5883L_PORT_US);
+
+ data = iio_priv(indio_dev);
+ data->regmap = map;
+
+ ret = devm_mutex_init(dev, &data->mutex);
+ if (ret)
+ return ret;
+
+ indio_dev->name = "qmc5883l";
+ indio_dev->info = &qmc5883l_info;
+ indio_dev->channels = qmc5883l_channels;
+ indio_dev->num_channels = ARRAY_SIZE(qmc5883l_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = qmc5883l_init(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "qmc5883l init failed\n");
+
+ ret = devm_add_action_or_reset(dev, qmc5883l_power_down_action, data);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id qmc5883l_match[] = {
+ { .compatible = "qstcorp,qmc5883l" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qmc5883l_match);
+
+static const struct i2c_device_id qmc5883l_id[] = {
+ { .name = "qmc5883l" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, qmc5883l_id);
+
+static struct i2c_driver qmc5883l_driver = {
+ .driver = {
+ .name = "qmc5883l",
+ .of_match_table = qmc5883l_match,
+ },
+ .id_table = qmc5883l_id,
+ .probe = qmc5883l_probe,
+};
+module_i2c_driver(qmc5883l_driver);
+
+MODULE_DESCRIPTION("QST QMC5883L 3-Axis Magnetic Sensor driver");
+MODULE_AUTHOR("Siratul Islam <siratul.islam@linux.dev>");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/iio/magnetometer/qmc6308.c b/drivers/iio/magnetometer/qmc6308.c
new file mode 100644
index 000000000000..72348cd9ef01
--- /dev/null
+++ b/drivers/iio/magnetometer/qmc6308.c
@@ -0,0 +1,601 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Support for QST QMC6308 3-Axis Magnetic Sensor on I2C bus.
+ *
+ * Copyright (C) 2026 Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
+ *
+ * Datasheet available at
+ * <https://qstcorp.com/upload/pdf/202202/13-52-15%20QMC6308%20Datasheet%20Rev.%20F(1).pdf>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/iio/iio.h>
+
+#define QMC6308_REG_ID 0x00
+#define QMC6308_REG_X_LSB 0x01
+#define QMC6308_REG_STATUS 0x09
+#define QMC6308_REG_CTRL1 0x0A
+#define QMC6308_REG_CTRL2 0x0B
+#define QMC6308_REG_CTRL3 0x0D
+#define QMC6308_REG_CTRL4 0x29
+
+#define QMC6308_CHIP_ID 0x80
+
+/* Control register 1 */
+#define QMC6308_MODE_MASK GENMASK(1, 0)
+#define QMC6308_ODR_MASK GENMASK(3, 2)
+#define QMC6308_OSR1_MASK GENMASK(5, 4)
+#define QMC6308_OSR2_MASK GENMASK(7, 6)
+
+#define QMC6308_MODE_SUSPEND 0x00
+#define QMC6308_MODE_NORMAL 0x01
+
+#define QMC6308_ODR_10HZ 0x00
+#define QMC6308_ODR_50HZ 0x01
+#define QMC6308_ODR_100HZ 0x02
+#define QMC6308_ODR_200HZ 0x03
+
+#define QMC6308_OSR1_8 0x00
+#define QMC6308_OSR1_4 0x01
+#define QMC6308_OSR1_2 0x02
+#define QMC6308_OSR1_1 0x03
+
+/* Control register 2 */
+#define QMC6308_SET_RESET_MASK GENMASK(1, 0)
+#define QMC6308_RNG_MASK GENMASK(3, 2)
+#define QMC6308_SELF_TEST BIT(6)
+#define QMC6308_SOFT_RST BIT(7)
+
+#define QMC6308_SET_RESET_ON 0x00
+
+#define QMC6308_RNG_30G 0x00
+#define QMC6308_RNG_12G 0x01
+#define QMC6308_RNG_8G 0x02
+#define QMC6308_RNG_2G 0x03
+
+/* Status register */
+#define QMC6308_STATUS_DRDY BIT(0)
+#define QMC6308_STATUS_OVFL BIT(1)
+
+/* Power-on completion time (datasheet Table 7) */
+#define QMC6308_POR_US 250
+
+#define QMC6308_AUTOSUSPEND_DELAY_MS 500
+
+struct qmc6308_data {
+ struct regmap *regmap;
+ /* Protect data->range/odr/osr and serialize measurements */
+ struct mutex mutex;
+ struct iio_mount_matrix orientation;
+ u8 range;
+ u8 odr;
+ u8 osr;
+};
+
+enum qmc6308_axis {
+ QMC6308_AXIS_X,
+ QMC6308_AXIS_Y,
+ QMC6308_AXIS_Z,
+};
+
+static const int qmc6308_odr_avail[] = {
+ [QMC6308_ODR_10HZ] = 10,
+ [QMC6308_ODR_50HZ] = 50,
+ [QMC6308_ODR_100HZ] = 100,
+ [QMC6308_ODR_200HZ] = 200,
+};
+
+static const int qmc6308_osr1_avail[] = {
+ [QMC6308_OSR1_8] = 8,
+ [QMC6308_OSR1_4] = 4,
+ [QMC6308_OSR1_2] = 2,
+ [QMC6308_OSR1_1] = 1,
+};
+
+/*
+ * Sensitivity is 1000/2500/3750/15000 LSB/Gauss for the
+ * +-30/12/8/2 Gauss ranges respectively.
+ */
+static const int qmc6308_scales[][2] = {
+ [QMC6308_RNG_30G] = { 0, 1000000 },
+ [QMC6308_RNG_12G] = { 0, 400000 },
+ [QMC6308_RNG_8G] = { 0, 266667 },
+ [QMC6308_RNG_2G] = { 0, 66667 },
+};
+
+static int qmc6308_set_mode(struct qmc6308_data *data, unsigned int mode)
+{
+ return regmap_update_bits(data->regmap, QMC6308_REG_CTRL1,
+ QMC6308_MODE_MASK,
+ FIELD_PREP(QMC6308_MODE_MASK, mode));
+}
+
+static int qmc6308_take_measurement(struct iio_dev *indio_dev, int index,
+ int *val)
+{
+ struct qmc6308_data *data = iio_priv(indio_dev);
+ struct device *dev = regmap_get_device(data->regmap);
+ unsigned int status;
+ __le16 buf[3];
+ int ret;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret) {
+ dev_err(dev, "Failed to power on (%d)\n", ret);
+ return ret;
+ }
+
+ guard(mutex)(&data->mutex);
+
+ /*
+ * Reading the status register clears DRDY, which is why the poll
+ * and the data read stay under one mutex hold. A runtime resume
+ * clears DRDY too, so a sample converted before the last suspend
+ * is never returned here.
+ *
+ * The timeout is 50ms of headroom over the slowest ODR (10Hz).
+ */
+ ret = regmap_read_poll_timeout(data->regmap, QMC6308_REG_STATUS,
+ status, (status & QMC6308_STATUS_DRDY),
+ 2 * USEC_PER_MSEC,
+ 150 * USEC_PER_MSEC);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_read(data->regmap, QMC6308_REG_X_LSB, buf,
+ sizeof(buf));
+ if (ret)
+ return ret;
+
+ if (status & QMC6308_STATUS_OVFL)
+ return -ERANGE;
+
+ *val = (s16)le16_to_cpu(buf[index]);
+
+ return 0;
+}
+
+static int qmc6308_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct qmc6308_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = qmc6308_take_measurement(indio_dev, chan->address, val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE: {
+ guard(mutex)(&data->mutex);
+
+ *val = qmc6308_scales[data->range][0];
+ *val2 = qmc6308_scales[data->range][1];
+
+ return IIO_VAL_INT_PLUS_NANO;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ guard(mutex)(&data->mutex);
+
+ *val = qmc6308_odr_avail[data->odr];
+
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: {
+ guard(mutex)(&data->mutex);
+
+ *val = qmc6308_osr1_avail[data->osr];
+
+ return IIO_VAL_INT;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int qmc6308_write_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int val, int val2, long mask)
+{
+ struct qmc6308_data *data = iio_priv(indio_dev);
+ unsigned int status;
+ unsigned int i;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE: {
+ if (val != 0)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(qmc6308_scales); i++) {
+ if (val2 == qmc6308_scales[i][1])
+ break;
+ }
+ if (i == ARRAY_SIZE(qmc6308_scales))
+ return -EINVAL;
+
+ guard(mutex)(&data->mutex);
+
+ ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL2,
+ QMC6308_RNG_MASK,
+ FIELD_PREP(QMC6308_RNG_MASK, i));
+ if (ret)
+ return ret;
+
+ data->range = i;
+
+ /*
+ * The data registers still hold (and DRDY still
+ * advertises) a sample converted at the previous range;
+ * discard it so that a read does not pair old-range data
+ * with the new scale. A conversion already in flight may
+ * still complete at the old range, so this narrows the
+ * window rather than closing it. The range change itself
+ * took effect, so only log a failure here: an error
+ * would mislead userspace about an effective write.
+ */
+ ret = regmap_read(data->regmap, QMC6308_REG_STATUS,
+ &status);
+ if (ret)
+ dev_warn(regmap_get_device(data->regmap),
+ "Failed to discard stale sample (%d)\n", ret);
+
+ return 0;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ for (i = 0; i < ARRAY_SIZE(qmc6308_odr_avail); i++) {
+ if (val == qmc6308_odr_avail[i])
+ break;
+ }
+ if (i == ARRAY_SIZE(qmc6308_odr_avail))
+ return -EINVAL;
+
+ guard(mutex)(&data->mutex);
+
+ ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1,
+ QMC6308_ODR_MASK,
+ FIELD_PREP(QMC6308_ODR_MASK, i));
+ if (ret)
+ return ret;
+
+ data->odr = i;
+
+ return 0;
+ }
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: {
+ for (i = 0; i < ARRAY_SIZE(qmc6308_osr1_avail); i++) {
+ if (val == qmc6308_osr1_avail[i])
+ break;
+ }
+ if (i == ARRAY_SIZE(qmc6308_osr1_avail))
+ return -EINVAL;
+
+ guard(mutex)(&data->mutex);
+
+ ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1,
+ QMC6308_OSR1_MASK,
+ FIELD_PREP(QMC6308_OSR1_MASK, i));
+ if (ret)
+ return ret;
+
+ data->osr = i;
+
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int qmc6308_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 = qmc6308_odr_avail;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(qmc6308_odr_avail);
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = qmc6308_osr1_avail;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(qmc6308_osr1_avail);
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (const int *)qmc6308_scales;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ *length = ARRAY_SIZE(qmc6308_scales) * 2;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int qmc6308_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return IIO_VAL_INT;
+ }
+}
+
+static const struct iio_mount_matrix *
+qmc6308_get_mount_matrix(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct qmc6308_data *data = iio_priv(indio_dev);
+
+ return &data->orientation;
+}
+
+static const struct iio_chan_spec_ext_info qmc6308_ext_info[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, qmc6308_get_mount_matrix),
+ { }
+};
+
+static const struct iio_info qmc6308_info = {
+ .read_raw = qmc6308_read_raw,
+ .write_raw = qmc6308_write_raw,
+ .read_avail = qmc6308_read_avail,
+ .write_raw_get_fmt = qmc6308_write_raw_get_fmt,
+};
+
+static int qmc6308_init(struct qmc6308_data *data)
+{
+ struct regmap *map = data->regmap;
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(map, QMC6308_REG_ID, &reg);
+ if (ret)
+ return ret;
+
+ /* Allow unknown IDs so that fallback compatibles work */
+ if (reg != QMC6308_CHIP_ID)
+ dev_warn(regmap_get_device(map),
+ "Unknown chip id: 0x%02x, continuing\n", reg);
+
+ /* The SOFT_RST bit is not auto-cleared and must be written back 0 */
+ ret = regmap_write(map, QMC6308_REG_CTRL2, QMC6308_SOFT_RST);
+ if (ret)
+ return ret;
+
+ /*
+ * The datasheet gives no soft-reset completion figure; reuse the
+ * power-on time as a conservative bound.
+ */
+ fsleep(QMC6308_POR_US);
+
+ data->range = QMC6308_RNG_30G;
+ data->odr = QMC6308_ODR_50HZ;
+ data->osr = QMC6308_OSR1_8;
+
+ ret = regmap_write(map, QMC6308_REG_CTRL2,
+ FIELD_PREP(QMC6308_SET_RESET_MASK,
+ QMC6308_SET_RESET_ON) |
+ FIELD_PREP(QMC6308_RNG_MASK, data->range));
+ if (ret)
+ return ret;
+
+ /* OSR2 (second-stage filter) set to its power-on default of 0 */
+ return regmap_write(map, QMC6308_REG_CTRL1,
+ FIELD_PREP(QMC6308_MODE_MASK,
+ QMC6308_MODE_NORMAL) |
+ FIELD_PREP(QMC6308_ODR_MASK, data->odr) |
+ FIELD_PREP(QMC6308_OSR1_MASK, data->osr) |
+ FIELD_PREP(QMC6308_OSR2_MASK, 0));
+}
+
+static void qmc6308_power_down_action(void *priv)
+{
+ struct qmc6308_data *data = priv;
+
+ if (!pm_runtime_status_suspended(regmap_get_device(data->regmap)))
+ qmc6308_set_mode(data, QMC6308_MODE_SUSPEND);
+}
+
+static bool qmc6308_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return reg >= QMC6308_REG_X_LSB && reg <= QMC6308_REG_STATUS;
+}
+
+static bool qmc6308_writable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case QMC6308_REG_CTRL1:
+ case QMC6308_REG_CTRL2:
+ case QMC6308_REG_CTRL3:
+ case QMC6308_REG_CTRL4:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config qmc6308_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = QMC6308_REG_CTRL4,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = qmc6308_volatile_reg,
+ .writeable_reg = qmc6308_writable_reg,
+};
+
+#define QMC6308_CHANNEL(_axis) \
+ { \
+ .type = IIO_MAGN, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##_axis, \
+ .address = QMC6308_AXIS_##_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) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .ext_info = qmc6308_ext_info, \
+ }
+
+static const struct iio_chan_spec qmc6308_channels[] = {
+ QMC6308_CHANNEL(X),
+ QMC6308_CHANNEL(Y),
+ QMC6308_CHANNEL(Z),
+};
+
+static int qmc6308_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct qmc6308_data *data;
+ struct iio_dev *indio_dev;
+ struct regmap *map;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, indio_dev);
+
+ map = devm_regmap_init_i2c(client, &qmc6308_regmap_config);
+ if (IS_ERR(map))
+ return dev_err_probe(dev, PTR_ERR(map),
+ "regmap initialization failed\n");
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable VDD regulator\n");
+
+ fsleep(QMC6308_POR_US);
+
+ data = iio_priv(indio_dev);
+ data->regmap = map;
+
+ ret = devm_mutex_init(dev, &data->mutex);
+ if (ret)
+ return ret;
+
+ ret = iio_read_mount_matrix(dev, &data->orientation);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to read mount matrix\n");
+
+ indio_dev->name = "qmc6308";
+ indio_dev->info = &qmc6308_info;
+ indio_dev->channels = qmc6308_channels;
+ indio_dev->num_channels = ARRAY_SIZE(qmc6308_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = qmc6308_init(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "qmc6308 init failed\n");
+
+ ret = pm_runtime_set_active(dev);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, qmc6308_power_down_action, data);
+ if (ret)
+ return ret;
+
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_autosuspend_delay(dev, QMC6308_AUTOSUSPEND_DELAY_MS);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static int qmc6308_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct qmc6308_data *data = iio_priv(indio_dev);
+
+ return qmc6308_set_mode(data, QMC6308_MODE_SUSPEND);
+}
+
+static int qmc6308_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct qmc6308_data *data = iio_priv(indio_dev);
+ unsigned int status;
+ int ret;
+
+ ret = qmc6308_set_mode(data, QMC6308_MODE_NORMAL);
+ if (ret)
+ return ret;
+
+ /*
+ * DRDY may still be set for a sample converted before the last
+ * suspend; reading the status register clears it so the next
+ * measurement waits for fresh data.
+ */
+ ret = regmap_read(data->regmap, QMC6308_REG_STATUS, &status);
+ if (ret) {
+ /* Best effort to leave the chip in a consistent state */
+ qmc6308_set_mode(data, QMC6308_MODE_SUSPEND);
+ }
+
+ return ret;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(qmc6308_pm_ops, qmc6308_runtime_suspend,
+ qmc6308_runtime_resume, NULL);
+
+static const struct of_device_id qmc6308_match[] = {
+ { .compatible = "qstcorp,qmc6308" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qmc6308_match);
+
+static const struct i2c_device_id qmc6308_id[] = {
+ { .name = "qmc6308" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, qmc6308_id);
+
+static struct i2c_driver qmc6308_driver = {
+ .driver = {
+ .name = "qmc6308",
+ .of_match_table = qmc6308_match,
+ .pm = pm_ptr(&qmc6308_pm_ops),
+ },
+ .id_table = qmc6308_id,
+ .probe = qmc6308_probe,
+};
+module_i2c_driver(qmc6308_driver);
+
+MODULE_DESCRIPTION("QST QMC6308 3-Axis Magnetic Sensor driver");
+MODULE_AUTHOR("Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c
index 2b2884425746..46fce2978d76 100644
--- a/drivers/iio/magnetometer/rm3100-core.c
+++ b/drivers/iio/magnetometer/rm3100-core.c
@@ -204,27 +204,23 @@ static int rm3100_read_mag(struct rm3100_data *data, int idx, int *val)
u8 buffer[3];
int ret;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
+
ret = regmap_write(regmap, RM3100_REG_POLL, BIT(4 + idx));
if (ret < 0)
- goto unlock_return;
+ return ret;
ret = rm3100_wait_measurement(data);
if (ret < 0)
- goto unlock_return;
+ return ret;
ret = regmap_bulk_read(regmap, RM3100_REG_MX2 + 3 * idx, buffer, 3);
if (ret < 0)
- goto unlock_return;
- mutex_unlock(&data->lock);
+ return ret;
*val = sign_extend32(get_unaligned_be24(&buffer[0]), 23);
return IIO_VAL_INT;
-
-unlock_return:
- mutex_unlock(&data->lock);
- return ret;
}
#define RM3100_CHANNEL(axis, idx) \
@@ -284,11 +280,12 @@ static int rm3100_get_samp_freq(struct rm3100_data *data, int *val, int *val2)
unsigned int tmp;
int ret;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
+
ret = regmap_read(data->regmap, RM3100_REG_TMRC, &tmp);
- mutex_unlock(&data->lock);
if (ret < 0)
return ret;
+
*val = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][0];
*val2 = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][1];
@@ -338,56 +335,50 @@ static int rm3100_set_samp_freq(struct iio_dev *indio_dev, int val, int val2)
int ret;
int i;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
+
/* All cycle count registers use the same value. */
ret = regmap_read(regmap, RM3100_REG_CC_X, &cycle_count);
if (ret < 0)
- goto unlock_return;
+ return ret;
for (i = 0; i < RM3100_SAMP_NUM; i++) {
if (val == rm3100_samp_rates[i][0] &&
val2 == rm3100_samp_rates[i][1])
break;
}
- if (i == RM3100_SAMP_NUM) {
- ret = -EINVAL;
- goto unlock_return;
- }
+ if (i == RM3100_SAMP_NUM)
+ return -EINVAL;
ret = regmap_write(regmap, RM3100_REG_TMRC, i + RM3100_TMRC_OFFSET);
if (ret < 0)
- goto unlock_return;
+ return ret;
/* Checking if cycle count registers need changing. */
if (val == 600 && cycle_count == 200) {
ret = rm3100_set_cycle_count(data, 100);
if (ret < 0)
- goto unlock_return;
+ return ret;
} else if (val != 600 && cycle_count == 100) {
ret = rm3100_set_cycle_count(data, 200);
if (ret < 0)
- goto unlock_return;
+ return ret;
}
if (iio_buffer_enabled(indio_dev)) {
/* Writing TMRC registers requires CMM reset. */
ret = regmap_write(regmap, RM3100_REG_CMM, 0);
if (ret < 0)
- goto unlock_return;
+ return ret;
ret = regmap_write(data->regmap, RM3100_REG_CMM,
(*indio_dev->active_scan_mask & 0x7) <<
RM3100_CMM_AXIS_SHIFT | RM3100_CMM_START);
if (ret < 0)
- goto unlock_return;
+ return ret;
}
- mutex_unlock(&data->lock);
data->conversion_time = rm3100_samp_rates[i][2] * 2;
return 0;
-
-unlock_return:
- mutex_unlock(&data->lock);
- return ret;
}
static int rm3100_read_raw(struct iio_dev *indio_dev,
@@ -458,6 +449,27 @@ static const struct iio_buffer_setup_ops rm3100_buffer_ops = {
.postdisable = rm3100_buffer_postdisable,
};
+/**
+ * rm3100_regmap_bulk_read_locked() - Wrapper around regmap_bulk_read() with a mutex
+ *
+ * @data: Data structure containing regmap and mutex
+ * @reg: First register to be read from, passed to regmap_bulk_read()
+ * @val: Pointer to store read value, in native register size for device,
+ * passed to regmap_bulk_read()
+ * @val_count: Number of registers to read, passed to regmap_bulk_read()
+ *
+ * Intended for use only in rm3100_trigger_handler().
+ *
+ * Return:
+ * A value of zero on success, a negative errno in error cases.
+ */
+static int rm3100_regmap_bulk_read_locked(struct rm3100_data *data, unsigned int reg,
+ void *val, size_t val_count)
+{
+ guard(mutex)(&data->lock);
+ return regmap_bulk_read(data->regmap, reg, val, val_count);
+}
+
static irqreturn_t rm3100_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
@@ -465,14 +477,12 @@ static irqreturn_t rm3100_trigger_handler(int irq, void *p)
unsigned long scan_mask = *indio_dev->active_scan_mask;
unsigned int mask_len = iio_get_masklength(indio_dev);
struct rm3100_data *data = iio_priv(indio_dev);
- struct regmap *regmap = data->regmap;
int ret, i, bit;
- mutex_lock(&data->lock);
switch (scan_mask) {
case BIT(0) | BIT(1) | BIT(2):
- ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 9);
- mutex_unlock(&data->lock);
+ ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MX2,
+ data->buffer, 9);
if (ret < 0)
goto done;
/* Convert XXXYYYZZZxxx to XXXxYYYxZZZx. x for paddings. */
@@ -480,36 +490,34 @@ static irqreturn_t rm3100_trigger_handler(int irq, void *p)
memmove(data->buffer + i * 4, data->buffer + i * 3, 3);
break;
case BIT(0) | BIT(1):
- ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 6);
- mutex_unlock(&data->lock);
+ ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MX2,
+ data->buffer, 6);
if (ret < 0)
goto done;
memmove(data->buffer + 4, data->buffer + 3, 3);
break;
case BIT(1) | BIT(2):
- ret = regmap_bulk_read(regmap, RM3100_REG_MY2, data->buffer, 6);
- mutex_unlock(&data->lock);
+ ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MY2,
+ data->buffer, 6);
if (ret < 0)
goto done;
memmove(data->buffer + 4, data->buffer + 3, 3);
break;
case BIT(0) | BIT(2):
- ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 9);
- mutex_unlock(&data->lock);
+ ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MX2,
+ data->buffer, 9);
if (ret < 0)
goto done;
memmove(data->buffer + 4, data->buffer + 6, 3);
break;
default:
for_each_set_bit(bit, &scan_mask, mask_len) {
- ret = regmap_bulk_read(regmap, RM3100_REG_MX2 + 3 * bit,
- data->buffer, 3);
- if (ret < 0) {
- mutex_unlock(&data->lock);
+ ret = rm3100_regmap_bulk_read_locked(data,
+ RM3100_REG_MX2 + 3 * bit,
+ data->buffer, 3);
+ if (ret < 0)
goto done;
- }
}
- mutex_unlock(&data->lock);
}
/*
* Always using the same buffer so that we wouldn't need to set the
@@ -560,10 +568,8 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq)
IRQF_ONESHOT,
indio_dev->name,
indio_dev);
- if (ret < 0) {
- dev_err(dev, "request irq line failed.\n");
+ if (ret)
return ret;
- }
data->drdy_trig = devm_iio_trigger_alloc(dev, "%s-drdy%d",
indio_dev->name,
diff --git a/drivers/iio/magnetometer/si7210.c b/drivers/iio/magnetometer/si7210.c
index 27e3feba7a0f..e9670d671a28 100644
--- a/drivers/iio/magnetometer/si7210.c
+++ b/drivers/iio/magnetometer/si7210.c
@@ -16,7 +16,6 @@
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/math64.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -128,8 +127,8 @@ static const struct regmap_config si7210_regmap_conf = {
struct si7210_data {
struct regmap *regmap;
struct i2c_client *client;
- struct regulator *vdd;
struct mutex fetch_lock; /* lock for a single measurement fetch */
+ unsigned int vdd_uV;
s8 temp_offset;
s8 temp_gain;
s8 scale_20_a[A_REGS_COUNT];
@@ -221,12 +220,8 @@ static int si7210_read_raw(struct iio_dev *indio_dev,
temp *= (1 + (data->temp_gain / 2048));
temp += (int)(MICRO / 16) * data->temp_offset;
- ret = regulator_get_voltage(data->vdd);
- if (ret < 0)
- return ret;
-
/* temp -= 0.222 * VDD */
- temp -= 222 * div_s64(ret, MILLI);
+ temp -= 222 * (data->vdd_uV / MILLI);
*val = div_s64(temp, MILLI);
@@ -396,14 +391,11 @@ static int si7210_probe(struct i2c_client *client)
return dev_err_probe(&client->dev, PTR_ERR(data->regmap),
"failed to register regmap\n");
- data->vdd = devm_regulator_get(&client->dev, "vdd");
- if (IS_ERR(data->vdd))
- return dev_err_probe(&client->dev, PTR_ERR(data->vdd),
- "failed to get VDD regulator\n");
-
- ret = regulator_enable(data->vdd);
- if (ret)
- return ret;
+ ret = devm_regulator_get_enable_read_voltage(&client->dev, "vdd");
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to get vdd regulator\n");
+ data->vdd_uV = ret;
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -420,7 +412,7 @@ static int si7210_probe(struct i2c_client *client)
}
static const struct i2c_device_id si7210_id[] = {
- { "si7210" },
+ { .name = "si7210" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si7210_id);
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
index ef348d316c00..7644bd04654b 100644
--- a/drivers/iio/magnetometer/st_magn_core.c
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -506,6 +506,11 @@ static const struct st_sensors_platform_data default_magn_pdata = {
.drdy_int_pin = 2,
};
+/* LIS2MDL only supports DRDY on INT1 */
+static const struct st_sensors_platform_data alt_magn_pdata = {
+ .drdy_int_pin = 1,
+};
+
static int st_magn_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *ch, int *val,
int *val2, long mask)
@@ -628,8 +633,12 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
mdata->current_fullscale = &mdata->sensor_settings->fs.fs_avl[0];
mdata->odr = mdata->sensor_settings->odr.odr_avl[0].hz;
- if (!pdata)
- pdata = (struct st_sensors_platform_data *)&default_magn_pdata;
+ if (!pdata) {
+ if (mdata->sensor_settings->drdy_irq.int2.mask)
+ pdata = (struct st_sensors_platform_data *)&default_magn_pdata;
+ else
+ pdata = (struct st_sensors_platform_data *)&alt_magn_pdata;
+ }
err = st_sensors_init_sensor(indio_dev, pdata);
if (err < 0)
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
index ed70e782af5e..de66016811db 100644
--- a/drivers/iio/magnetometer/st_magn_i2c.c
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
@@ -93,15 +92,15 @@ static int st_magn_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id st_magn_id_table[] = {
- { LSM303DLH_MAGN_DEV_NAME },
- { LSM303DLHC_MAGN_DEV_NAME },
- { LSM303DLM_MAGN_DEV_NAME },
- { LIS3MDL_MAGN_DEV_NAME },
- { LSM303AGR_MAGN_DEV_NAME },
- { LIS2MDL_MAGN_DEV_NAME },
- { LSM9DS1_MAGN_DEV_NAME },
- { IIS2MDC_MAGN_DEV_NAME },
- { LSM303C_MAGN_DEV_NAME },
+ { .name = LSM303DLH_MAGN_DEV_NAME },
+ { .name = LSM303DLHC_MAGN_DEV_NAME },
+ { .name = LSM303DLM_MAGN_DEV_NAME },
+ { .name = LIS3MDL_MAGN_DEV_NAME },
+ { .name = LSM303AGR_MAGN_DEV_NAME },
+ { .name = LIS2MDL_MAGN_DEV_NAME },
+ { .name = LSM9DS1_MAGN_DEV_NAME },
+ { .name = IIS2MDC_MAGN_DEV_NAME },
+ { .name = LSM303C_MAGN_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
index 68816362bb95..af4642b6c3c0 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
@@ -88,12 +87,12 @@ static int st_magn_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id st_magn_id_table[] = {
- { LIS3MDL_MAGN_DEV_NAME },
- { LSM303AGR_MAGN_DEV_NAME },
- { LIS2MDL_MAGN_DEV_NAME },
- { LSM9DS1_MAGN_DEV_NAME },
- { IIS2MDC_MAGN_DEV_NAME },
- { LSM303C_MAGN_DEV_NAME },
+ { .name = LIS3MDL_MAGN_DEV_NAME },
+ { .name = LSM303AGR_MAGN_DEV_NAME },
+ { .name = LIS2MDL_MAGN_DEV_NAME },
+ { .name = LSM9DS1_MAGN_DEV_NAME },
+ { .name = IIS2MDC_MAGN_DEV_NAME },
+ { .name = LSM303C_MAGN_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(spi, st_magn_id_table);
diff --git a/drivers/iio/magnetometer/tlv493d.c b/drivers/iio/magnetometer/tlv493d.c
index e5e050af2b74..03415cc2c9b3 100644
--- a/drivers/iio/magnetometer/tlv493d.c
+++ b/drivers/iio/magnetometer/tlv493d.c
@@ -14,7 +14,6 @@
#include <linux/i2c.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -499,7 +498,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(tlv493d_pm_ops, tlv493d_runtime_suspend,
tlv493d_runtime_resume, NULL);
static const struct i2c_device_id tlv493d_id[] = {
- { "tlv493d" },
+ { .name = "tlv493d" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tlv493d_id);
diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c
index 2adc3c036ab4..155294b66924 100644
--- a/drivers/iio/magnetometer/tmag5273.c
+++ b/drivers/iio/magnetometer/tmag5273.c
@@ -708,7 +708,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(tmag5273_pm_ops,
NULL);
static const struct i2c_device_id tmag5273_id[] = {
- { "tmag5273" },
+ { .name = "tmag5273" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmag5273_id);
diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c
index d49e37edcbed..f9afe9a59464 100644
--- a/drivers/iio/magnetometer/yamaha-yas530.c
+++ b/drivers/iio/magnetometer/yamaha-yas530.c
@@ -29,7 +29,6 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -168,6 +167,7 @@ struct yas5xx;
/**
* struct yas5xx_chip_info - device-specific data and function pointers
* @devid: device ID number
+ * @product_label: product label used in Linux
* @product_name: product name of the YAS variant
* @version_names: version letters or namings
* @volatile_reg: device-specific volatile registers
@@ -189,6 +189,7 @@ struct yas5xx;
*/
struct yas5xx_chip_info {
unsigned int devid;
+ const char *product_label;
const char *product_name;
const char *version_names[2];
const int *volatile_reg;
@@ -859,9 +860,9 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx)
c->f[0] = FIELD_GET(GENMASK(22, 21), val);
c->f[1] = FIELD_GET(GENMASK(14, 13), val);
c->f[2] = FIELD_GET(GENMASK(6, 5), val);
- c->r[0] = sign_extend32(FIELD_GET(GENMASK(28, 23), val), 5);
- c->r[1] = sign_extend32(FIELD_GET(GENMASK(20, 15), val), 5);
- c->r[2] = sign_extend32(FIELD_GET(GENMASK(12, 7), val), 5);
+ c->r[0] = FIELD_GET_SIGNED(GENMASK(28, 23), val);
+ c->r[1] = FIELD_GET_SIGNED(GENMASK(20, 15), val);
+ c->r[2] = FIELD_GET_SIGNED(GENMASK(12, 7), val);
return 0;
}
@@ -914,9 +915,9 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx)
c->f[0] = FIELD_GET(GENMASK(24, 23), val);
c->f[1] = FIELD_GET(GENMASK(16, 15), val);
c->f[2] = FIELD_GET(GENMASK(8, 7), val);
- c->r[0] = sign_extend32(FIELD_GET(GENMASK(30, 25), val), 5);
- c->r[1] = sign_extend32(FIELD_GET(GENMASK(22, 17), val), 5);
- c->r[2] = sign_extend32(FIELD_GET(GENMASK(14, 7), val), 5);
+ c->r[0] = FIELD_GET_SIGNED(GENMASK(30, 25), val);
+ c->r[1] = FIELD_GET_SIGNED(GENMASK(22, 17), val);
+ c->r[2] = FIELD_GET_SIGNED(GENMASK(14, 7), val);
return 0;
}
@@ -1223,7 +1224,7 @@ static int yas530_measure_offsets(struct yas5xx *yas5xx)
* as the values for [x, y1, y2]. The value is +/-31
* but the effect on the raw values is much larger.
* The effect of the offset is to bring the measure
- * rougly to the center.
+ * roughly to the center.
*/
ox = 0;
oy1 = 0;
@@ -1315,7 +1316,7 @@ static int yas537_power_on(struct yas5xx *yas5xx)
return ret;
/* Wait until the coil has ramped up */
- usleep_range(YAS537_MAG_RCOIL_TIME_US, YAS537_MAG_RCOIL_TIME_US + 100);
+ fsleep(YAS537_MAG_RCOIL_TIME_US);
return 0;
}
@@ -1323,6 +1324,7 @@ static int yas537_power_on(struct yas5xx *yas5xx)
static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
[yas530] = {
.devid = YAS530_DEVICE_ID,
+ .product_label = "yas530",
.product_name = "YAS530 MS-3E",
.version_names = { "A", "B" },
.volatile_reg = yas530_volatile_reg,
@@ -1338,6 +1340,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
},
[yas532] = {
.devid = YAS532_DEVICE_ID,
+ .product_label = "yas532",
.product_name = "YAS532 MS-3R",
.version_names = { "AB", "AC" },
.volatile_reg = yas530_volatile_reg,
@@ -1353,6 +1356,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
},
[yas533] = {
.devid = YAS532_DEVICE_ID,
+ .product_label = "yas533",
.product_name = "YAS533 MS-3F",
.version_names = { "AB", "AC" },
.volatile_reg = yas530_volatile_reg,
@@ -1368,6 +1372,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
},
[yas537] = {
.devid = YAS537_DEVICE_ID,
+ .product_label = "yas537",
.product_name = "YAS537 MS-3T",
.version_names = { "v0", "v1" }, /* version naming unknown */
.volatile_reg = yas537_volatile_reg,
@@ -1385,7 +1390,6 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
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;
@@ -1400,7 +1404,10 @@ static int yas5xx_probe(struct i2c_client *i2c)
yas5xx = iio_priv(indio_dev);
i2c_set_clientdata(i2c, indio_dev);
yas5xx->dev = dev;
- mutex_init(&yas5xx->lock);
+
+ ret = devm_mutex_init(dev, &yas5xx->lock);
+ if (ret)
+ return ret;
ret = iio_read_mount_matrix(dev, &yas5xx->orientation);
if (ret)
@@ -1418,7 +1425,7 @@ static int yas5xx_probe(struct i2c_client *i2c)
return dev_err_probe(dev, ret, "cannot enable regulators\n");
/* See comment in runtime resume callback */
- usleep_range(31000, 40000);
+ fsleep(31 * USEC_PER_MSEC);
/* This will take the device out of reset if need be */
yas5xx->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
@@ -1443,7 +1450,7 @@ static int yas5xx_probe(struct i2c_client *i2c)
if (id_check != ci->devid) {
ret = dev_err_probe(dev, -ENODEV,
"device ID %02x doesn't match %s\n",
- id_check, id->name);
+ id_check, ci->product_label);
goto assert_reset;
}
@@ -1469,7 +1476,7 @@ static int yas5xx_probe(struct i2c_client *i2c)
indio_dev->info = &yas5xx_info;
indio_dev->available_scan_masks = yas5xx_scan_masks;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->name = id->name;
+ indio_dev->name = ci->product_label;
indio_dev->channels = yas5xx_channels;
indio_dev->num_channels = ARRAY_SIZE(yas5xx_channels);
@@ -1557,7 +1564,7 @@ static int yas5xx_runtime_resume(struct device *dev)
* for all voltages to settle. The YAS532 is 10ms then 4ms for the
* I2C to come online. Let's keep it safe and put this at 31ms.
*/
- usleep_range(31000, 40000);
+ fsleep(31 * USEC_PER_MSEC);
gpiod_set_value_cansleep(yas5xx->reset, 0);
ret = ci->power_on(yas5xx);
@@ -1579,10 +1586,10 @@ static DEFINE_RUNTIME_DEV_PM_OPS(yas5xx_dev_pm_ops, yas5xx_runtime_suspend,
yas5xx_runtime_resume, NULL);
static const struct i2c_device_id yas5xx_id[] = {
- {"yas530", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas530] },
- {"yas532", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas532] },
- {"yas533", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas533] },
- {"yas537", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas537] },
+ { .name = "yas530", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas530] },
+ { .name = "yas532", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas532] },
+ { .name = "yas533", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas533] },
+ { .name = "yas537", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas537] },
{ }
};
MODULE_DEVICE_TABLE(i2c, yas5xx_id);
diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
index b742ca9a99d1..562457a67382 100644
--- a/drivers/iio/multiplexer/iio-mux.c
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -11,7 +11,6 @@
#include <linux/err.h>
#include <linux/iio/consumer.h>
#include <linux/iio/iio.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/mux/consumer.h>
@@ -464,3 +463,4 @@ module_platform_driver(mux_driver);
MODULE_DESCRIPTION("IIO multiplexer driver");
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c
index 4e23a598a3fb..aea28321db95 100644
--- a/drivers/iio/orientation/hid-sensor-incl-3d.c
+++ b/drivers/iio/orientation/hid-sensor-incl-3d.c
@@ -7,7 +7,6 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
@@ -86,8 +85,7 @@ static const struct iio_chan_spec incl_3d_channels[] = {
};
/* Adjust channel real bits based on report descriptor */
-static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan,
- int size)
+static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, int size)
{
chan->scan_type.sign = 's';
/* Real storage bits will change based on the report desc. */
@@ -98,9 +96,8 @@ static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan,
/* Channel read_raw handler */
static int incl_3d_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct incl_3d_state *incl_state = iio_priv(indio_dev);
int report_id = -1;
@@ -125,7 +122,7 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev,
min < 0);
else {
hid_sensor_power_state(&incl_state->common_attributes,
- false);
+ false);
return -EINVAL;
}
hid_sensor_power_state(&incl_state->common_attributes, false);
@@ -158,10 +155,8 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int incl_3d_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct incl_3d_state *incl_state = iio_priv(indio_dev);
int ret;
@@ -189,8 +184,7 @@ static const struct iio_info incl_3d_info = {
/* Callback handler to send event after all samples are received and captured */
static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct incl_3d_state *incl_state = iio_priv(indio_dev);
@@ -212,9 +206,9 @@ static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct incl_3d_state *incl_state = iio_priv(indio_dev);
@@ -247,7 +241,7 @@ static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
static int incl_3d_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
struct iio_chan_spec *channels,
- unsigned usage_id,
+ u32 usage_id,
struct incl_3d_state *st)
{
int ret;
@@ -307,7 +301,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct incl_3d_state));
- if (indio_dev == NULL)
+ if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -350,33 +344,33 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
atomic_set(&incl_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &incl_state->common_attributes);
+ &incl_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
incl_state->callbacks.send_event = incl_3d_proc_event;
incl_state->callbacks.capture_sample = incl_3d_capture_sample;
incl_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev,
- HID_USAGE_SENSOR_INCLINOMETER_3D,
- &incl_state->callbacks);
+ HID_USAGE_SENSOR_INCLINOMETER_3D,
+ &incl_state->callbacks);
if (ret) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return 0;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
return ret;
@@ -389,8 +383,8 @@ static void hid_incl_3d_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct incl_3d_state *incl_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D);
hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
}
diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
index e759f91a710a..f8c98f866cb0 100644
--- a/drivers/iio/orientation/hid-sensor-rotation.c
+++ b/drivers/iio/orientation/hid-sensor-rotation.c
@@ -7,7 +7,6 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -19,8 +18,13 @@ struct dev_rot_state {
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info quaternion;
struct {
- s32 sampled_vals[4];
- aligned_s64 timestamp;
+ IIO_DECLARE_QUATERNION(s32, sampled_vals);
+ /*
+ * ABI regression avoidance: There are two copies of the same
+ * timestamp in case of userspace depending on broken alignment
+ * from older kernels.
+ */
+ aligned_s64 timestamp[2];
} scan;
int scale_pre_decml;
int scale_post_decml;
@@ -34,6 +38,27 @@ static const u32 rotation_sensitivity_addresses[] = {
HID_USAGE_SENSOR_ORIENT_QUATERNION,
};
+enum {
+ DEV_ROT_SCAN_TYPE_16BIT,
+ DEV_ROT_SCAN_TYPE_32BIT,
+};
+
+static const struct iio_scan_type dev_rot_scan_types[] = {
+ [DEV_ROT_SCAN_TYPE_16BIT] = {
+ .sign = 's',
+ .realbits = 16,
+ /* Storage bits has to stay 32 to not break userspace. */
+ .storagebits = 32,
+ .repeat = 4,
+ },
+ [DEV_ROT_SCAN_TYPE_32BIT] = {
+ .sign = 's',
+ .realbits = 32,
+ .storagebits = 32,
+ .repeat = 4,
+ },
+};
+
/* Channel definitions */
static const struct iio_chan_spec dev_rot_channels[] = {
{
@@ -45,30 +70,27 @@ static const struct iio_chan_spec dev_rot_channels[] = {
BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
- .scan_index = 0
+ .scan_index = 0,
+ .has_ext_scan_type = 1,
+ .ext_scan_type = dev_rot_scan_types,
+ .num_ext_scan_type = ARRAY_SIZE(dev_rot_scan_types),
},
IIO_CHAN_SOFT_TIMESTAMP(1)
};
-/* Adjust channel real bits based on report descriptor */
-static void dev_rot_adjust_channel_bit_mask(struct iio_chan_spec *chan,
- int size)
-{
- chan->scan_type.sign = 's';
- /* Real storage bits will change based on the report desc. */
- chan->scan_type.realbits = size * 8;
- /* Maximum size of a sample to capture is u32 */
- chan->scan_type.storagebits = sizeof(u32) * 8;
- chan->scan_type.repeat = 4;
-}
-
/* Channel read_raw handler */
static int dev_rot_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int size, int *vals, int *val_len,
- long mask)
+ struct iio_chan_spec const *chan,
+ int size, int *vals, int *val_len, long mask)
{
struct dev_rot_state *rot_state = iio_priv(indio_dev);
+ struct hid_sensor_hub_device *hsdev = rot_state->common_attributes.hsdev;
+ struct hid_sensor_hub_attribute_info *info = &rot_state->quaternion;
+ u32 usage_id = HID_USAGE_SENSOR_ORIENT_QUATERNION;
+ union {
+ s16 val16[4];
+ s32 val32[4];
+ } raw_buf;
int ret_type;
int i;
@@ -78,8 +100,37 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (size >= 4) {
- for (i = 0; i < 4; ++i)
- vals[i] = rot_state->scan.sampled_vals[i];
+ if (info->size <= 0 || info->size > sizeof(raw_buf))
+ return -EINVAL;
+
+ hid_sensor_power_state(&rot_state->common_attributes, true);
+
+ ret_type = sensor_hub_input_attr_read_values(hsdev,
+ hsdev->usage,
+ usage_id,
+ info->report_id,
+ SENSOR_HUB_SYNC,
+ info->size,
+ (u8 *)&raw_buf);
+
+ hid_sensor_power_state(&rot_state->common_attributes, false);
+
+ if (ret_type < 0)
+ return ret_type;
+
+ switch (info->size) {
+ case sizeof(raw_buf.val16):
+ for (i = 0; i < ARRAY_SIZE(raw_buf.val16); i++)
+ vals[i] = raw_buf.val16[i];
+ break;
+ case sizeof(raw_buf.val32):
+ for (i = 0; i < ARRAY_SIZE(raw_buf.val32); i++)
+ vals[i] = raw_buf.val32[i];
+ break;
+ default:
+ return -EINVAL;
+ }
+
ret_type = IIO_VAL_INT_MULTIPLE;
*val_len = 4;
} else
@@ -112,10 +163,8 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int dev_rot_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct dev_rot_state *rot_state = iio_priv(indio_dev);
int ret;
@@ -136,15 +185,30 @@ static int dev_rot_write_raw(struct iio_dev *indio_dev,
return ret;
}
+static int dev_rot_get_current_scan_type(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct dev_rot_state *rot_state = iio_priv(indio_dev);
+
+ switch (rot_state->quaternion.size / 4) {
+ case sizeof(s16):
+ return DEV_ROT_SCAN_TYPE_16BIT;
+ case sizeof(s32):
+ return DEV_ROT_SCAN_TYPE_32BIT;
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct iio_info dev_rot_info = {
.read_raw_multi = &dev_rot_read_raw,
.write_raw = &dev_rot_write_raw,
+ .get_current_scan_type = &dev_rot_get_current_scan_type,
};
/* Callback handler to send event after all samples are received and captured */
static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct dev_rot_state *rot_state = iio_priv(indio_dev);
@@ -154,8 +218,19 @@ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev,
if (!rot_state->timestamp)
rot_state->timestamp = iio_get_time_ns(indio_dev);
- iio_push_to_buffers_with_timestamp(indio_dev, &rot_state->scan,
- rot_state->timestamp);
+ /*
+ * ABI regression avoidance: IIO previously had an incorrect
+ * implementation of iio_push_to_buffers_with_timestamp() that
+ * put the timestamp in the last 8 bytes of the buffer, which
+ * was incorrect according to the IIO ABI. To avoid breaking
+ * userspace that may be depending on this broken behavior, we
+ * put the timestamp in both the correct place [0] and the old
+ * incorrect place [1].
+ */
+ rot_state->scan.timestamp[0] = rot_state->timestamp;
+ rot_state->scan.timestamp[1] = rot_state->timestamp;
+
+ iio_push_to_buffers(indio_dev, &rot_state->scan);
rot_state->timestamp = 0;
}
@@ -165,9 +240,9 @@ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct dev_rot_state *rot_state = iio_priv(indio_dev);
@@ -196,8 +271,7 @@ static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int dev_rot_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
- struct iio_chan_spec *channels,
- unsigned usage_id,
+ u32 usage_id,
struct dev_rot_state *st)
{
int ret;
@@ -210,9 +284,6 @@ static int dev_rot_parse_report(struct platform_device *pdev,
if (ret)
return ret;
- dev_rot_adjust_channel_bit_mask(&channels[0],
- st->quaternion.size / 4);
-
dev_dbg(&pdev->dev, "dev_rot %x:%x\n", st->quaternion.index,
st->quaternion.report_id);
@@ -238,7 +309,7 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct dev_rot_state));
- if (indio_dev == NULL)
+ if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -271,22 +342,13 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
return ret;
}
- indio_dev->channels = devm_kmemdup(&pdev->dev, dev_rot_channels,
- sizeof(dev_rot_channels),
- GFP_KERNEL);
- if (!indio_dev->channels) {
- dev_err(&pdev->dev, "failed to duplicate channels\n");
- return -ENOMEM;
- }
-
- ret = dev_rot_parse_report(pdev, hsdev,
- (struct iio_chan_spec *)indio_dev->channels,
- hsdev->usage, rot_state);
+ ret = dev_rot_parse_report(pdev, hsdev, hsdev->usage, rot_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
return ret;
}
+ indio_dev->channels = dev_rot_channels;
indio_dev->num_channels = ARRAY_SIZE(dev_rot_channels);
indio_dev->info = &dev_rot_info;
indio_dev->name = name;
@@ -295,32 +357,32 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
atomic_set(&rot_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &rot_state->common_attributes);
+ &rot_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
rot_state->callbacks.send_event = dev_rot_proc_event;
rot_state->callbacks.capture_sample = dev_rot_capture_sample;
rot_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, hsdev->usage,
- &rot_state->callbacks);
+ &rot_state->callbacks);
if (ret) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return 0;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes);
return ret;
@@ -333,8 +395,8 @@ static void hid_dev_rot_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct dev_rot_state *rot_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes);
}
diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
index a26d391661fd..d275bc1413fe 100644
--- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c
+++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
@@ -8,7 +8,6 @@
#include <linux/iio/iio.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -107,8 +106,8 @@ static void hinge_adjust_channel_realbits(struct iio_chan_spec *channels,
/* Channel read_raw handler */
static int hinge_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct hinge_state *st = iio_priv(indio_dev);
struct hid_sensor_hub_device *hsdev;
@@ -154,8 +153,8 @@ static int hinge_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int hinge_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int val, int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct hinge_state *st = iio_priv(indio_dev);
@@ -190,7 +189,7 @@ static const struct iio_info hinge_info = {
* and captured.
*/
static int hinge_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned int usage_id, void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct hinge_state *st = iio_priv(indio_dev);
@@ -209,8 +208,9 @@ static int hinge_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int hinge_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned int usage_id, size_t raw_len,
- char *raw_data, void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct hinge_state *st = iio_priv(indio_dev);
@@ -236,7 +236,7 @@ static int hinge_capture_sample(struct hid_sensor_hub_device *hsdev,
static int hinge_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
struct iio_chan_spec *channels,
- unsigned int usage_id, struct hinge_state *st)
+ u32 usage_id, struct hinge_state *st)
{
int ret;
int i;
@@ -292,7 +292,7 @@ static int hid_hinge_probe(struct platform_device *pdev)
}
indio_dev->num_channels = ARRAY_SIZE(hinge_channels);
- indio_dev->channels = devm_kmemdup(&indio_dev->dev, hinge_channels,
+ indio_dev->channels = devm_kmemdup(&pdev->dev, hinge_channels,
sizeof(hinge_channels), GFP_KERNEL);
if (!indio_dev->channels)
return -ENOMEM;
diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c
index 672b1ca3a920..35fe1575e972 100644
--- a/drivers/iio/potentiometer/ad5272.c
+++ b/drivers/iio/potentiometer/ad5272.c
@@ -15,7 +15,6 @@
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#define AD5272_RDAC_WR 1
#define AD5272_RDAC_RD 2
@@ -204,11 +203,11 @@ static const struct of_device_id ad5272_dt_ids[] = {
MODULE_DEVICE_TABLE(of, ad5272_dt_ids);
static const struct i2c_device_id ad5272_id[] = {
- { "ad5272-020", AD5272_020 },
- { "ad5272-050", AD5272_050 },
- { "ad5272-100", AD5272_100 },
- { "ad5274-020", AD5274_020 },
- { "ad5274-100", AD5274_100 },
+ { .name = "ad5272-020", .driver_data = AD5272_020 },
+ { .name = "ad5272-050", .driver_data = AD5272_050 },
+ { .name = "ad5272-100", .driver_data = AD5272_100 },
+ { .name = "ad5274-020", .driver_data = AD5274_020 },
+ { .name = "ad5274-100", .driver_data = AD5274_100 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad5272_id);
diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c
index 8a64d93f7e7b..5046119b78b0 100644
--- a/drivers/iio/potentiometer/ds1803.c
+++ b/drivers/iio/potentiometer/ds1803.c
@@ -16,7 +16,6 @@
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#define DS1803_WIPER_0 0xA9
@@ -235,10 +234,10 @@ static const struct of_device_id ds1803_dt_ids[] = {
MODULE_DEVICE_TABLE(of, ds1803_dt_ids);
static const struct i2c_device_id ds1803_id[] = {
- { "ds1803-010", (kernel_ulong_t)&ds1803_cfg[DS1803_010] },
- { "ds1803-050", (kernel_ulong_t)&ds1803_cfg[DS1803_050] },
- { "ds1803-100", (kernel_ulong_t)&ds1803_cfg[DS1803_100] },
- { "ds3502", (kernel_ulong_t)&ds1803_cfg[DS3502] },
+ { .name = "ds1803-010", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS1803_010] },
+ { .name = "ds1803-050", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS1803_050] },
+ { .name = "ds1803-100", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS1803_100] },
+ { .name = "ds3502", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS3502] },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds1803_id);
diff --git a/drivers/iio/potentiometer/max5432.c b/drivers/iio/potentiometer/max5432.c
index 26390be79d02..f6d3ec04fdcf 100644
--- a/drivers/iio/potentiometer/max5432.c
+++ b/drivers/iio/potentiometer/max5432.c
@@ -11,7 +11,6 @@
#include <linux/iio/iio.h>
#include <linux/limits.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
/* All chip variants have 32 wiper positions. */
diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c
index b40e5ac218d7..ec1b7bdc706b 100644
--- a/drivers/iio/potentiometer/max5481.c
+++ b/drivers/iio/potentiometer/max5481.c
@@ -10,7 +10,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
@@ -170,10 +169,10 @@ static int max5481_probe(struct spi_device *spi)
}
static const struct spi_device_id max5481_id_table[] = {
- { "max5481", max5481 },
- { "max5482", max5482 },
- { "max5483", max5483 },
- { "max5484", max5484 },
+ { .name = "max5481", .driver_data = max5481 },
+ { .name = "max5482", .driver_data = max5482 },
+ { .name = "max5483", .driver_data = max5483 },
+ { .name = "max5484", .driver_data = max5484 },
{ }
};
MODULE_DEVICE_TABLE(spi, max5481_id_table);
diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c
index 3b11b991940b..1f0d0056f412 100644
--- a/drivers/iio/potentiometer/max5487.c
+++ b/drivers/iio/potentiometer/max5487.c
@@ -5,7 +5,6 @@
* Copyright (C) 2016 Cristina-Gabriela Moraru <cristina.moraru09@gmail.com>
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/sysfs.h>
@@ -126,9 +125,9 @@ static void max5487_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id max5487_id[] = {
- { "MAX5487", 10 },
- { "MAX5488", 50 },
- { "MAX5489", 100 },
+ { .name = "MAX5487", .driver_data = 10 },
+ { .name = "MAX5488", .driver_data = 50 },
+ { .name = "MAX5489", .driver_data = 100 },
{ }
};
MODULE_DEVICE_TABLE(spi, max5487_id);
diff --git a/drivers/iio/potentiometer/mcp4018.c b/drivers/iio/potentiometer/mcp4018.c
index a88bb2231850..b10b4b920dc0 100644
--- a/drivers/iio/potentiometer/mcp4018.c
+++ b/drivers/iio/potentiometer/mcp4018.c
@@ -16,7 +16,6 @@
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#define MCP4018_WIPER_MAX 127
diff --git a/drivers/iio/potentiometer/mcp41010.c b/drivers/iio/potentiometer/mcp41010.c
index f35fc4a6c55b..cfd5d0f6d368 100644
--- a/drivers/iio/potentiometer/mcp41010.c
+++ b/drivers/iio/potentiometer/mcp41010.c
@@ -21,7 +21,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
@@ -176,12 +175,12 @@ static const struct of_device_id mcp41010_match[] = {
MODULE_DEVICE_TABLE(of, mcp41010_match);
static const struct spi_device_id mcp41010_id[] = {
- { "mcp41010", MCP41010 },
- { "mcp41050", MCP41050 },
- { "mcp41100", MCP41100 },
- { "mcp42010", MCP42010 },
- { "mcp42050", MCP42050 },
- { "mcp42100", MCP42100 },
+ { .name = "mcp41010", .driver_data = MCP41010 },
+ { .name = "mcp41050", .driver_data = MCP41050 },
+ { .name = "mcp41100", .driver_data = MCP41100 },
+ { .name = "mcp42010", .driver_data = MCP42010 },
+ { .name = "mcp42050", .driver_data = MCP42050 },
+ { .name = "mcp42100", .driver_data = MCP42100 },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp41010_id);
diff --git a/drivers/iio/potentiometer/mcp4131.c b/drivers/iio/potentiometer/mcp4131.c
index 56c9111ef5e8..fadf9fcc1817 100644
--- a/drivers/iio/potentiometer/mcp4131.c
+++ b/drivers/iio/potentiometer/mcp4131.c
@@ -36,7 +36,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
@@ -407,70 +406,70 @@ static const struct of_device_id mcp4131_dt_ids[] = {
MODULE_DEVICE_TABLE(of, mcp4131_dt_ids);
static const struct spi_device_id mcp4131_id[] = {
- { "mcp4131-502", MCP413x_502 },
- { "mcp4131-103", MCP413x_103 },
- { "mcp4131-503", MCP413x_503 },
- { "mcp4131-104", MCP413x_104 },
- { "mcp4132-502", MCP413x_502 },
- { "mcp4132-103", MCP413x_103 },
- { "mcp4132-503", MCP413x_503 },
- { "mcp4132-104", MCP413x_104 },
- { "mcp4141-502", MCP414x_502 },
- { "mcp4141-103", MCP414x_103 },
- { "mcp4141-503", MCP414x_503 },
- { "mcp4141-104", MCP414x_104 },
- { "mcp4142-502", MCP414x_502 },
- { "mcp4142-103", MCP414x_103 },
- { "mcp4142-503", MCP414x_503 },
- { "mcp4142-104", MCP414x_104 },
- { "mcp4151-502", MCP415x_502 },
- { "mcp4151-103", MCP415x_103 },
- { "mcp4151-503", MCP415x_503 },
- { "mcp4151-104", MCP415x_104 },
- { "mcp4152-502", MCP415x_502 },
- { "mcp4152-103", MCP415x_103 },
- { "mcp4152-503", MCP415x_503 },
- { "mcp4152-104", MCP415x_104 },
- { "mcp4161-502", MCP416x_502 },
- { "mcp4161-103", MCP416x_103 },
- { "mcp4161-503", MCP416x_503 },
- { "mcp4161-104", MCP416x_104 },
- { "mcp4162-502", MCP416x_502 },
- { "mcp4162-103", MCP416x_103 },
- { "mcp4162-503", MCP416x_503 },
- { "mcp4162-104", MCP416x_104 },
- { "mcp4231-502", MCP423x_502 },
- { "mcp4231-103", MCP423x_103 },
- { "mcp4231-503", MCP423x_503 },
- { "mcp4231-104", MCP423x_104 },
- { "mcp4232-502", MCP423x_502 },
- { "mcp4232-103", MCP423x_103 },
- { "mcp4232-503", MCP423x_503 },
- { "mcp4232-104", MCP423x_104 },
- { "mcp4241-502", MCP424x_502 },
- { "mcp4241-103", MCP424x_103 },
- { "mcp4241-503", MCP424x_503 },
- { "mcp4241-104", MCP424x_104 },
- { "mcp4242-502", MCP424x_502 },
- { "mcp4242-103", MCP424x_103 },
- { "mcp4242-503", MCP424x_503 },
- { "mcp4242-104", MCP424x_104 },
- { "mcp4251-502", MCP425x_502 },
- { "mcp4251-103", MCP425x_103 },
- { "mcp4251-503", MCP425x_503 },
- { "mcp4251-104", MCP425x_104 },
- { "mcp4252-502", MCP425x_502 },
- { "mcp4252-103", MCP425x_103 },
- { "mcp4252-503", MCP425x_503 },
- { "mcp4252-104", MCP425x_104 },
- { "mcp4261-502", MCP426x_502 },
- { "mcp4261-103", MCP426x_103 },
- { "mcp4261-503", MCP426x_503 },
- { "mcp4261-104", MCP426x_104 },
- { "mcp4262-502", MCP426x_502 },
- { "mcp4262-103", MCP426x_103 },
- { "mcp4262-503", MCP426x_503 },
- { "mcp4262-104", MCP426x_104 },
+ { .name = "mcp4131-502", .driver_data = MCP413x_502 },
+ { .name = "mcp4131-103", .driver_data = MCP413x_103 },
+ { .name = "mcp4131-503", .driver_data = MCP413x_503 },
+ { .name = "mcp4131-104", .driver_data = MCP413x_104 },
+ { .name = "mcp4132-502", .driver_data = MCP413x_502 },
+ { .name = "mcp4132-103", .driver_data = MCP413x_103 },
+ { .name = "mcp4132-503", .driver_data = MCP413x_503 },
+ { .name = "mcp4132-104", .driver_data = MCP413x_104 },
+ { .name = "mcp4141-502", .driver_data = MCP414x_502 },
+ { .name = "mcp4141-103", .driver_data = MCP414x_103 },
+ { .name = "mcp4141-503", .driver_data = MCP414x_503 },
+ { .name = "mcp4141-104", .driver_data = MCP414x_104 },
+ { .name = "mcp4142-502", .driver_data = MCP414x_502 },
+ { .name = "mcp4142-103", .driver_data = MCP414x_103 },
+ { .name = "mcp4142-503", .driver_data = MCP414x_503 },
+ { .name = "mcp4142-104", .driver_data = MCP414x_104 },
+ { .name = "mcp4151-502", .driver_data = MCP415x_502 },
+ { .name = "mcp4151-103", .driver_data = MCP415x_103 },
+ { .name = "mcp4151-503", .driver_data = MCP415x_503 },
+ { .name = "mcp4151-104", .driver_data = MCP415x_104 },
+ { .name = "mcp4152-502", .driver_data = MCP415x_502 },
+ { .name = "mcp4152-103", .driver_data = MCP415x_103 },
+ { .name = "mcp4152-503", .driver_data = MCP415x_503 },
+ { .name = "mcp4152-104", .driver_data = MCP415x_104 },
+ { .name = "mcp4161-502", .driver_data = MCP416x_502 },
+ { .name = "mcp4161-103", .driver_data = MCP416x_103 },
+ { .name = "mcp4161-503", .driver_data = MCP416x_503 },
+ { .name = "mcp4161-104", .driver_data = MCP416x_104 },
+ { .name = "mcp4162-502", .driver_data = MCP416x_502 },
+ { .name = "mcp4162-103", .driver_data = MCP416x_103 },
+ { .name = "mcp4162-503", .driver_data = MCP416x_503 },
+ { .name = "mcp4162-104", .driver_data = MCP416x_104 },
+ { .name = "mcp4231-502", .driver_data = MCP423x_502 },
+ { .name = "mcp4231-103", .driver_data = MCP423x_103 },
+ { .name = "mcp4231-503", .driver_data = MCP423x_503 },
+ { .name = "mcp4231-104", .driver_data = MCP423x_104 },
+ { .name = "mcp4232-502", .driver_data = MCP423x_502 },
+ { .name = "mcp4232-103", .driver_data = MCP423x_103 },
+ { .name = "mcp4232-503", .driver_data = MCP423x_503 },
+ { .name = "mcp4232-104", .driver_data = MCP423x_104 },
+ { .name = "mcp4241-502", .driver_data = MCP424x_502 },
+ { .name = "mcp4241-103", .driver_data = MCP424x_103 },
+ { .name = "mcp4241-503", .driver_data = MCP424x_503 },
+ { .name = "mcp4241-104", .driver_data = MCP424x_104 },
+ { .name = "mcp4242-502", .driver_data = MCP424x_502 },
+ { .name = "mcp4242-103", .driver_data = MCP424x_103 },
+ { .name = "mcp4242-503", .driver_data = MCP424x_503 },
+ { .name = "mcp4242-104", .driver_data = MCP424x_104 },
+ { .name = "mcp4251-502", .driver_data = MCP425x_502 },
+ { .name = "mcp4251-103", .driver_data = MCP425x_103 },
+ { .name = "mcp4251-503", .driver_data = MCP425x_503 },
+ { .name = "mcp4251-104", .driver_data = MCP425x_104 },
+ { .name = "mcp4252-502", .driver_data = MCP425x_502 },
+ { .name = "mcp4252-103", .driver_data = MCP425x_103 },
+ { .name = "mcp4252-503", .driver_data = MCP425x_503 },
+ { .name = "mcp4252-104", .driver_data = MCP425x_104 },
+ { .name = "mcp4261-502", .driver_data = MCP426x_502 },
+ { .name = "mcp4261-103", .driver_data = MCP426x_103 },
+ { .name = "mcp4261-503", .driver_data = MCP426x_503 },
+ { .name = "mcp4261-104", .driver_data = MCP426x_104 },
+ { .name = "mcp4262-502", .driver_data = MCP426x_502 },
+ { .name = "mcp4262-103", .driver_data = MCP426x_103 },
+ { .name = "mcp4262-503", .driver_data = MCP426x_503 },
+ { .name = "mcp4262-104", .driver_data = MCP426x_104 },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp4131_id);
diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c
index 9912e91ff7b4..7fb1fb5ab8a5 100644
--- a/drivers/iio/potentiometer/mcp4531.c
+++ b/drivers/iio/potentiometer/mcp4531.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
-#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c
index a42b57733363..77149908e1bf 100644
--- a/drivers/iio/potentiometer/tpl0102.c
+++ b/drivers/iio/potentiometer/tpl0102.c
@@ -149,10 +149,10 @@ static int tpl0102_probe(struct i2c_client *client)
}
static const struct i2c_device_id tpl0102_id[] = {
- { "cat5140-503", CAT5140_503 },
- { "cat5140-104", CAT5140_104 },
- { "tpl0102-104", TPL0102_104 },
- { "tpl0401-103", TPL0401_103 },
+ { .name = "cat5140-503", .driver_data = CAT5140_503 },
+ { .name = "cat5140-104", .driver_data = CAT5140_104 },
+ { .name = "tpl0102-104", .driver_data = TPL0102_104 },
+ { .name = "tpl0401-103", .driver_data = TPL0401_103 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tpl0102_id);
diff --git a/drivers/iio/potentiometer/x9250.c b/drivers/iio/potentiometer/x9250.c
index 735348492699..974e4447fc2c 100644
--- a/drivers/iio/potentiometer/x9250.c
+++ b/drivers/iio/potentiometer/x9250.c
@@ -198,8 +198,8 @@ static const struct of_device_id x9250_of_match[] = {
MODULE_DEVICE_TABLE(of, x9250_of_match);
static const struct spi_device_id x9250_id_table[] = {
- { "x9250t", (kernel_ulong_t)&x9250_cfg[X9250T] },
- { "x9250u", (kernel_ulong_t)&x9250_cfg[X9250U] },
+ { .name = "x9250t", .driver_data = (kernel_ulong_t)&x9250_cfg[X9250T] },
+ { .name = "x9250u", .driver_data = (kernel_ulong_t)&x9250_cfg[X9250U] },
{ }
};
MODULE_DEVICE_TABLE(spi, x9250_id_table);
diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c
index eccc2a34358f..00cb3fea97ca 100644
--- a/drivers/iio/potentiostat/lmp91000.c
+++ b/drivers/iio/potentiostat/lmp91000.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/delay.h>
-#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
@@ -403,8 +402,8 @@ static const struct of_device_id lmp91000_of_match[] = {
MODULE_DEVICE_TABLE(of, lmp91000_of_match);
static const struct i2c_device_id lmp91000_id[] = {
- { "lmp91000" },
- { "lmp91002" },
+ { .name = "lmp91000" },
+ { .name = "lmp91002" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lmp91000_id);
@@ -423,3 +422,4 @@ module_i2c_driver(lmp91000_driver);
MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("LMP91000 digital potentiostat");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/pressure/abp060mg.c b/drivers/iio/pressure/abp060mg.c
index 699b0fd64985..fd48bed35088 100644
--- a/drivers/iio/pressure/abp060mg.c
+++ b/drivers/iio/pressure/abp060mg.c
@@ -209,44 +209,66 @@ static int abp060mg_probe(struct i2c_client *client)
static const struct i2c_device_id abp060mg_id_table[] = {
/* mbar & kPa variants (abp060m [60 mbar] == abp006k [6 kPa]) */
/* gage: */
- { "abp060mg", ABP006KG }, { "abp006kg", ABP006KG },
- { "abp100mg", ABP010KG }, { "abp010kg", ABP010KG },
- { "abp160mg", ABP016KG }, { "abp016kg", ABP016KG },
- { "abp250mg", ABP025KG }, { "abp025kg", ABP025KG },
- { "abp400mg", ABP040KG }, { "abp040kg", ABP040KG },
- { "abp600mg", ABP060KG }, { "abp060kg", ABP060KG },
- { "abp001bg", ABP100KG }, { "abp100kg", ABP100KG },
- { "abp1_6bg", ABP160KG }, { "abp160kg", ABP160KG },
- { "abp2_5bg", ABP250KG }, { "abp250kg", ABP250KG },
- { "abp004bg", ABP400KG }, { "abp400kg", ABP400KG },
- { "abp006bg", ABP600KG }, { "abp600kg", ABP600KG },
- { "abp010bg", ABP001GG }, { "abp001gg", ABP001GG },
+ { .name = "abp060mg", .driver_data = ABP006KG },
+ { .name = "abp006kg", .driver_data = ABP006KG },
+ { .name = "abp100mg", .driver_data = ABP010KG },
+ { .name = "abp010kg", .driver_data = ABP010KG },
+ { .name = "abp160mg", .driver_data = ABP016KG },
+ { .name = "abp016kg", .driver_data = ABP016KG },
+ { .name = "abp250mg", .driver_data = ABP025KG },
+ { .name = "abp025kg", .driver_data = ABP025KG },
+ { .name = "abp400mg", .driver_data = ABP040KG },
+ { .name = "abp040kg", .driver_data = ABP040KG },
+ { .name = "abp600mg", .driver_data = ABP060KG },
+ { .name = "abp060kg", .driver_data = ABP060KG },
+ { .name = "abp001bg", .driver_data = ABP100KG },
+ { .name = "abp100kg", .driver_data = ABP100KG },
+ { .name = "abp1_6bg", .driver_data = ABP160KG },
+ { .name = "abp160kg", .driver_data = ABP160KG },
+ { .name = "abp2_5bg", .driver_data = ABP250KG },
+ { .name = "abp250kg", .driver_data = ABP250KG },
+ { .name = "abp004bg", .driver_data = ABP400KG },
+ { .name = "abp400kg", .driver_data = ABP400KG },
+ { .name = "abp006bg", .driver_data = ABP600KG },
+ { .name = "abp600kg", .driver_data = ABP600KG },
+ { .name = "abp010bg", .driver_data = ABP001GG },
+ { .name = "abp001gg", .driver_data = ABP001GG },
/* differential: */
- { "abp060md", ABP006KD }, { "abp006kd", ABP006KD },
- { "abp100md", ABP010KD }, { "abp010kd", ABP010KD },
- { "abp160md", ABP016KD }, { "abp016kd", ABP016KD },
- { "abp250md", ABP025KD }, { "abp025kd", ABP025KD },
- { "abp400md", ABP040KD }, { "abp040kd", ABP040KD },
- { "abp600md", ABP060KD }, { "abp060kd", ABP060KD },
- { "abp001bd", ABP100KD }, { "abp100kd", ABP100KD },
- { "abp1_6bd", ABP160KD }, { "abp160kd", ABP160KD },
- { "abp2_5bd", ABP250KD }, { "abp250kd", ABP250KD },
- { "abp004bd", ABP400KD }, { "abp400kd", ABP400KD },
+ { .name = "abp060md", .driver_data = ABP006KD },
+ { .name = "abp006kd", .driver_data = ABP006KD },
+ { .name = "abp100md", .driver_data = ABP010KD },
+ { .name = "abp010kd", .driver_data = ABP010KD },
+ { .name = "abp160md", .driver_data = ABP016KD },
+ { .name = "abp016kd", .driver_data = ABP016KD },
+ { .name = "abp250md", .driver_data = ABP025KD },
+ { .name = "abp025kd", .driver_data = ABP025KD },
+ { .name = "abp400md", .driver_data = ABP040KD },
+ { .name = "abp040kd", .driver_data = ABP040KD },
+ { .name = "abp600md", .driver_data = ABP060KD },
+ { .name = "abp060kd", .driver_data = ABP060KD },
+ { .name = "abp001bd", .driver_data = ABP100KD },
+ { .name = "abp100kd", .driver_data = ABP100KD },
+ { .name = "abp1_6bd", .driver_data = ABP160KD },
+ { .name = "abp160kd", .driver_data = ABP160KD },
+ { .name = "abp2_5bd", .driver_data = ABP250KD },
+ { .name = "abp250kd", .driver_data = ABP250KD },
+ { .name = "abp004bd", .driver_data = ABP400KD },
+ { .name = "abp400kd", .driver_data = ABP400KD },
/* psi variants */
/* gage: */
- { "abp001pg", ABP001PG },
- { "abp005pg", ABP005PG },
- { "abp015pg", ABP015PG },
- { "abp030pg", ABP030PG },
- { "abp060pg", ABP060PG },
- { "abp100pg", ABP100PG },
- { "abp150pg", ABP150PG },
+ { .name = "abp001pg", .driver_data = ABP001PG },
+ { .name = "abp005pg", .driver_data = ABP005PG },
+ { .name = "abp015pg", .driver_data = ABP015PG },
+ { .name = "abp030pg", .driver_data = ABP030PG },
+ { .name = "abp060pg", .driver_data = ABP060PG },
+ { .name = "abp100pg", .driver_data = ABP100PG },
+ { .name = "abp150pg", .driver_data = ABP150PG },
/* differential: */
- { "abp001pd", ABP001PD },
- { "abp005pd", ABP005PD },
- { "abp015pd", ABP015PD },
- { "abp030pd", ABP030PD },
- { "abp060pd", ABP060PD },
+ { .name = "abp001pd", .driver_data = ABP001PD },
+ { .name = "abp005pd", .driver_data = ABP005PD },
+ { .name = "abp015pd", .driver_data = ABP015PD },
+ { .name = "abp030pd", .driver_data = ABP030PD },
+ { .name = "abp060pd", .driver_data = ABP060PD },
{ }
};
MODULE_DEVICE_TABLE(i2c, abp060mg_id_table);
diff --git a/drivers/iio/pressure/abp2030pa.c b/drivers/iio/pressure/abp2030pa.c
index 4ca056a73cef..41395036e9ad 100644
--- a/drivers/iio/pressure/abp2030pa.c
+++ b/drivers/iio/pressure/abp2030pa.c
@@ -379,7 +379,6 @@ static int abp2_read_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
- return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (channel->type) {
@@ -520,7 +519,7 @@ int abp2_common_probe(struct device *dev, const struct abp2_ops *ops, int irq)
data->p_offset = div_s64(odelta * data->pmin, pdelta) - data->outmin;
if (data->irq > 0) {
- ret = devm_request_irq(dev, irq, abp2_eoc_handler, IRQF_ONESHOT,
+ ret = devm_request_irq(dev, irq, abp2_eoc_handler, 0,
dev_name(dev), data);
if (ret)
return ret;
diff --git a/drivers/iio/pressure/abp2030pa_i2c.c b/drivers/iio/pressure/abp2030pa_i2c.c
index 9f1c1c8a9afb..fa4d290cfd3e 100644
--- a/drivers/iio/pressure/abp2030pa_i2c.c
+++ b/drivers/iio/pressure/abp2030pa_i2c.c
@@ -8,7 +8,6 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -69,7 +68,7 @@ static const struct of_device_id abp2_i2c_match[] = {
MODULE_DEVICE_TABLE(of, abp2_i2c_match);
static const struct i2c_device_id abp2_i2c_id[] = {
- { "abp2030pa" },
+ { .name = "abp2030pa" },
{ }
};
MODULE_DEVICE_TABLE(i2c, abp2_i2c_id);
diff --git a/drivers/iio/pressure/abp2030pa_spi.c b/drivers/iio/pressure/abp2030pa_spi.c
index eaea9a3ebf11..60d078574827 100644
--- a/drivers/iio/pressure/abp2030pa_spi.c
+++ b/drivers/iio/pressure/abp2030pa_spi.c
@@ -6,7 +6,6 @@
*/
#include <linux/errno.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
@@ -46,7 +45,7 @@ static const struct of_device_id abp2_spi_match[] = {
MODULE_DEVICE_TABLE(of, abp2_spi_match);
static const struct spi_device_id abp2_spi_id[] = {
- { "abp2030pa" },
+ { .name = "abp2030pa" },
{ }
};
MODULE_DEVICE_TABLE(spi, abp2_spi_id);
diff --git a/drivers/iio/pressure/adp810.c b/drivers/iio/pressure/adp810.c
index 5282612d1309..82aa433548d2 100644
--- a/drivers/iio/pressure/adp810.c
+++ b/drivers/iio/pressure/adp810.c
@@ -16,7 +16,6 @@
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/unaligned.h>
@@ -199,7 +198,7 @@ static int adp810_probe(struct i2c_client *client)
}
static const struct i2c_device_id adp810_id_table[] = {
- { "adp810" },
+ { .name = "adp810" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adp810_id_table);
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index d983ce9c0b99..1066792b9087 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -392,7 +392,7 @@ static int bme280_read_calib(struct bmp280_data *data)
h4_lower = FIELD_GET(BME280_COMP_H4_MASK_LOW, tmp_1);
calib->H4 = sign_extend32(h4_upper | h4_lower, 11);
tmp_3 = get_unaligned_le16(&data->bme280_humid_cal_buf[H5]);
- calib->H5 = sign_extend32(FIELD_GET(BME280_COMP_H5_MASK, tmp_3), 11);
+ calib->H5 = FIELD_GET_SIGNED(BME280_COMP_H5_MASK, tmp_3);
calib->H6 = data->bme280_humid_cal_buf[H6];
return 0;
@@ -750,7 +750,10 @@ static int bmp280_read_raw(struct iio_dev *indio_dev,
struct bmp280_data *data = iio_priv(indio_dev);
int ret;
- pm_runtime_get_sync(data->dev);
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
ret = bmp280_read_raw_impl(indio_dev, chan, val, val2, mask);
pm_runtime_put_autosuspend(data->dev);
@@ -924,7 +927,10 @@ static int bmp280_write_raw(struct iio_dev *indio_dev,
struct bmp280_data *data = iio_priv(indio_dev);
int ret;
- pm_runtime_get_sync(data->dev);
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
ret = bmp280_write_raw_impl(indio_dev, chan, val, val2, mask);
pm_runtime_put_autosuspend(data->dev);
@@ -1333,7 +1339,7 @@ static int __bmp280_trigger_probe(struct iio_dev *indio_dev,
irq_thread_handler, IRQF_ONESHOT,
indio_dev->name, indio_dev);
if (ret)
- return dev_err_probe(dev, ret, "request IRQ failed.\n");
+ return ret;
ret = devm_iio_trigger_register(data->dev, data->trig);
if (ret)
@@ -1910,7 +1916,7 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p)
u32 comp_press;
s32 comp_temp;
aligned_s64 timestamp;
- } buffer;
+ } buffer = { };
int ret;
guard(mutex)(&data->lock);
@@ -2254,7 +2260,10 @@ static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val,
struct bmp280_data *data = priv;
int ret;
- pm_runtime_get_sync(data->dev);
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
ret = bmp580_nvmem_read_impl(priv, offset, val, bytes);
pm_runtime_put_autosuspend(data->dev);
@@ -2328,7 +2337,10 @@ static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val,
struct bmp280_data *data = priv;
int ret;
- pm_runtime_get_sync(data->dev);
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
ret = bmp580_nvmem_write_impl(priv, offset, val, bytes);
pm_runtime_put_autosuspend(data->dev);
@@ -2616,7 +2628,7 @@ static irqreturn_t bmp580_trigger_handler(int irq, void *p)
__le32 comp_temp;
__le32 comp_press;
aligned_s64 timestamp;
- } buffer;
+ } buffer = { };
int ret;
guard(mutex)(&data->lock);
@@ -3108,11 +3120,17 @@ EXPORT_SYMBOL_NS(bmp085_chip_info, "IIO_BMP280");
static int bmp280_buffer_preenable(struct iio_dev *indio_dev)
{
struct bmp280_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
- pm_runtime_get_sync(data->dev);
- data->chip_info->set_mode(data, BMP280_NORMAL);
+ ret = data->chip_info->set_mode(data, BMP280_NORMAL);
+ if (ret)
+ pm_runtime_put_autosuspend(data->dev);
- return 0;
+ return ret;
}
static int bmp280_buffer_postdisable(struct iio_dev *indio_dev)
diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c
index 8e459b6c97ff..3f6e0723a9d7 100644
--- a/drivers/iio/pressure/bmp280-i2c.c
+++ b/drivers/iio/pressure/bmp280-i2c.c
@@ -38,12 +38,12 @@ static const struct of_device_id bmp280_of_i2c_match[] = {
MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match);
static const struct i2c_device_id bmp280_i2c_id[] = {
- {"bmp085", (kernel_ulong_t)&bmp085_chip_info },
- {"bmp180", (kernel_ulong_t)&bmp180_chip_info },
- {"bmp280", (kernel_ulong_t)&bmp280_chip_info },
- {"bme280", (kernel_ulong_t)&bme280_chip_info },
- {"bmp380", (kernel_ulong_t)&bmp380_chip_info },
- {"bmp580", (kernel_ulong_t)&bmp580_chip_info },
+ { .name = "bmp085", .driver_data = (kernel_ulong_t)&bmp085_chip_info },
+ { .name = "bmp180", .driver_data = (kernel_ulong_t)&bmp180_chip_info },
+ { .name = "bmp280", .driver_data = (kernel_ulong_t)&bmp280_chip_info },
+ { .name = "bme280", .driver_data = (kernel_ulong_t)&bme280_chip_info },
+ { .name = "bmp380", .driver_data = (kernel_ulong_t)&bmp380_chip_info },
+ { .name = "bmp580", .driver_data = (kernel_ulong_t)&bmp580_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id);
diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c
index 3b90384f17d7..a02a621b8015 100644
--- a/drivers/iio/pressure/bmp280-spi.c
+++ b/drivers/iio/pressure/bmp280-spi.c
@@ -47,7 +47,7 @@ static int bmp380_regmap_spi_read(void *context, const void *reg,
return -EINVAL;
/*
- * According to the BMP3xx datasheets, for a basic SPI read opertion,
+ * According to the BMP3xx datasheets, for a basic SPI read operation,
* the first byte needs to be dropped and the rest are the requested
* data.
*/
@@ -118,13 +118,13 @@ static const struct of_device_id bmp280_of_spi_match[] = {
MODULE_DEVICE_TABLE(of, bmp280_of_spi_match);
static const struct spi_device_id bmp280_spi_id[] = {
- { "bmp085", (kernel_ulong_t)&bmp085_chip_info },
- { "bmp180", (kernel_ulong_t)&bmp180_chip_info },
- { "bmp181", (kernel_ulong_t)&bmp180_chip_info },
- { "bmp280", (kernel_ulong_t)&bmp280_chip_info },
- { "bme280", (kernel_ulong_t)&bme280_chip_info },
- { "bmp380", (kernel_ulong_t)&bmp380_chip_info },
- { "bmp580", (kernel_ulong_t)&bmp580_chip_info },
+ { .name = "bmp085", .driver_data = (kernel_ulong_t)&bmp085_chip_info },
+ { .name = "bmp180", .driver_data = (kernel_ulong_t)&bmp180_chip_info },
+ { .name = "bmp181", .driver_data = (kernel_ulong_t)&bmp180_chip_info },
+ { .name = "bmp280", .driver_data = (kernel_ulong_t)&bmp280_chip_info },
+ { .name = "bme280", .driver_data = (kernel_ulong_t)&bme280_chip_info },
+ { .name = "bmp380", .driver_data = (kernel_ulong_t)&bmp380_chip_info },
+ { .name = "bmp580", .driver_data = (kernel_ulong_t)&bmp580_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, bmp280_spi_id);
diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c
index c6b950c596c1..6a567b6075d9 100644
--- a/drivers/iio/pressure/cros_ec_baro.c
+++ b/drivers/iio/pressure/cros_ec_baro.c
@@ -14,7 +14,6 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_data/cros_ec_commands.h>
@@ -170,14 +169,8 @@ static int cros_ec_baro_probe(struct platform_device *pdev)
return -EINVAL;
}
- /* Timestamp */
channel++;
- channel->type = IIO_TIMESTAMP;
- channel->channel = -1;
- channel->scan_index = 1;
- channel->scan_type.sign = 's';
- channel->scan_type.realbits = 64;
- channel->scan_type.storagebits = 64;
+ *channel = IIO_CHAN_SOFT_TIMESTAMP(1);
indio_dev->channels = state->channels;
indio_dev->num_channels = CROS_EC_BARO_MAX_CHANNELS;
diff --git a/drivers/iio/pressure/dlhl60d.c b/drivers/iio/pressure/dlhl60d.c
index 46feb27fe632..961888fd03a7 100644
--- a/drivers/iio/pressure/dlhl60d.c
+++ b/drivers/iio/pressure/dlhl60d.c
@@ -309,10 +309,8 @@ static int dlh_probe(struct i2c_client *client)
ret = devm_request_irq(&client->dev, client->irq, dlh_interrupt,
IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
st->info->name, indio_dev);
- if (ret) {
- dev_err(&client->dev, "failed to allocate threaded irq");
+ if (ret)
return ret;
- }
st->use_interrupt = true;
init_completion(&st->completion);
@@ -340,8 +338,8 @@ static const struct of_device_id dlh_of_match[] = {
MODULE_DEVICE_TABLE(of, dlh_of_match);
static const struct i2c_device_id dlh_id[] = {
- { "dlhl60d", (kernel_ulong_t)&dlhl60d_info },
- { "dlhl60g", (kernel_ulong_t)&dlhl60g_info },
+ { .name = "dlhl60d", .driver_data = (kernel_ulong_t)&dlhl60d_info },
+ { .name = "dlhl60g", .driver_data = (kernel_ulong_t)&dlhl60g_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, dlh_id);
diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c
index 8edaa4d10a70..45bdb8c7670f 100644
--- a/drivers/iio/pressure/dps310.c
+++ b/drivers/iio/pressure/dps310.c
@@ -845,7 +845,6 @@ static const struct iio_info dps310_info = {
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;
@@ -858,7 +857,7 @@ static int dps310_probe(struct i2c_client *client)
data->client = client;
mutex_init(&data->lock);
- iio->name = id->name;
+ iio->name = DPS310_DEV_NAME;
iio->channels = dps310_channels;
iio->num_channels = ARRAY_SIZE(dps310_channels);
iio->info = &dps310_info;
@@ -887,7 +886,7 @@ static int dps310_probe(struct i2c_client *client)
}
static const struct i2c_device_id dps310_id[] = {
- { DPS310_DEV_NAME },
+ { .name = DPS310_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, dps310_id);
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
index 5f1d6abda3e4..e688b0776547 100644
--- a/drivers/iio/pressure/hid-sensor-press.c
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -3,10 +3,10 @@
* HID Sensors Driver
* Copyright (c) 2014, Intel Corporation.
*/
+#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
@@ -53,22 +53,10 @@ static const struct iio_chan_spec press_channels[] = {
};
-/* Adjust channel real bits based on report descriptor */
-static void press_adjust_channel_bit_mask(struct iio_chan_spec *channels,
- int channel, int size)
-{
- channels[channel].scan_type.sign = 's';
- /* Real storage bits will change based on the report desc. */
- channels[channel].scan_type.realbits = size * 8;
- /* Maximum size of a sample to capture is u32 */
- channels[channel].scan_type.storagebits = sizeof(u32) * 8;
-}
-
/* Channel read_raw handler */
static int press_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct press_state *press_state = iio_priv(indio_dev);
int report_id = -1;
@@ -92,7 +80,7 @@ static int press_read_raw(struct iio_dev *indio_dev,
}
if (report_id >= 0) {
hid_sensor_power_state(&press_state->common_attributes,
- true);
+ true);
*val = sensor_hub_input_attr_get_raw_value(
press_state->common_attributes.hsdev,
HID_USAGE_SENSOR_PRESSURE, address,
@@ -100,7 +88,7 @@ static int press_read_raw(struct iio_dev *indio_dev,
SENSOR_HUB_SYNC,
min < 0);
hid_sensor_power_state(&press_state->common_attributes,
- false);
+ false);
} else {
*val = 0;
return -EINVAL;
@@ -134,10 +122,8 @@ static int press_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int press_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct press_state *press_state = iio_priv(indio_dev);
int ret = 0;
@@ -165,8 +151,7 @@ static const struct iio_info press_info = {
/* Callback handler to send event after all samples are received and captured */
static int press_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct press_state *press_state = iio_priv(indio_dev);
@@ -186,7 +171,7 @@ static int press_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int press_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned usage_id,
+ u32 usage_id,
size_t raw_len, char *raw_data,
void *priv)
{
@@ -212,10 +197,10 @@ static int press_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int press_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct iio_chan_spec *channels,
- unsigned usage_id,
- struct press_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ u32 usage_id,
+ struct press_state *st)
{
int ret;
@@ -225,11 +210,14 @@ static int press_parse_report(struct platform_device *pdev,
&st->press_attr);
if (ret < 0)
return ret;
- press_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESSURE,
- st->press_attr.size);
+ channels[CHANNEL_SCAN_INDEX_PRESSURE].scan_type = (struct iio_scan_type) {
+ .format = 's',
+ .realbits = BYTES_TO_BITS(st->press_attr.size),
+ .storagebits = BITS_PER_TYPE(u32),
+ };
dev_dbg(&pdev->dev, "press %x:%x\n", st->press_attr.index,
- st->press_attr.report_id);
+ st->press_attr.report_id);
st->scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_PRESSURE,
@@ -248,8 +236,7 @@ static int hid_press_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct press_state *press_state;
- indio_dev = devm_iio_device_alloc(&pdev->dev,
- sizeof(struct press_state));
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct press_state));
if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -292,32 +279,32 @@ static int hid_press_probe(struct platform_device *pdev)
atomic_set(&press_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &press_state->common_attributes);
+ &press_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
press_state->callbacks.send_event = press_proc_event;
press_state->callbacks.capture_sample = press_capture_sample;
press_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PRESSURE,
- &press_state->callbacks);
+ &press_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
return ret;
@@ -330,8 +317,8 @@ static void hid_press_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct press_state *press_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
}
diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c
index cbb4aaf45e2c..424523345060 100644
--- a/drivers/iio/pressure/hp03.c
+++ b/drivers/iio/pressure/hp03.c
@@ -266,7 +266,7 @@ static int hp03_probe(struct i2c_client *client)
}
static const struct i2c_device_id hp03_id[] = {
- { "hp03" },
+ { .name = "hp03" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hp03_id);
diff --git a/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c
index abe10ccb6770..ee34c8908b74 100644
--- a/drivers/iio/pressure/hp206c.c
+++ b/drivers/iio/pressure/hp206c.c
@@ -11,7 +11,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -395,7 +394,7 @@ static int hp206c_probe(struct i2c_client *client)
}
static const struct i2c_device_id hp206c_id[] = {
- {"hp206c"},
+ { .name = "hp206c" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hp206c_id);
diff --git a/drivers/iio/pressure/hsc030pa.c b/drivers/iio/pressure/hsc030pa.c
index 2d00c0656259..0374d406b401 100644
--- a/drivers/iio/pressure/hsc030pa.c
+++ b/drivers/iio/pressure/hsc030pa.c
@@ -13,7 +13,6 @@
#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/math64.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/property.h>
@@ -273,7 +272,7 @@ static const struct hsc_range_config hsc_range_config[HSC_VARIANTS_MAX] = {
* @data: structure containing instantiated sensor data
* Return: true only if both status bits are zero
*
- * the two MSB from the first transfered byte contain a status code
+ * The two MSB from the first transferred byte contain a status code
* 00 - normal operation, valid data
* 01 - device in factory programming mode
* 10 - stale data
diff --git a/drivers/iio/pressure/hsc030pa_i2c.c b/drivers/iio/pressure/hsc030pa_i2c.c
index a34ef4653f34..050cacd9ea6a 100644
--- a/drivers/iio/pressure/hsc030pa_i2c.c
+++ b/drivers/iio/pressure/hsc030pa_i2c.c
@@ -12,7 +12,6 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -34,8 +33,13 @@ static int hsc_i2c_recv(struct hsc_data *data)
msg.buf = data->buffer;
ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0)
+ return ret;
- return (ret == 2) ? 0 : ret;
+ if (ret != 1)
+ return -EIO;
+
+ return 0;
}
static int hsc_i2c_probe(struct i2c_client *client)
@@ -53,7 +57,7 @@ static const struct of_device_id hsc_i2c_match[] = {
MODULE_DEVICE_TABLE(of, hsc_i2c_match);
static const struct i2c_device_id hsc_i2c_id[] = {
- { "hsc030pa" },
+ { .name = "hsc030pa" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hsc_i2c_id);
diff --git a/drivers/iio/pressure/hsc030pa_spi.c b/drivers/iio/pressure/hsc030pa_spi.c
index 5d331b3b6da8..02021b6f799a 100644
--- a/drivers/iio/pressure/hsc030pa_spi.c
+++ b/drivers/iio/pressure/hsc030pa_spi.c
@@ -10,7 +10,6 @@
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/stddef.h>
@@ -40,7 +39,7 @@ static const struct of_device_id hsc_spi_match[] = {
MODULE_DEVICE_TABLE(of, hsc_spi_match);
static const struct spi_device_id hsc_spi_id[] = {
- { "hsc030pa" },
+ { .name = "hsc030pa" },
{ }
};
MODULE_DEVICE_TABLE(spi, hsc_spi_id);
diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c
index 3d83d0098a57..82824e3e8db9 100644
--- a/drivers/iio/pressure/icp10100.c
+++ b/drivers/iio/pressure/icp10100.c
@@ -10,7 +10,6 @@
#include <linux/device.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/crc8.h>
@@ -633,7 +632,7 @@ static const struct of_device_id icp10100_of_match[] = {
MODULE_DEVICE_TABLE(of, icp10100_of_match);
static const struct i2c_device_id icp10100_id[] = {
- { "icp10100" },
+ { .name = "icp10100" },
{ }
};
MODULE_DEVICE_TABLE(i2c, icp10100_id);
diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c
index 830a5065c008..2929ea8e4e01 100644
--- a/drivers/iio/pressure/mpl115.c
+++ b/drivers/iio/pressure/mpl115.c
@@ -106,18 +106,18 @@ static int mpl115_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PROCESSED:
pm_runtime_get_sync(data->dev);
ret = mpl115_comp_pressure(data, val, val2);
+ pm_runtime_put_autosuspend(data->dev);
if (ret < 0)
return ret;
- 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);
+ pm_runtime_put_autosuspend(data->dev);
if (ret < 0)
return ret;
- pm_runtime_put_autosuspend(data->dev);
*val = ret >> 6;
return IIO_VAL_INT;
@@ -203,9 +203,9 @@ int mpl115_probe(struct device *dev, const char *name,
if (data->shutdown) {
/* Enable runtime PM */
- pm_runtime_get_noresume(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ ret = pm_runtime_set_active(dev);
+ if (ret)
+ return ret;
/*
* As the device takes 3 ms to come up with a fresh
@@ -215,7 +215,10 @@ int mpl115_probe(struct device *dev, const char *name,
*/
pm_runtime_set_autosuspend_delay(dev, 2000);
pm_runtime_use_autosuspend(dev);
- pm_runtime_put(dev);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
dev_dbg(dev, "low-power mode enabled");
} else
diff --git a/drivers/iio/pressure/mpl115_i2c.c b/drivers/iio/pressure/mpl115_i2c.c
index 3db9ef4e2770..4a43eba078a8 100644
--- a/drivers/iio/pressure/mpl115_i2c.c
+++ b/drivers/iio/pressure/mpl115_i2c.c
@@ -45,7 +45,7 @@ static int mpl115_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id mpl115_i2c_id[] = {
- { "mpl115" },
+ { .name = "mpl115" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mpl115_i2c_id);
diff --git a/drivers/iio/pressure/mpl115_spi.c b/drivers/iio/pressure/mpl115_spi.c
index 4e1d24beff94..3cff616e8d2f 100644
--- a/drivers/iio/pressure/mpl115_spi.c
+++ b/drivers/iio/pressure/mpl115_spi.c
@@ -84,7 +84,7 @@ static int mpl115_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id mpl115_spi_ids[] = {
- { "mpl115", 0 },
+ { .name = "mpl115" },
{ }
};
MODULE_DEVICE_TABLE(spi, mpl115_spi_ids);
diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c
index aeac1586f12e..f20fa6ad16fe 100644
--- a/drivers/iio/pressure/mpl3115.c
+++ b/drivers/iio/pressure/mpl3115.c
@@ -783,7 +783,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend,
mpl3115_resume);
static const struct i2c_device_id mpl3115_id[] = {
- { "mpl3115" },
+ { .name = "mpl3115" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mpl3115_id);
diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c
index e8c495f336ff..c21f0a050660 100644
--- a/drivers/iio/pressure/mprls0025pa.c
+++ b/drivers/iio/pressure/mprls0025pa.c
@@ -20,7 +20,6 @@
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/math64.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/string.h>
diff --git a/drivers/iio/pressure/mprls0025pa_i2c.c b/drivers/iio/pressure/mprls0025pa_i2c.c
index 0fe8cfe0d7e7..06907b64a596 100644
--- a/drivers/iio/pressure/mprls0025pa_i2c.c
+++ b/drivers/iio/pressure/mprls0025pa_i2c.c
@@ -11,7 +11,6 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -69,7 +68,7 @@ static const struct of_device_id mpr_i2c_match[] = {
MODULE_DEVICE_TABLE(of, mpr_i2c_match);
static const struct i2c_device_id mpr_i2c_id[] = {
- { "mprls0025pa" },
+ { .name = "mprls0025pa" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mpr_i2c_id);
diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c
index 8c8c726f703f..6270370383c3 100644
--- a/drivers/iio/pressure/mprls0025pa_spi.c
+++ b/drivers/iio/pressure/mprls0025pa_spi.c
@@ -11,7 +11,6 @@
#include <linux/array_size.h>
#include <linux/device.h>
#include <linux/errno.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/stddef.h>
@@ -60,7 +59,7 @@ static const struct of_device_id mpr_spi_match[] = {
MODULE_DEVICE_TABLE(of, mpr_spi_match);
static const struct spi_device_id mpr_spi_id[] = {
- { "mprls0025pa" },
+ { .name = "mprls0025pa" },
{ }
};
MODULE_DEVICE_TABLE(spi, mpr_spi_id);
diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c
index 1c041b9085fb..c57ad473b21f 100644
--- a/drivers/iio/pressure/ms5611_i2c.c
+++ b/drivers/iio/pressure/ms5611_i2c.c
@@ -14,7 +14,6 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/unaligned.h>
@@ -113,8 +112,8 @@ static const struct of_device_id ms5611_i2c_matches[] = {
MODULE_DEVICE_TABLE(of, ms5611_i2c_matches);
static const struct i2c_device_id ms5611_id[] = {
- { "ms5611", MS5611 },
- { "ms5607", MS5607 },
+ { .name = "ms5611", .driver_data = MS5611 },
+ { .name = "ms5607", .driver_data = MS5607 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ms5611_id);
diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c
index 25c7bd2d8fdf..7133e6744e3f 100644
--- a/drivers/iio/pressure/ms5611_spi.c
+++ b/drivers/iio/pressure/ms5611_spi.c
@@ -9,7 +9,6 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
-#include <linux/mod_devicetable.h>
#include <linux/unaligned.h>
@@ -114,8 +113,8 @@ static const struct of_device_id ms5611_spi_matches[] = {
MODULE_DEVICE_TABLE(of, ms5611_spi_matches);
static const struct spi_device_id ms5611_id[] = {
- { "ms5611", MS5611 },
- { "ms5607", MS5607 },
+ { .name = "ms5611", .driver_data = MS5611 },
+ { .name = "ms5607", .driver_data = MS5607 },
{ }
};
MODULE_DEVICE_TABLE(spi, ms5611_id);
diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
index 59705a666979..be8921644558 100644
--- a/drivers/iio/pressure/ms5637.c
+++ b/drivers/iio/pressure/ms5637.c
@@ -22,7 +22,6 @@
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -215,10 +214,10 @@ static const struct ms_tp_data ms8607_data = {
};
static const struct i2c_device_id ms5637_id[] = {
- {"ms5637", (kernel_ulong_t)&ms5637_data },
- {"ms5805", (kernel_ulong_t)&ms5805_data },
- {"ms5837", (kernel_ulong_t)&ms5837_data },
- {"ms8607-temppressure", (kernel_ulong_t)&ms8607_data },
+ { .name = "ms5637", .driver_data = (kernel_ulong_t)&ms5637_data },
+ { .name = "ms5805", .driver_data = (kernel_ulong_t)&ms5805_data },
+ { .name = "ms5837", .driver_data = (kernel_ulong_t)&ms5837_data },
+ { .name = "ms8607-temppressure", .driver_data = (kernel_ulong_t)&ms8607_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, ms5637_id);
diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c
index dac27fd359ad..57941fb4a535 100644
--- a/drivers/iio/pressure/rohm-bm1390.c
+++ b/drivers/iio/pressure/rohm-bm1390.c
@@ -440,7 +440,7 @@ static int bm1390_fifo_flush(struct iio_dev *idev, unsigned int samples)
* 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
+ * side. We do this using synchronous disable so that if the
* IRQ thread is being ran on other CPU we wait for it to be
* finished.
*/
@@ -621,17 +621,15 @@ static const struct iio_buffer_setup_ops bm1390_buffer_ops = {
.predisable = bm1390_buffer_predisable,
};
-static irqreturn_t bm1390_trigger_handler(int irq, void *p)
+static bool bm1390_handle_trigger(struct iio_dev *idev)
{
- struct iio_poll_func *pf = p;
- struct iio_dev *idev = pf->indio_dev;
struct bm1390_data *data = iio_priv(idev);
int ret, status;
/* DRDY is acked by reading status reg */
ret = regmap_read(data->regmap, BM1390_REG_STATUS, &status);
if (ret || !status)
- return IRQ_NONE;
+ return false;
dev_dbg(data->dev, "DRDY trig status 0x%x\n", status);
@@ -639,7 +637,7 @@ static irqreturn_t bm1390_trigger_handler(int irq, void *p)
ret = bm1390_pressure_read(data, &data->buf.pressure);
if (ret) {
dev_warn(data->dev, "sample read failed %d\n", ret);
- return IRQ_NONE;
+ return false;
}
}
@@ -648,15 +646,26 @@ static irqreturn_t bm1390_trigger_handler(int irq, void *p)
&data->buf.temp, sizeof(data->buf.temp));
if (ret) {
dev_warn(data->dev, "temp read failed %d\n", ret);
- return IRQ_HANDLED;
+ return true;
}
}
iio_push_to_buffers_with_ts(idev, &data->buf, sizeof(data->buf),
data->timestamp);
+
+ return true;
+}
+
+static irqreturn_t bm1390_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *idev = pf->indio_dev;
+ bool result;
+
+ result = bm1390_handle_trigger(idev);
iio_trigger_notify_done(idev->trig);
- return IRQ_HANDLED;
+ return IRQ_RETVAL(result);
}
/* Get timestamps and wake the thread if we need to read data */
@@ -796,7 +805,7 @@ static int bm1390_setup_trigger(struct bm1390_data *data, struct iio_dev *idev,
&bm1390_irq_thread_handler,
IRQF_ONESHOT, name, idev);
if (ret)
- return dev_err_probe(data->dev, ret, "Could not request IRQ\n");
+ return ret;
ret = devm_iio_trigger_register(data->dev, itrig);
@@ -888,7 +897,7 @@ static const struct of_device_id bm1390_of_match[] = {
MODULE_DEVICE_TABLE(of, bm1390_of_match);
static const struct i2c_device_id bm1390_id[] = {
- { "bm1390glv-z", },
+ { .name = "bm1390glv-z" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bm1390_id);
diff --git a/drivers/iio/pressure/sdp500.c b/drivers/iio/pressure/sdp500.c
index 9828c73c4855..153f335ebf1e 100644
--- a/drivers/iio/pressure/sdp500.c
+++ b/drivers/iio/pressure/sdp500.c
@@ -8,7 +8,6 @@
#include <linux/i2c.h>
#include <linux/crc8.h>
#include <linux/iio/iio.h>
-#include <linux/mod_devicetable.h>
#include <linux/regulator/consumer.h>
#include <linux/unaligned.h>
@@ -130,7 +129,7 @@ static int sdp500_probe(struct i2c_client *client)
}
static const struct i2c_device_id sdp500_id[] = {
- { "sdp500" },
+ { .name = "sdp500" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sdp500_id);
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index 0f50bac1fb4d..2b7c84b7e6b4 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
@@ -61,14 +60,14 @@ static const struct acpi_device_id st_press_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, st_press_acpi_match);
static const struct i2c_device_id st_press_id_table[] = {
- { LPS001WP_PRESS_DEV_NAME, LPS001WP },
- { LPS25H_PRESS_DEV_NAME, LPS25H },
- { LPS331AP_PRESS_DEV_NAME, LPS331AP },
- { LPS22HB_PRESS_DEV_NAME, LPS22HB },
- { LPS33HW_PRESS_DEV_NAME, LPS33HW },
- { LPS35HW_PRESS_DEV_NAME, LPS35HW },
- { LPS22HH_PRESS_DEV_NAME, LPS22HH },
- { LPS22DF_PRESS_DEV_NAME, LPS22DF },
+ { .name = LPS001WP_PRESS_DEV_NAME, .driver_data = LPS001WP },
+ { .name = LPS25H_PRESS_DEV_NAME, .driver_data = LPS25H },
+ { .name = LPS331AP_PRESS_DEV_NAME, .driver_data = LPS331AP },
+ { .name = LPS22HB_PRESS_DEV_NAME, .driver_data = LPS22HB },
+ { .name = LPS33HW_PRESS_DEV_NAME, .driver_data = LPS33HW },
+ { .name = LPS35HW_PRESS_DEV_NAME, .driver_data = LPS35HW },
+ { .name = LPS22HH_PRESS_DEV_NAME, .driver_data = LPS22HH },
+ { .name = LPS22DF_PRESS_DEV_NAME, .driver_data = LPS22DF },
{ }
};
MODULE_DEVICE_TABLE(i2c, st_press_id_table);
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index 39827e6841ca..8add0c392c6a 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
@@ -94,18 +93,18 @@ static int st_press_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id st_press_id_table[] = {
- { LPS001WP_PRESS_DEV_NAME },
- { LPS25H_PRESS_DEV_NAME },
- { LPS331AP_PRESS_DEV_NAME },
- { LPS22HB_PRESS_DEV_NAME },
- { LPS33HW_PRESS_DEV_NAME },
- { LPS35HW_PRESS_DEV_NAME },
- { LPS22HH_PRESS_DEV_NAME },
- { LPS22DF_PRESS_DEV_NAME },
- { "lps001wp-press" },
- { "lps25h-press", },
- { "lps331ap-press" },
- { "lps22hb-press" },
+ { .name = LPS001WP_PRESS_DEV_NAME },
+ { .name = LPS25H_PRESS_DEV_NAME },
+ { .name = LPS331AP_PRESS_DEV_NAME },
+ { .name = LPS22HB_PRESS_DEV_NAME },
+ { .name = LPS33HW_PRESS_DEV_NAME },
+ { .name = LPS35HW_PRESS_DEV_NAME },
+ { .name = LPS22HH_PRESS_DEV_NAME },
+ { .name = LPS22DF_PRESS_DEV_NAME },
+ { .name = "lps001wp-press" },
+ { .name = "lps25h-press" },
+ { .name = "lps331ap-press" },
+ { .name = "lps22hb-press" },
{ }
};
MODULE_DEVICE_TABLE(spi, st_press_id_table);
diff --git a/drivers/iio/pressure/t5403.c b/drivers/iio/pressure/t5403.c
index c7cb0fd816d3..ab30f6745181 100644
--- a/drivers/iio/pressure/t5403.c
+++ b/drivers/iio/pressure/t5403.c
@@ -251,7 +251,7 @@ static int t5403_probe(struct i2c_client *client)
}
static const struct i2c_device_id t5403_id[] = {
- { "t5403" },
+ { .name = "t5403" },
{ }
};
MODULE_DEVICE_TABLE(i2c, t5403_id);
diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c
index 4923a558a26a..b38493ff3b8b 100644
--- a/drivers/iio/pressure/zpa2326.c
+++ b/drivers/iio/pressure/zpa2326.c
@@ -840,7 +840,7 @@ static irqreturn_t zpa2326_handle_threaded_irq(int irq, void *data)
complete:
/*
- * Wake up direct or externaly triggered buffer mode waiters: see
+ * Wake up direct or externally triggered buffer mode waiters: see
* zpa2326_sample_oneshot() and zpa2326_trigger_handler().
*/
complete(&priv->data_ready);
@@ -911,11 +911,8 @@ static int zpa2326_init_managed_irq(struct device *parent,
zpa2326_handle_threaded_irq,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(parent), indio_dev);
- if (err) {
- dev_err(parent, "failed to request interrupt %d (%d)", irq,
- err);
+ if (err)
return err;
- }
dev_info(parent, "using interrupt %d", irq);
diff --git a/drivers/iio/pressure/zpa2326_i2c.c b/drivers/iio/pressure/zpa2326_i2c.c
index a6034bf05d97..e04a61c2388b 100644
--- a/drivers/iio/pressure/zpa2326_i2c.c
+++ b/drivers/iio/pressure/zpa2326_i2c.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
#include "zpa2326.h"
/*
@@ -58,7 +57,7 @@ static void zpa2326_remove_i2c(struct i2c_client *client)
}
static const struct i2c_device_id zpa2326_i2c_ids[] = {
- { "zpa2326" },
+ { .name = "zpa2326" },
{ }
};
MODULE_DEVICE_TABLE(i2c, zpa2326_i2c_ids);
diff --git a/drivers/iio/pressure/zpa2326_spi.c b/drivers/iio/pressure/zpa2326_spi.c
index af756e2b0f31..dfbb74a58dc0 100644
--- a/drivers/iio/pressure/zpa2326_spi.c
+++ b/drivers/iio/pressure/zpa2326_spi.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
-#include <linux/mod_devicetable.h>
#include "zpa2326.h"
/*
@@ -61,7 +60,7 @@ static void zpa2326_remove_spi(struct spi_device *spi)
}
static const struct spi_device_id zpa2326_spi_ids[] = {
- { "zpa2326", 0 },
+ { .name = "zpa2326" },
{ }
};
MODULE_DEVICE_TABLE(spi, zpa2326_spi_ids);
diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index 6070974c2c85..bb77fad2a1b3 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -244,6 +244,21 @@ config VL53L0X_I2C
To compile this driver as a module, choose M here: the
module will be called vl53l0x-i2c.
+config VL53L1X_I2C
+ tristate "STMicroelectronics VL53L1X ToF ranger sensor (I2C)"
+ depends on I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ select REGMAP_I2C
+ select RESET_CONTROLLER
+ help
+ Say Y here to build a driver for STMicroelectronics VL53L1X
+ ToF ranger sensors with i2c interface.
+ This driver can be used to measure the distance of objects.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vl53l1x-i2c.
+
config AW96103
tristate "AW96103/AW96105 Awinic proximity sensor"
select REGMAP_I2C
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index 152034d38c49..4352833dd8a4 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -23,5 +23,6 @@ obj-$(CONFIG_SX_COMMON) += sx_common.o
obj-$(CONFIG_SX9500) += sx9500.o
obj-$(CONFIG_VCNL3020) += vcnl3020.o
obj-$(CONFIG_VL53L0X_I2C) += vl53l0x-i2c.o
+obj-$(CONFIG_VL53L1X_I2C) += vl53l1x-i2c.o
obj-$(CONFIG_AW96103) += aw96103.o
diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c
index f1018b14aecf..d7f43c3af165 100644
--- a/drivers/iio/proximity/as3935.c
+++ b/drivers/iio/proximity/as3935.c
@@ -7,7 +7,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -429,10 +428,8 @@ static int as3935_probe(struct spi_device *spi)
dev_name(dev),
indio_dev);
- if (ret) {
- dev_err(dev, "unable to request irq\n");
+ if (ret)
return ret;
- }
ret = devm_iio_device_register(dev, indio_dev);
if (ret < 0) {
@@ -449,7 +446,7 @@ static const struct of_device_id as3935_of_match[] = {
MODULE_DEVICE_TABLE(of, as3935_of_match);
static const struct spi_device_id as3935_id[] = {
- {"as3935", 0},
+ { .name = "as3935" },
{ }
};
MODULE_DEVICE_TABLE(spi, as3935_id);
diff --git a/drivers/iio/proximity/aw96103.c b/drivers/iio/proximity/aw96103.c
index 3472a2c36e44..8fbb755dcae0 100644
--- a/drivers/iio/proximity/aw96103.c
+++ b/drivers/iio/proximity/aw96103.c
@@ -825,8 +825,8 @@ static const struct of_device_id aw96103_dt_match[] = {
MODULE_DEVICE_TABLE(of, aw96103_dt_match);
static const struct i2c_device_id aw96103_i2c_id[] = {
- { "aw96103", (kernel_ulong_t)&aw_chip_info_tbl[AW96103_VAL] },
- { "aw96105", (kernel_ulong_t)&aw_chip_info_tbl[AW96105_VAL] },
+ { .name = "aw96103", .driver_data = (kernel_ulong_t)&aw_chip_info_tbl[AW96103_VAL] },
+ { .name = "aw96105", .driver_data = (kernel_ulong_t)&aw_chip_info_tbl[AW96105_VAL] },
{ }
};
MODULE_DEVICE_TABLE(i2c, aw96103_i2c_id);
diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c
index 1f9de7066ebf..63f9b45bef7b 100644
--- a/drivers/iio/proximity/cros_ec_mkbp_proximity.c
+++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c
@@ -6,7 +6,6 @@
*/
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
diff --git a/drivers/iio/proximity/d3323aa.c b/drivers/iio/proximity/d3323aa.c
index 30821f583454..1f43c1fed342 100644
--- a/drivers/iio/proximity/d3323aa.c
+++ b/drivers/iio/proximity/d3323aa.c
@@ -13,7 +13,6 @@
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
@@ -772,7 +771,7 @@ static int d3323aa_probe(struct platform_device *pdev)
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
dev_name(dev), indio_dev);
if (ret)
- return dev_err_probe(dev, ret, "Could not request IRQ\n");
+ return ret;
ret = d3323aa_setup(indio_dev, D3323AA_LP_FILTER_FREQ_DEFAULT_IDX,
D3323AA_FILTER_GAIN_DEFAULT_IDX,
diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c
index 17e00ee2b6f8..0199a6351a46 100644
--- a/drivers/iio/proximity/hx9023s.c
+++ b/drivers/iio/proximity/hx9023s.c
@@ -19,7 +19,6 @@
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/math64.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm.h>
@@ -1088,6 +1087,7 @@ static int hx9023s_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct hx9023s_data *data;
+ const char *fw_name;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
@@ -1125,7 +1125,9 @@ static int hx9023s_probe(struct i2c_client *client)
if (ret)
return dev_err_probe(dev, ret, "channel config failed\n");
- ret = request_firmware_nowait(THIS_MODULE, true, "hx9023s.bin", dev,
+ fw_name = "hx9023s.bin";
+ device_property_read_string(dev, "firmware-name", &fw_name);
+ ret = request_firmware_nowait(THIS_MODULE, true, fw_name, dev,
GFP_KERNEL, data, hx9023s_cfg_update);
if (ret)
return dev_err_probe(dev, ret, "reg config failed\n");
@@ -1137,7 +1139,7 @@ static int hx9023s_probe(struct i2c_client *client)
IRQF_ONESHOT,
"hx9023s_event", indio_dev);
if (ret)
- return dev_err_probe(dev, ret, "irq request failed\n");
+ return ret;
data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
@@ -1196,7 +1198,7 @@ static const struct of_device_id hx9023s_of_match[] = {
MODULE_DEVICE_TABLE(of, hx9023s_of_match);
static const struct i2c_device_id hx9023s_id[] = {
- { "hx9023s" },
+ { .name = "hx9023s" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hx9023s_id);
diff --git a/drivers/iio/proximity/irsd200.c b/drivers/iio/proximity/irsd200.c
index 65af31d43453..b3db7f3a49f6 100644
--- a/drivers/iio/proximity/irsd200.c
+++ b/drivers/iio/proximity/irsd200.c
@@ -910,7 +910,7 @@ static int irsd200_probe(struct i2c_client *client)
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
NULL, indio_dev);
if (ret)
- return dev_err_probe(data->dev, ret, "Could not request irq\n");
+ return ret;
trigger = devm_iio_trigger_alloc(data->dev, "%s-dev%d", indio_dev->name,
iio_device_id(indio_dev));
diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c
index f69db6f2f380..95fb7238f678 100644
--- a/drivers/iio/proximity/isl29501.c
+++ b/drivers/iio/proximity/isl29501.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
-#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -995,7 +994,7 @@ static int isl29501_probe(struct i2c_client *client)
}
static const struct i2c_device_id isl29501_id[] = {
- { "isl29501" },
+ { .name = "isl29501" },
{ }
};
diff --git a/drivers/iio/proximity/mb1232.c b/drivers/iio/proximity/mb1232.c
index 34b49c54e68b..accfc296e1f0 100644
--- a/drivers/iio/proximity/mb1232.c
+++ b/drivers/iio/proximity/mb1232.c
@@ -14,7 +14,6 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/delay.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
@@ -214,10 +213,8 @@ static int mb1232_probe(struct i2c_client *client)
if (data->irqnr > 0) {
ret = devm_request_irq(dev, data->irqnr, mb1232_handle_irq,
IRQF_TRIGGER_FALLING, id->name, indio_dev);
- if (ret < 0) {
- dev_err(dev, "request_irq: %d\n", ret);
+ if (ret)
return ret;
- }
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
@@ -244,13 +241,13 @@ static const struct of_device_id of_mb1232_match[] = {
MODULE_DEVICE_TABLE(of, of_mb1232_match);
static const struct i2c_device_id mb1232_id[] = {
- { "maxbotix-mb1202", },
- { "maxbotix-mb1212", },
- { "maxbotix-mb1222", },
- { "maxbotix-mb1232", },
- { "maxbotix-mb1242", },
- { "maxbotix-mb7040", },
- { "maxbotix-mb7137", },
+ { .name = "maxbotix-mb1202" },
+ { .name = "maxbotix-mb1212" },
+ { .name = "maxbotix-mb1222" },
+ { .name = "maxbotix-mb1232" },
+ { .name = "maxbotix-mb1242" },
+ { .name = "maxbotix-mb7040" },
+ { .name = "maxbotix-mb7137" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mb1232_id);
diff --git a/drivers/iio/proximity/ping.c b/drivers/iio/proximity/ping.c
index e3487094d7be..1e646b858468 100644
--- a/drivers/iio/proximity/ping.c
+++ b/drivers/iio/proximity/ping.c
@@ -29,7 +29,6 @@
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
index 21336b8f122a..400477b4c740 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -13,7 +13,6 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -319,8 +318,8 @@ static void lidar_remove(struct i2c_client *client)
}
static const struct i2c_device_id lidar_id[] = {
- { "lidar-lite-v2" },
- { "lidar-lite-v3" },
+ { .name = "lidar-lite-v2" },
+ { .name = "lidar-lite-v3" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lidar_id);
diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c
index 6afdbfca3e5a..db1e94fc5658 100644
--- a/drivers/iio/proximity/rfd77402.c
+++ b/drivers/iio/proximity/rfd77402.c
@@ -173,10 +173,8 @@ static int rfd77402_wait_for_result(struct rfd77402_data *data)
struct i2c_client *client = data->client;
int val, ret;
- if (data->irq_en) {
- reinit_completion(&data->completion);
+ if (data->irq_en)
return rfd77402_wait_for_irq(data);
- }
/*
* As per RFD77402 datasheet section '3.1.1 Single Measure', the
@@ -204,6 +202,9 @@ static int rfd77402_measure(struct rfd77402_data *data)
if (ret < 0)
return ret;
+ if (data->irq_en)
+ reinit_completion(&data->completion);
+
ret = i2c_smbus_write_byte_data(client, RFD77402_CMD_R,
RFD77402_CMD_SINGLE |
RFD77402_CMD_VALID);
@@ -432,7 +433,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend,
rfd77402_resume);
static const struct i2c_device_id rfd77402_id[] = {
- { "rfd77402" },
+ { .name = "rfd77402" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rfd77402_id);
diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c
index e97f9a20ac7a..4e042214df29 100644
--- a/drivers/iio/proximity/srf04.c
+++ b/drivers/iio/proximity/srf04.c
@@ -37,7 +37,6 @@
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -304,10 +303,8 @@ static int srf04_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, data->irqnr, srf04_handle_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
pdev->name, indio_dev);
- if (ret < 0) {
- dev_err(data->dev, "request_irq: %d\n", ret);
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, indio_dev);
@@ -331,6 +328,7 @@ static int srf04_probe(struct platform_device *pdev)
if (ret) {
dev_err(data->dev, "pm_runtime_set_active: %d\n", ret);
iio_device_unregister(indio_dev);
+ return ret;
}
pm_runtime_enable(data->dev);
diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c
index d7e4cc48cfbf..35eb3fd7e700 100644
--- a/drivers/iio/proximity/srf08.c
+++ b/drivers/iio/proximity/srf08.c
@@ -226,7 +226,7 @@ static int srf08_read_raw(struct iio_dev *indio_dev,
static ssize_t srf08_show_range_mm_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "[0.043 0.043 11.008]\n");
+ return sysfs_emit(buf, "[0.043 0.043 11.008]\n");
}
static IIO_DEVICE_ATTR(sensor_max_range_available, S_IRUGO,
@@ -238,8 +238,8 @@ static ssize_t srf08_show_range_mm(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct srf08_data *data = iio_priv(indio_dev);
- return sprintf(buf, "%d.%03d\n", data->range_mm / 1000,
- data->range_mm % 1000);
+ return sysfs_emit(buf, "%d.%03d\n",
+ data->range_mm / 1000, data->range_mm % 1000);
}
/*
@@ -316,10 +316,10 @@ static ssize_t srf08_show_sensitivity_available(struct device *dev,
for (i = 0; i < data->chip_info->num_sensitivity_avail; i++)
if (data->chip_info->sensitivity_avail[i])
- len += sprintf(buf + len, "%d ",
- data->chip_info->sensitivity_avail[i]);
+ len += sysfs_emit_at(buf, len, "%d ",
+ data->chip_info->sensitivity_avail[i]);
- len += sprintf(buf + len, "\n");
+ len += sysfs_emit_at(buf, len, "\n");
return len;
}
@@ -332,11 +332,8 @@ static ssize_t srf08_show_sensitivity(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct srf08_data *data = iio_priv(indio_dev);
- int len;
- len = sprintf(buf, "%d\n", data->sensitivity);
-
- return len;
+ return sysfs_emit(buf, "%d\n", data->sensitivity);
}
static ssize_t srf08_write_sensitivity(struct srf08_data *data,
@@ -533,9 +530,9 @@ static const struct of_device_id of_srf08_match[] = {
MODULE_DEVICE_TABLE(of, of_srf08_match);
static const struct i2c_device_id srf08_id[] = {
- { "srf02", SRF02 },
- { "srf08", SRF08 },
- { "srf10", SRF10 },
+ { .name = "srf02", .driver_data = SRF02 },
+ { .name = "srf08", .driver_data = SRF08 },
+ { .name = "srf10", .driver_data = SRF10 },
{ }
};
MODULE_DEVICE_TABLE(i2c, srf08_id);
diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c
index fb02eac78ed4..79ba46d8a0aa 100644
--- a/drivers/iio/proximity/sx9310.c
+++ b/drivers/iio/proximity/sx9310.c
@@ -16,7 +16,6 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/log2.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/property.h>
@@ -1007,8 +1006,8 @@ static const struct of_device_id sx9310_of_match[] = {
MODULE_DEVICE_TABLE(of, sx9310_of_match);
static const struct i2c_device_id sx9310_id[] = {
- { "sx9310", (kernel_ulong_t)&sx9310_info },
- { "sx9311", (kernel_ulong_t)&sx9311_info },
+ { .name = "sx9310", .driver_data = (kernel_ulong_t)&sx9310_info },
+ { .name = "sx9311", .driver_data = (kernel_ulong_t)&sx9311_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, sx9310_id);
diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c
index c7b2d03c23bc..13b4ef2896e3 100644
--- a/drivers/iio/proximity/sx9324.c
+++ b/drivers/iio/proximity/sx9324.c
@@ -15,7 +15,6 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/log2.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/property.h>
@@ -821,7 +820,7 @@ static const struct sx_common_reg_default sx9324_default_regs[] = {
{ SX9324_REG_ADV_CTRL10, 0x00, "adv_ctrl10" },
{ SX9324_REG_ADV_CTRL11, 0x00, "adv_ctrl11" },
{ SX9324_REG_ADV_CTRL12, 0x00, "adv_ctrl12" },
- /* TODO(gwendal): SAR currenly disabled */
+ /* TODO(gwendal): SAR currently disabled */
{ SX9324_REG_ADV_CTRL13, 0x00, "adv_ctrl13" },
{ SX9324_REG_ADV_CTRL14, 0x00, "adv_ctrl14" },
{ SX9324_REG_ADV_CTRL15, 0x00, "adv_ctrl15" },
@@ -1123,19 +1122,19 @@ static int sx9324_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(sx9324_pm_ops, sx9324_suspend, sx9324_resume);
static const struct acpi_device_id sx9324_acpi_match[] = {
- { "STH9324", SX9324_WHOAMI_VALUE },
+ { .id = "STH9324" },
{ }
};
MODULE_DEVICE_TABLE(acpi, sx9324_acpi_match);
static const struct of_device_id sx9324_of_match[] = {
- { .compatible = "semtech,sx9324", (void *)SX9324_WHOAMI_VALUE },
+ { .compatible = "semtech,sx9324" },
{ }
};
MODULE_DEVICE_TABLE(of, sx9324_of_match);
static const struct i2c_device_id sx9324_id[] = {
- { "sx9324", SX9324_WHOAMI_VALUE },
+ { .name = "sx9324" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sx9324_id);
diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c
index 4448988d4e7e..ed83d809ecf5 100644
--- a/drivers/iio/proximity/sx9360.c
+++ b/drivers/iio/proximity/sx9360.c
@@ -14,7 +14,6 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/log2.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/property.h>
@@ -832,20 +831,20 @@ static int sx9360_resume(struct device *dev)
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 },
+ { .id = "STH9360" },
+ { .id = "SAMM0208" },
{ }
};
MODULE_DEVICE_TABLE(acpi, sx9360_acpi_match);
static const struct of_device_id sx9360_of_match[] = {
- { .compatible = "semtech,sx9360", (void *)SX9360_WHOAMI_VALUE },
+ { .compatible = "semtech,sx9360" },
{ }
};
MODULE_DEVICE_TABLE(of, sx9360_of_match);
static const struct i2c_device_id sx9360_id[] = {
- {"sx9360", SX9360_WHOAMI_VALUE },
+ { .name = "sx9360" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sx9360_id);
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index 6c67bae7488c..dadce9b44227 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -1025,7 +1025,7 @@ static const struct of_device_id sx9500_of_match[] = {
MODULE_DEVICE_TABLE(of, sx9500_of_match);
static const struct i2c_device_id sx9500_id[] = {
- { "sx9500" },
+ { .name = "sx9500" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sx9500_id);
diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c
index 59b35e40739b..4d4937395d9a 100644
--- a/drivers/iio/proximity/sx_common.c
+++ b/drivers/iio/proximity/sx_common.c
@@ -517,7 +517,7 @@ int sx_common_probe(struct i2c_client *client,
IRQF_ONESHOT,
"sx_event", indio_dev);
if (ret)
- return dev_err_probe(dev, ret, "No IRQ\n");
+ return ret;
data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c
index 7f417372566a..6b0d7a9038d9 100644
--- a/drivers/iio/proximity/vcnl3020.c
+++ b/drivers/iio/proximity/vcnl3020.c
@@ -638,12 +638,8 @@ static int vcnl3020_probe(struct i2c_client *client)
NULL, vcnl3020_handle_irq_thread,
IRQF_ONESHOT, indio_dev->name,
indio_dev);
- if (rc) {
- dev_err(&client->dev,
- "Error (%d) irq request failed (%u)\n", rc,
- client->irq);
+ if (rc)
return rc;
- }
}
return devm_iio_device_register(&client->dev, indio_dev);
diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c
index ad3e46d47fa8..9fe14ceb8be7 100644
--- a/drivers/iio/proximity/vl53l0x-i2c.c
+++ b/drivers/iio/proximity/vl53l0x-i2c.c
@@ -87,15 +87,14 @@ static irqreturn_t vl53l0x_trigger_handler(int irq, void *priv)
ret = i2c_smbus_read_i2c_block_data(data->client,
VL_REG_RESULT_RANGE_STATUS,
sizeof(buffer), buffer);
- if (ret < 0)
- return ret;
- else if (ret != 12)
- return -EREMOTEIO;
+ if (ret != 12)
+ goto done;
scan.chan = get_unaligned_be16(&buffer[10]);
iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
iio_get_time_ns(indio_dev));
+done:
iio_trigger_notify_done(indio_dev->trig);
vl53l0x_clear_irq(data);
@@ -128,10 +127,8 @@ static int vl53l0x_configure_irq(struct i2c_client *client,
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, vl53l0x_threaded_irq,
irq_flags | IRQF_ONESHOT, indio_dev->name, indio_dev);
- if (ret) {
- dev_err(&client->dev, "devm_request_irq error: %d\n", ret);
+ if (ret)
return ret;
- }
ret = i2c_smbus_write_byte_data(data->client,
VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO,
@@ -393,7 +390,7 @@ static int vl53l0x_probe(struct i2c_client *client)
}
static const struct i2c_device_id vl53l0x_id[] = {
- { "vl53l0x" },
+ { .name = "vl53l0x" },
{ }
};
MODULE_DEVICE_TABLE(i2c, vl53l0x_id);
diff --git a/drivers/iio/proximity/vl53l1x-i2c.c b/drivers/iio/proximity/vl53l1x-i2c.c
new file mode 100644
index 000000000000..bce238d1b6de
--- /dev/null
+++ b/drivers/iio/proximity/vl53l1x-i2c.c
@@ -0,0 +1,756 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * Support for ST VL53L1X FlightSense ToF Ranging Sensor on a i2c bus.
+ *
+ * Copyright (C) 2026 Siratul Islam <siratul.islam@linux.dev>
+ *
+ * Datasheet available at
+ * <https://www.st.com/resource/en/datasheet/vl53l1x.pdf>
+ *
+ * Default 7-bit i2c slave address 0x29.
+ *
+ * The VL53L1X requires a firmware configuration blob to be loaded at boot.
+ * Register values for the default configuration are taken from
+ * ST's VL53L1X Ultra Lite Driver (STSW-IMG009).
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <asm/byteorder.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 VL53L1X_REG_SOFT_RESET 0x0000
+#define VL53L1X_REG_VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND 0x0008
+#define VL53L1X_REG_VHV_CONFIG__INIT 0x000B
+#define VL53L1X_REG_DEFAULT_CONFIG 0x002D
+#define VL53L1X_REG_GPIO_HV_MUX__CTRL 0x0030
+#define VL53L1X_REG_GPIO__TIO_HV_STATUS 0x0031
+#define VL53L1X_REG_SYSTEM__INTERRUPT_CONFIG_GPIO 0x0046
+#define VL53L1X_REG_PHASECAL_CONFIG__TIMEOUT_MACROP 0x004B
+#define VL53L1X_REG_RANGE_CONFIG__TIMEOUT_MACROP_A 0x005E
+#define VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_A 0x0060
+#define VL53L1X_REG_RANGE_CONFIG__TIMEOUT_MACROP_B 0x0061
+#define VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_B 0x0063
+#define VL53L1X_REG_RANGE_CONFIG__VALID_PHASE_HIGH 0x0069
+#define VL53L1X_REG_SYSTEM__INTERMEASUREMENT_PERIOD 0x006C
+#define VL53L1X_REG_SD_CONFIG__WOI_SD0 0x0078
+#define VL53L1X_REG_SD_CONFIG__WOI_SD1 0x0079
+#define VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD0 0x007A
+#define VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD1 0x007B
+#define VL53L1X_REG_SYSTEM__INTERRUPT_CLEAR 0x0086
+#define VL53L1X_REG_SYSTEM__MODE_START 0x0087
+#define VL53L1X_REG_RESULT__RANGE_STATUS 0x0089
+#define VL53L1X_REG_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0096
+#define VL53L1X_REG_RESULT__OSC_CALIBRATE_VAL 0x00DE
+#define VL53L1X_REG_FIRMWARE__SYSTEM_STATUS 0x00E5
+#define VL53L1X_REG_IDENTIFICATION__MODEL_ID 0x010F
+
+#define VL53L1X_MODEL_ID_VAL 0xEACC
+
+#define VL53L1X_MODE_START_TIMED 0x40
+#define VL53L1X_MODE_START_STOP 0x00
+
+#define VL53L1X_INT_NEW_SAMPLE_READY 0x02
+
+#define VL53L1X_GPIO_HV_MUX_POLARITY BIT(4)
+
+#define VL53L1X_VHV_LOOP_BOUND_TWO 0x09
+
+#define VL53L1X_RANGE_STATUS_MASK GENMASK(4, 0)
+#define VL53L1X_RANGE_STATUS_VALID 9
+
+#define VL53L1X_OSC_CALIBRATE_MASK GENMASK(9, 0)
+
+#define VL53L1X_FIRMWARE__SYSTEM_STATUS_BOOTED BIT(0)
+#define VL53L1X_GPIO__TIO_HV_STATUS_DATA_READY BIT(0)
+
+/* Inter-measurement period uses PLL divider with 1.075 oscillator correction */
+static const struct u32_fract vl53l1x_osc_correction = {
+ .numerator = 1075,
+ .denominator = 1000,
+};
+
+enum vl53l1x_distance_mode {
+ VL53L1X_SHORT,
+ VL53L1X_LONG,
+};
+
+struct vl53l1x_data {
+ struct regmap *regmap;
+ struct completion completion;
+ struct reset_control *xshut_reset;
+ enum vl53l1x_distance_mode distance_mode;
+ u8 gpio_polarity;
+ int irq;
+};
+
+static const struct regmap_range vl53l1x_volatile_ranges[] = {
+ regmap_reg_range(VL53L1X_REG_GPIO__TIO_HV_STATUS,
+ VL53L1X_REG_GPIO__TIO_HV_STATUS),
+ regmap_reg_range(VL53L1X_REG_RESULT__RANGE_STATUS,
+ VL53L1X_REG_RESULT__RANGE_STATUS),
+ regmap_reg_range(VL53L1X_REG_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0,
+ VL53L1X_REG_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 + 1),
+ regmap_reg_range(VL53L1X_REG_RESULT__OSC_CALIBRATE_VAL,
+ VL53L1X_REG_RESULT__OSC_CALIBRATE_VAL + 1),
+ regmap_reg_range(VL53L1X_REG_FIRMWARE__SYSTEM_STATUS,
+ VL53L1X_REG_FIRMWARE__SYSTEM_STATUS),
+};
+
+static const struct regmap_access_table vl53l1x_volatile_table = {
+ .yes_ranges = vl53l1x_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(vl53l1x_volatile_ranges),
+};
+
+static const struct regmap_range vl53l1x_write_only_ranges[] = {
+ regmap_reg_range(VL53L1X_REG_SOFT_RESET, VL53L1X_REG_SOFT_RESET),
+ regmap_reg_range(VL53L1X_REG_SYSTEM__INTERRUPT_CLEAR,
+ VL53L1X_REG_SYSTEM__MODE_START),
+};
+
+static const struct regmap_access_table vl53l1x_readable_table = {
+ .no_ranges = vl53l1x_write_only_ranges,
+ .n_no_ranges = ARRAY_SIZE(vl53l1x_write_only_ranges),
+};
+
+static const struct regmap_config vl53l1x_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ /* MODEL_ID is 16-bit. +1 covers the second byte at 0x0110 */
+ .max_register = VL53L1X_REG_IDENTIFICATION__MODEL_ID + 1,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_table = &vl53l1x_volatile_table,
+ .rd_table = &vl53l1x_readable_table,
+};
+
+static int vl53l1x_read_u16(struct vl53l1x_data *data, u16 reg, u16 *val)
+{
+ __be16 buf;
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, reg, &buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ *val = be16_to_cpu(buf);
+ return 0;
+}
+
+static int vl53l1x_write_u16(struct vl53l1x_data *data, u16 reg, u16 val)
+{
+ __be16 buf = cpu_to_be16(val);
+
+ return regmap_bulk_write(data->regmap, reg, &buf, sizeof(buf));
+}
+
+static int vl53l1x_write_u32(struct vl53l1x_data *data, u16 reg, u32 val)
+{
+ __be32 buf = cpu_to_be32(val);
+
+ return regmap_bulk_write(data->regmap, reg, &buf, sizeof(buf));
+}
+
+static int vl53l1x_clear_irq(struct vl53l1x_data *data)
+{
+ return regmap_write(data->regmap, VL53L1X_REG_SYSTEM__INTERRUPT_CLEAR, 0x01);
+}
+
+static int vl53l1x_start_ranging(struct vl53l1x_data *data)
+{
+ int ret;
+
+ ret = vl53l1x_clear_irq(data);
+ if (ret)
+ return ret;
+
+ return regmap_write(data->regmap, VL53L1X_REG_SYSTEM__MODE_START,
+ VL53L1X_MODE_START_TIMED);
+}
+
+static int vl53l1x_stop_ranging(struct vl53l1x_data *data)
+{
+ return regmap_write(data->regmap, VL53L1X_REG_SYSTEM__MODE_START,
+ VL53L1X_MODE_START_STOP);
+}
+
+static int vl53l1x_wait_data_ready(struct vl53l1x_data *data)
+{
+ unsigned int val;
+
+ /* 1ms poll, 1s timeout covers max timing budgets (per ST Ultra Lite Driver) */
+ return regmap_read_poll_timeout(data->regmap,
+ VL53L1X_REG_GPIO__TIO_HV_STATUS, val,
+ (val & VL53L1X_GPIO__TIO_HV_STATUS_DATA_READY) != data->gpio_polarity,
+ 1 * USEC_PER_MSEC, 1 * USEC_PER_SEC);
+}
+
+/*
+ * Default configuration blob from ST's VL53L1X Ultra Lite Driver
+ * (STSW-IMG009).
+ */
+static const u8 vl53l1x_default_config[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x08, /* reg 0x2d..0x34 */
+ 0x00, 0x08, 0x10, 0x01, 0x01, 0x00, 0x00, 0x00, /* reg 0x35..0x3c */
+ 0x00, 0xFF, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, /* reg 0x3d..0x44 */
+ 0x00, 0x20, 0x0B, 0x00, 0x00, 0x02, 0x0A, 0x21, /* reg 0x45..0x4c */
+ 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xC8, /* reg 0x4d..0x54 */
+ 0x00, 0x00, 0x38, 0xFF, 0x01, 0x00, 0x08, 0x00, /* reg 0x55..0x5c */
+ 0x00, 0x01, 0xCC, 0x0F, 0x01, 0xF1, 0x0D, 0x01, /* reg 0x5d..0x64 */
+ 0x68, 0x00, 0x80, 0x08, 0xB8, 0x00, 0x00, 0x00, /* reg 0x65..0x6c */
+ 0x00, 0x0F, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, /* reg 0x6d..0x74 */
+ 0x00, 0x00, 0x01, 0x0F, 0x0D, 0x0E, 0x0E, 0x00, /* reg 0x75..0x7c */
+ 0x00, 0x02, 0xC7, 0xFF, 0x9B, 0x00, 0x00, 0x00, /* reg 0x7d..0x84 */
+ 0x01, 0x00, 0x00, /* reg 0x85..0x87 */
+};
+
+static int vl53l1x_chip_init(struct vl53l1x_data *data)
+{
+ struct device *dev = regmap_get_device(data->regmap);
+ unsigned int val;
+ u16 model_id;
+ int ret;
+
+ if (!data->xshut_reset) {
+ ret = regmap_write(data->regmap, VL53L1X_REG_SOFT_RESET, 0x00);
+ if (ret)
+ return ret;
+ fsleep(100); /* conservative reset pulse, no spec */
+
+ ret = regmap_write(data->regmap, VL53L1X_REG_SOFT_RESET, 0x01);
+ if (ret)
+ return ret;
+ fsleep(1000); /* conservative boot wait, no spec */
+ }
+
+ ret = regmap_read_poll_timeout(data->regmap,
+ VL53L1X_REG_FIRMWARE__SYSTEM_STATUS,
+ val, val & VL53L1X_FIRMWARE__SYSTEM_STATUS_BOOTED,
+ 1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC);
+ if (ret)
+ return dev_err_probe(dev, ret, "firmware boot timeout\n");
+
+ ret = vl53l1x_read_u16(data, VL53L1X_REG_IDENTIFICATION__MODEL_ID,
+ &model_id);
+ if (ret)
+ return ret;
+
+ if (model_id != VL53L1X_MODEL_ID_VAL)
+ dev_info(dev, "unknown model id: 0x%04x, continuing\n", model_id);
+
+ ret = regmap_bulk_write(data->regmap, VL53L1X_REG_DEFAULT_CONFIG,
+ vl53l1x_default_config,
+ sizeof(vl53l1x_default_config));
+ if (ret)
+ return ret;
+
+ ret = regmap_read(data->regmap, VL53L1X_REG_GPIO_HV_MUX__CTRL, &val);
+ if (ret)
+ return ret;
+ data->gpio_polarity = !!(val & VL53L1X_GPIO_HV_MUX_POLARITY);
+
+ /* Initial ranging cycle for VHV calibration */
+ ret = vl53l1x_start_ranging(data);
+ if (ret)
+ return ret;
+
+ ret = vl53l1x_wait_data_ready(data);
+ if (ret)
+ return ret;
+
+ ret = vl53l1x_clear_irq(data);
+ if (ret)
+ return ret;
+
+ ret = vl53l1x_stop_ranging(data);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap,
+ VL53L1X_REG_VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND,
+ VL53L1X_VHV_LOOP_BOUND_TWO);
+ if (ret)
+ return ret;
+
+ return regmap_write(data->regmap, VL53L1X_REG_VHV_CONFIG__INIT, 0x00);
+}
+
+static const struct reg_sequence vl53l1x_mode_short[] = {
+ { VL53L1X_REG_PHASECAL_CONFIG__TIMEOUT_MACROP, 0x14 },
+ { VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_A, 0x07 },
+ { VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_B, 0x05 },
+ { VL53L1X_REG_RANGE_CONFIG__VALID_PHASE_HIGH, 0x38 },
+ { VL53L1X_REG_SD_CONFIG__WOI_SD0, 0x07 },
+ { VL53L1X_REG_SD_CONFIG__WOI_SD1, 0x05 },
+ { VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD0, 0x06 },
+ { VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD1, 0x06 },
+};
+
+static const struct reg_sequence vl53l1x_mode_long[] = {
+ { VL53L1X_REG_PHASECAL_CONFIG__TIMEOUT_MACROP, 0x0A },
+ { VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_A, 0x0F },
+ { VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_B, 0x0D },
+ { VL53L1X_REG_RANGE_CONFIG__VALID_PHASE_HIGH, 0xB8 },
+ { VL53L1X_REG_SD_CONFIG__WOI_SD0, 0x0F },
+ { VL53L1X_REG_SD_CONFIG__WOI_SD1, 0x0D },
+ { VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD0, 0x0E },
+ { VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD1, 0x0E },
+};
+
+static const struct {
+ const struct reg_sequence *regs;
+ size_t num_regs;
+} vl53l1x_mode_configs[] = {
+ [VL53L1X_SHORT] = { vl53l1x_mode_short, ARRAY_SIZE(vl53l1x_mode_short) },
+ [VL53L1X_LONG] = { vl53l1x_mode_long, ARRAY_SIZE(vl53l1x_mode_long) },
+};
+
+static int vl53l1x_set_distance_mode(struct vl53l1x_data *data,
+ enum vl53l1x_distance_mode mode)
+{
+ int ret;
+
+ if (mode >= ARRAY_SIZE(vl53l1x_mode_configs))
+ return -EINVAL;
+
+ ret = regmap_multi_reg_write(data->regmap,
+ vl53l1x_mode_configs[mode].regs,
+ vl53l1x_mode_configs[mode].num_regs);
+ if (ret)
+ return ret;
+
+ data->distance_mode = mode;
+ return 0;
+}
+
+/*
+ * The timing budget controls how long the sensor spends collecting
+ * a single range measurement. Pre-computed TIMEOUT_MACROP register
+ * values from ST's VL53L1X Ultra Lite Driver.
+ */
+static int vl53l1x_set_timing_budget(struct vl53l1x_data *data, u16 budget_ms)
+{
+ u16 timeout_a, timeout_b;
+ int ret;
+
+ switch (data->distance_mode) {
+ case VL53L1X_SHORT:
+ switch (budget_ms) {
+ case 15:
+ timeout_a = 0x001D;
+ timeout_b = 0x0027;
+ break;
+ case 20:
+ timeout_a = 0x0051;
+ timeout_b = 0x006E;
+ break;
+ case 33:
+ timeout_a = 0x00D6;
+ timeout_b = 0x006E;
+ break;
+ case 50:
+ timeout_a = 0x01AE;
+ timeout_b = 0x01E8;
+ break;
+ case 100:
+ timeout_a = 0x02E1;
+ timeout_b = 0x0388;
+ break;
+ case 200:
+ timeout_a = 0x03E1;
+ timeout_b = 0x0496;
+ break;
+ case 500:
+ timeout_a = 0x0591;
+ timeout_b = 0x05C1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case VL53L1X_LONG:
+ switch (budget_ms) {
+ case 20:
+ timeout_a = 0x001E;
+ timeout_b = 0x0022;
+ break;
+ case 33:
+ timeout_a = 0x0060;
+ timeout_b = 0x006E;
+ break;
+ case 50:
+ timeout_a = 0x00AD;
+ timeout_b = 0x00C6;
+ break;
+ case 100:
+ timeout_a = 0x01CC;
+ timeout_b = 0x01EA;
+ break;
+ case 200:
+ timeout_a = 0x02D9;
+ timeout_b = 0x02F8;
+ break;
+ case 500:
+ timeout_a = 0x048F;
+ timeout_b = 0x04A4;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = vl53l1x_write_u16(data, VL53L1X_REG_RANGE_CONFIG__TIMEOUT_MACROP_A,
+ timeout_a);
+ if (ret)
+ return ret;
+
+ return vl53l1x_write_u16(data, VL53L1X_REG_RANGE_CONFIG__TIMEOUT_MACROP_B,
+ timeout_b);
+}
+
+static int vl53l1x_set_inter_measurement_ms(struct vl53l1x_data *data,
+ u16 period_ms)
+{
+ u16 osc_calibrate_val;
+ u16 clock_pll;
+ u32 inter_meas;
+ int ret;
+
+ ret = vl53l1x_read_u16(data, VL53L1X_REG_RESULT__OSC_CALIBRATE_VAL,
+ &osc_calibrate_val);
+ if (ret)
+ return ret;
+
+ clock_pll = osc_calibrate_val & VL53L1X_OSC_CALIBRATE_MASK;
+ inter_meas = (clock_pll * period_ms * vl53l1x_osc_correction.numerator) /
+ vl53l1x_osc_correction.denominator;
+
+ return vl53l1x_write_u32(data,
+ VL53L1X_REG_SYSTEM__INTERMEASUREMENT_PERIOD,
+ inter_meas);
+}
+
+static int vl53l1x_read_proximity(struct vl53l1x_data *data, int *val)
+{
+ unsigned int range_status;
+ u16 distance;
+ int ret;
+
+ if (data->irq) {
+ reinit_completion(&data->completion);
+
+ ret = vl53l1x_clear_irq(data);
+ if (ret)
+ return ret;
+
+ if (!wait_for_completion_timeout(&data->completion, HZ))
+ return -ETIMEDOUT;
+ } else {
+ ret = vl53l1x_wait_data_ready(data);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_read(data->regmap, VL53L1X_REG_RESULT__RANGE_STATUS,
+ &range_status);
+ if (ret)
+ goto clear_irq;
+
+ if (FIELD_GET(VL53L1X_RANGE_STATUS_MASK, range_status) !=
+ VL53L1X_RANGE_STATUS_VALID) {
+ ret = -EIO;
+ goto clear_irq;
+ }
+
+ ret = vl53l1x_read_u16(data,
+ VL53L1X_REG_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0,
+ &distance);
+ if (ret)
+ goto clear_irq;
+
+ *val = distance;
+
+clear_irq:
+ vl53l1x_clear_irq(data);
+ return ret;
+}
+
+static const struct iio_chan_spec vl53l1x_channels[] = {
+ {
+ .type = IIO_DISTANCE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static int vl53l1x_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct vl53l1x_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (chan->type != IIO_DISTANCE)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = vl53l1x_read_proximity(data, val);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = 1000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info vl53l1x_info = {
+ .read_raw = vl53l1x_read_raw,
+ .validate_trigger = iio_validate_own_trigger,
+};
+
+static irqreturn_t vl53l1x_trigger_handler(int irq, void *priv)
+{
+ struct iio_poll_func *pf = priv;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct vl53l1x_data *data = iio_priv(indio_dev);
+ struct {
+ u16 distance;
+ aligned_s64 timestamp;
+ } scan = { };
+ unsigned int range_status;
+ int ret;
+
+ ret = regmap_read(data->regmap, VL53L1X_REG_RESULT__RANGE_STATUS,
+ &range_status);
+ if (ret)
+ goto notify_and_clear_irq;
+ if (FIELD_GET(VL53L1X_RANGE_STATUS_MASK, range_status) !=
+ VL53L1X_RANGE_STATUS_VALID)
+ goto notify_and_clear_irq;
+
+ ret = vl53l1x_read_u16(data,
+ VL53L1X_REG_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0,
+ &scan.distance);
+ if (ret)
+ goto notify_and_clear_irq;
+
+ iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
+ iio_get_time_ns(indio_dev));
+
+notify_and_clear_irq:
+ iio_trigger_notify_done(indio_dev->trig);
+ vl53l1x_clear_irq(data);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t vl53l1x_irq_handler(int irq, void *priv)
+{
+ struct iio_dev *indio_dev = priv;
+ struct vl53l1x_data *data = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev))
+ iio_trigger_poll(indio_dev->trig);
+ else
+ complete(&data->completion);
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_trigger_ops vl53l1x_trigger_ops = {
+ .validate_device = iio_trigger_validate_own_device,
+};
+
+static void vl53l1x_stop_ranging_action(void *priv)
+{
+ vl53l1x_stop_ranging(priv);
+}
+
+static int vl53l1x_configure_irq(struct device *dev, int irq,
+ struct iio_dev *indio_dev)
+{
+ struct vl53l1x_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = devm_request_irq(dev, irq, vl53l1x_irq_handler, IRQF_NO_THREAD,
+ indio_dev->name, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, VL53L1X_REG_SYSTEM__INTERRUPT_CONFIG_GPIO,
+ VL53L1X_INT_NEW_SAMPLE_READY);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to configure IRQ\n");
+
+ return 0;
+}
+
+static int vl53l1x_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct vl53l1x_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->irq = client->irq;
+
+ data->regmap = devm_regmap_init_i2c(client, &vl53l1x_regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(dev, PTR_ERR(data->regmap),
+ "regmap initialization failed\n");
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable VDD regulator\n");
+
+ /*
+ * XSHUT held low puts the chip in hardware standby. All register
+ * state is lost on de-assert so this is functionally a reset.
+ */
+ data->xshut_reset = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL);
+ if (IS_ERR(data->xshut_reset))
+ return dev_err_probe(dev, PTR_ERR(data->xshut_reset),
+ "Cannot get reset control\n");
+
+ /*
+ * 1.2 ms max boot duration.
+ * Datasheet Section 3.6 "Power up and boot sequence".
+ */
+ fsleep(1200);
+
+ ret = vl53l1x_chip_init(data);
+ if (ret)
+ return ret;
+
+ ret = vl53l1x_set_distance_mode(data, VL53L1X_LONG);
+ if (ret)
+ return ret;
+
+ /* 50 ms timing budget (per ST Ultra Lite Driver) */
+ ret = vl53l1x_set_timing_budget(data, 50);
+ if (ret)
+ return ret;
+
+ /* 50 ms inter-measurement period (per ST Ultra Lite Driver) */
+ ret = vl53l1x_set_inter_measurement_ms(data, 50);
+ if (ret)
+ return ret;
+
+ /*
+ * The hardware only supports "autonomous" continuous ranging mode.
+ * Start ranging here and leave it running for the lifetime of
+ * the device. Both direct reads and the buffer path rely on this.
+ */
+ ret = vl53l1x_start_ranging(data);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, vl53l1x_stop_ranging_action, data);
+ if (ret)
+ return ret;
+
+ indio_dev->name = "vl53l1x";
+ indio_dev->info = &vl53l1x_info;
+ indio_dev->channels = vl53l1x_channels;
+ indio_dev->num_channels = ARRAY_SIZE(vl53l1x_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ if (client->irq) {
+ struct iio_trigger *trig;
+
+ init_completion(&data->completion);
+
+ trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!trig)
+ return -ENOMEM;
+
+ trig->ops = &vl53l1x_trigger_ops;
+ iio_trigger_set_drvdata(trig, indio_dev);
+ ret = devm_iio_trigger_register(dev, trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(trig);
+
+ ret = vl53l1x_configure_irq(dev, client->irq, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ &vl53l1x_trigger_handler,
+ NULL);
+ if (ret)
+ return ret;
+ }
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id vl53l1x_id[] = {
+ { .name = "vl53l1x" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, vl53l1x_id);
+
+static const struct of_device_id st_vl53l1x_dt_match[] = {
+ { .compatible = "st,vl53l1x" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, st_vl53l1x_dt_match);
+
+static struct i2c_driver vl53l1x_driver = {
+ .driver = {
+ .name = "vl53l1x-i2c",
+ .of_match_table = st_vl53l1x_dt_match,
+ },
+ .probe = vl53l1x_probe,
+ .id_table = vl53l1x_id,
+};
+module_i2c_driver(vl53l1x_driver);
+
+MODULE_AUTHOR("Siratul Islam <siratul.islam@linux.dev>");
+MODULE_DESCRIPTION("ST VL53L1X ToF ranging sensor driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/iio/resolver/ad2s1200.c b/drivers/iio/resolver/ad2s1200.c
index c00a60cb31a5..27ecc434eee9 100644
--- a/drivers/iio/resolver/ad2s1200.c
+++ b/drivers/iio/resolver/ad2s1200.c
@@ -12,7 +12,6 @@
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
@@ -144,18 +143,14 @@ static int ad2s1200_probe(struct spi_device *spi)
st->sdev = spi;
st->sample = devm_gpiod_get(&spi->dev, "adi,sample", GPIOD_OUT_LOW);
- if (IS_ERR(st->sample)) {
- dev_err(&spi->dev, "Failed to claim SAMPLE gpio: err=%ld\n",
- PTR_ERR(st->sample));
- return PTR_ERR(st->sample);
- }
+ if (IS_ERR(st->sample))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->sample),
+ "Failed to claim SAMPLE gpio\n");
st->rdvel = devm_gpiod_get(&spi->dev, "adi,rdvel", GPIOD_OUT_LOW);
- if (IS_ERR(st->rdvel)) {
- dev_err(&spi->dev, "Failed to claim RDVEL gpio: err=%ld\n",
- PTR_ERR(st->rdvel));
- return PTR_ERR(st->rdvel);
- }
+ if (IS_ERR(st->rdvel))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->rdvel),
+ "Failed to claim RDVEL gpio\n");
indio_dev->info = &ad2s1200_info;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -183,8 +178,8 @@ static const struct of_device_id ad2s1200_of_match[] = {
MODULE_DEVICE_TABLE(of, ad2s1200_of_match);
static const struct spi_device_id ad2s1200_id[] = {
- { "ad2s1200" },
- { "ad2s1205" },
+ { .name = "ad2s1200" },
+ { .name = "ad2s1205" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad2s1200_id);
diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c
index 06d9c784f93e..3b5ec21e3446 100644
--- a/drivers/iio/resolver/ad2s1210.c
+++ b/drivers/iio/resolver/ad2s1210.c
@@ -896,14 +896,14 @@ static const struct iio_event_spec ad2s1210_monitor_signal_event_spec[] = {
.mask_separate = BIT(IIO_EV_INFO_VALUE),
},
{
- /* Sine/cosine DOS overrange fault.*/
+ /* Sine/cosine DOS overrange fault. */
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
- /* Degredation of signal overrange threshold. */
+ /* Degradation of signal overrange threshold. */
.mask_separate = BIT(IIO_EV_INFO_VALUE),
},
{
- /* Sine/cosine DOS mismatch fault.*/
+ /* Sine/cosine DOS mismatch fault. */
.type = IIO_EV_TYPE_MAG,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
@@ -1276,10 +1276,8 @@ static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev,
return regmap_write(st->regmap, reg, writeval);
}
-static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
+static void ad2s1210_scan_to_buffers(struct iio_dev *indio_dev, s64 timestamp)
{
- struct iio_poll_func *pf = p;
- struct iio_dev *indio_dev = pf->indio_dev;
struct ad2s1210_state *st = iio_priv(indio_dev);
size_t chan = 0;
int ret;
@@ -1295,15 +1293,15 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
AD2S1210_REG_POSITION_MSB,
&st->sample.raw, 2);
if (ret < 0)
- goto error_ret;
+ return;
} else {
ret = ad2s1210_set_mode(st, MOD_POS);
if (ret < 0)
- goto error_ret;
+ return;
ret = spi_read(st->sdev, &st->sample, 3);
if (ret < 0)
- goto error_ret;
+ return;
}
memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
@@ -1315,15 +1313,15 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
AD2S1210_REG_VELOCITY_MSB,
&st->sample.raw, 2);
if (ret < 0)
- goto error_ret;
+ return;
} else {
ret = ad2s1210_set_mode(st, MOD_VEL);
if (ret < 0)
- goto error_ret;
+ return;
ret = spi_read(st->sdev, &st->sample, 3);
if (ret < 0)
- goto error_ret;
+ return;
}
memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
@@ -1334,16 +1332,22 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &reg_val);
if (ret < 0)
- return ret;
+ return;
st->sample.fault = reg_val;
}
- ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp);
+ ad2s1210_push_events(indio_dev, st->sample.fault, timestamp);
iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan),
- pf->timestamp);
+ timestamp);
+}
+
+static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
-error_ret:
+ ad2s1210_scan_to_buffers(indio_dev, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
@@ -1597,7 +1601,7 @@ static const struct of_device_id ad2s1210_of_match[] = {
MODULE_DEVICE_TABLE(of, ad2s1210_of_match);
static const struct spi_device_id ad2s1210_id[] = {
- { "ad2s1210" },
+ { .name = "ad2s1210" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad2s1210_id);
diff --git a/drivers/iio/resolver/ad2s90.c b/drivers/iio/resolver/ad2s90.c
index 18f1c905eeac..b7a2dcc42871 100644
--- a/drivers/iio/resolver/ad2s90.c
+++ b/drivers/iio/resolver/ad2s90.c
@@ -110,7 +110,7 @@ static const struct of_device_id ad2s90_of_match[] = {
MODULE_DEVICE_TABLE(of, ad2s90_of_match);
static const struct spi_device_id ad2s90_id[] = {
- { "ad2s90" },
+ { .name = "ad2s90" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad2s90_id);
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index 07d6e65709f7..0850bf691820 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_MAX31865) += max31865.o
obj-$(CONFIG_MCP9600) += mcp9600.o
obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_MLX90632) += mlx90632.o
-obj-$(CONFIG_MLX90632) += mlx90635.o
+obj-$(CONFIG_MLX90635) += mlx90635.o
obj-$(CONFIG_TMP006) += tmp006.o
obj-$(CONFIG_TMP007) += tmp007.o
obj-$(CONFIG_TMP117) += tmp117.o
diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c
index 9f628a8e5cfb..5e3262e461f4 100644
--- a/drivers/iio/temperature/hid-sensor-temperature.c
+++ b/drivers/iio/temperature/hid-sensor-temperature.c
@@ -8,7 +8,6 @@
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -45,7 +44,7 @@ static const struct iio_chan_spec temperature_channels[] = {
/* Adjust channel real bits based on report descriptor */
static void temperature_adjust_channel_bit_mask(struct iio_chan_spec *channels,
- int channel, int size)
+ int channel, int size)
{
channels[channel].scan_type.sign = 's';
/* Real storage bits will change based on the report desc. */
@@ -101,8 +100,8 @@ static int temperature_read_raw(struct iio_dev *indio_dev,
}
static int temperature_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct temperature_state *temp_st = iio_priv(indio_dev);
@@ -125,7 +124,7 @@ static const struct iio_info temperature_info = {
/* Callback handler to send event after all samples are received and captured */
static int temperature_proc_event(struct hid_sensor_hub_device *hsdev,
- unsigned int usage_id, void *pdev)
+ u32 usage_id, void *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct temperature_state *temp_st = iio_priv(indio_dev);
@@ -140,8 +139,9 @@ static int temperature_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int temperature_capture_sample(struct hid_sensor_hub_device *hsdev,
- unsigned int usage_id, size_t raw_len,
- char *raw_data, void *pdev)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct temperature_state *temp_st = iio_priv(indio_dev);
@@ -157,10 +157,10 @@ static int temperature_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int temperature_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct iio_chan_spec *channels,
- unsigned int usage_id,
- struct temperature_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ u32 usage_id,
+ struct temperature_state *st)
{
int ret;
@@ -171,8 +171,7 @@ static int temperature_parse_report(struct platform_device *pdev,
if (ret < 0)
return ret;
- temperature_adjust_channel_bit_mask(channels, 0,
- st->temperature_attr.size);
+ temperature_adjust_channel_bit_mask(channels, 0, st->temperature_attr.size);
st->scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_TEMPERATURE,
@@ -213,13 +212,13 @@ static int hid_temperature_probe(struct platform_device *pdev)
if (ret)
return ret;
- temp_chans = devm_kmemdup(&indio_dev->dev, temperature_channels,
- sizeof(temperature_channels), GFP_KERNEL);
+ temp_chans = devm_kmemdup(&pdev->dev, temperature_channels,
+ sizeof(temperature_channels), GFP_KERNEL);
if (!temp_chans)
return -ENOMEM;
ret = temperature_parse_report(pdev, hsdev, temp_chans,
- HID_USAGE_SENSOR_TEMPERATURE, temp_st);
+ HID_USAGE_SENSOR_TEMPERATURE, temp_st);
if (ret)
return ret;
@@ -232,7 +231,7 @@ static int hid_temperature_probe(struct platform_device *pdev)
atomic_set(&temp_st->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &temp_st->common_attributes);
+ &temp_st->common_attributes);
if (ret)
return ret;
@@ -240,11 +239,11 @@ static int hid_temperature_probe(struct platform_device *pdev)
temperature_callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE,
- &temperature_callbacks);
+ &temperature_callbacks);
if (ret)
goto error_remove_trigger;
- ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
+ ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_callback;
@@ -264,6 +263,7 @@ static void hid_temperature_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct temperature_state *temp_st = iio_priv(indio_dev);
+ iio_device_unregister(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE);
hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes);
}
diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
index 7dd40d69cce6..6efb5252a773 100644
--- a/drivers/iio/temperature/ltc2983.c
+++ b/drivers/iio/temperature/ltc2983.c
@@ -14,7 +14,6 @@
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/list.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -28,6 +27,8 @@
#define LTC2983_STATUS_REG 0x0000
#define LTC2983_TEMP_RES_START_REG 0x0010
#define LTC2983_TEMP_RES_END_REG 0x005F
+#define ADT7604_RES_RES_START_REG 0x0060
+#define ADT7604_RES_RES_END_REG 0x00AF
#define LTC2983_EEPROM_KEY_REG 0x00B0
#define LTC2983_EEPROM_READ_STATUS_REG 0x00D0
#define LTC2983_GLOBAL_CONFIG_REG 0x00F0
@@ -56,10 +57,10 @@
#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) \
- (((chan - 1) * 4) + LTC2983_TEMP_RES_START_REG)
+#define LTC2983_CHAN_ASSIGN_ADDR(chan) \
+ ((((chan) - 1) * 4) + LTC2983_CHAN_ASSIGN_START_REG)
+#define LTC2983_RESULT_ADDR(chan, base) \
+ ((((chan) - 1) * 4) + (base))
#define LTC2983_THERMOCOUPLE_DIFF_MASK BIT(3)
#define LTC2983_THERMOCOUPLE_SGL(x) \
FIELD_PREP(LTC2983_THERMOCOUPLE_DIFF_MASK, x)
@@ -186,17 +187,44 @@ enum {
LTC2983_SENSOR_SENSE_RESISTOR = 29,
LTC2983_SENSOR_DIRECT_ADC = 30,
LTC2983_SENSOR_ACTIVE_TEMP = 31,
+ /* Sensor types for some parts only; map to RTD_CUSTOM/THERMISTOR_CUSTOM in HW */
+ LTC2983_SENSOR_COPPER_TRACE = 32,
+ LTC2983_SENSOR_LEAK_DETECTOR = 33,
+ LTC2983_SENSOR_NUM
};
+/* Bitmask of sensor types supported by LTC2983/LTC2984 and derivatives */
+#define LTC2983_COMMON_SENSORS \
+ (GENMASK_ULL(LTC2983_SENSOR_THERMOCOUPLE_CUSTOM, LTC2983_SENSOR_THERMOCOUPLE) | \
+ GENMASK_ULL(LTC2983_SENSOR_RTD_CUSTOM, LTC2983_SENSOR_RTD) | \
+ GENMASK_ULL(LTC2983_SENSOR_THERMISTOR_CUSTOM, LTC2983_SENSOR_THERMISTOR) | \
+ BIT_ULL(LTC2983_SENSOR_DIODE) | \
+ BIT_ULL(LTC2983_SENSOR_SENSE_RESISTOR) | \
+ BIT_ULL(LTC2983_SENSOR_DIRECT_ADC))
+
+/* Bitmask of sensor types supported by ADT7604 */
+#define ADT7604_SENSORS \
+ (GENMASK_ULL(LTC2983_SENSOR_RTD_CUSTOM - 1, LTC2983_SENSOR_RTD) | \
+ GENMASK_ULL(LTC2983_SENSOR_THERMISTOR_CUSTOM - 1, LTC2983_SENSOR_THERMISTOR) | \
+ BIT_ULL(LTC2983_SENSOR_SENSE_RESISTOR) | \
+ BIT_ULL(LTC2983_SENSOR_COPPER_TRACE) | \
+ BIT_ULL(LTC2983_SENSOR_LEAK_DETECTOR))
+
#define to_thermocouple(_sensor) \
container_of(_sensor, struct ltc2983_thermocouple, sensor)
#define to_rtd(_sensor) \
container_of(_sensor, struct ltc2983_rtd, sensor)
+#define to_copper_trace(_sensor) \
+ container_of(_sensor, struct ltc2983_copper_trace, sensor)
+
#define to_thermistor(_sensor) \
container_of(_sensor, struct ltc2983_thermistor, sensor)
+#define to_leak_detector(_sensor) \
+ container_of(_sensor, struct ltc2983_leak_detector, sensor)
+
#define to_diode(_sensor) \
container_of(_sensor, struct ltc2983_diode, sensor)
@@ -212,7 +240,7 @@ enum {
struct ltc2983_chip_info {
const char *name;
unsigned int max_channels_nr;
- bool has_temp;
+ u64 supported_sensors;
bool has_eeprom;
};
@@ -247,6 +275,8 @@ struct ltc2983_sensor {
u32 chan;
/* sensor type */
u32 type;
+ /* number of IIO channels this sensor produces */
+ u8 n_iio_chan;
};
struct ltc2983_custom_sensor {
@@ -274,6 +304,25 @@ struct ltc2983_rtd {
u32 rtd_curve;
};
+struct ltc2983_copper_trace {
+ struct ltc2983_sensor sensor;
+ struct ltc2983_custom_sensor *custom;
+ u32 r_sense_chan;
+ u32 excitation_current;
+ /* selects the <1Ω variant: bits 17:0 of the channel word are zeroed,
+ * disabling excitation current and custom table fields (ADT7604
+ * datasheet Table 26)
+ */
+ bool is_sub_ohm;
+};
+
+struct ltc2983_leak_detector {
+ struct ltc2983_sensor sensor;
+ struct ltc2983_custom_sensor *custom;
+ u32 r_sense_chan;
+ u32 excitation_current;
+};
+
struct ltc2983_thermistor {
struct ltc2983_sensor sensor;
struct ltc2983_custom_sensor *custom;
@@ -351,11 +400,17 @@ 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);
+ struct device *dev = &st->spi->dev;
+ u32 reg = LTC2983_CHAN_ASSIGN_ADDR(sensor->chan);
+ u32 hw_type = sensor->type;
+
+ if (hw_type == LTC2983_SENSOR_COPPER_TRACE)
+ hw_type = LTC2983_SENSOR_RTD_CUSTOM;
+ else if (hw_type == LTC2983_SENSOR_LEAK_DETECTOR)
+ hw_type = LTC2983_SENSOR_THERMISTOR_CUSTOM;
- 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 |= LTC2983_CHAN_TYPE(hw_type);
+ dev_dbg(dev, "Assign reg:0x%04X, val:0x%08X\n", reg, chan_val);
st->chan_val = cpu_to_be32(chan_val);
return regmap_bulk_write(st->regmap, reg, &st->chan_val,
sizeof(st->chan_val));
@@ -485,6 +540,14 @@ __ltc2983_custom_sensor_new(struct ltc2983_data *st, const struct fwnode_handle
for (index = 0; index < n_entries; index++) {
u64 temp = ((u64 *)new_custom->table)[index];
+ /*
+ * Users specify plain coverage percentage (0-100). Convert
+ * to µK so __convert_to_raw() produces the correct hardware
+ * encoding: P + 273.15 K.
+ */
+ if ((index % 2) != 0 && !strcmp(propname, "adi,custom-leak-detector"))
+ temp = temp * 1000000 + 273150000;
+
if ((index % 2) != 0)
temp = __convert_to_raw(temp, 1024);
else if (has_signed && (s64)temp < 0)
@@ -578,6 +641,31 @@ static int ltc2983_rtd_assign_chan(struct ltc2983_data *st,
return __ltc2983_chan_assign_common(st, sensor, chan_val);
}
+static int ltc2983_copper_trace_assign_chan(struct ltc2983_data *st,
+ const struct ltc2983_sensor *sensor)
+{
+ struct ltc2983_copper_trace *ct = to_copper_trace(sensor);
+ u32 chan_val;
+
+ chan_val = LTC2983_CHAN_ASSIGN(ct->r_sense_chan);
+ /* Sensor config bits 21:18 must be 0b1001 (ADT7604 datasheet Table 26) */
+ chan_val |= LTC2983_RTD_CFG(0x9);
+
+ if (ct->is_sub_ohm) {
+ chan_val &= ~GENMASK(17, 0);
+ } else {
+ int ret;
+
+ chan_val |= LTC2983_RTD_EXC_CURRENT(ct->excitation_current);
+ ret = __ltc2983_chan_custom_sensor_assign(st, ct->custom,
+ &chan_val);
+ if (ret)
+ return ret;
+ }
+
+ return __ltc2983_chan_assign_common(st, sensor, chan_val);
+}
+
static int ltc2983_thermistor_assign_chan(struct ltc2983_data *st,
const struct ltc2983_sensor *sensor)
{
@@ -601,6 +689,25 @@ static int ltc2983_thermistor_assign_chan(struct ltc2983_data *st,
return __ltc2983_chan_assign_common(st, sensor, chan_val);
}
+static int ltc2983_leak_detector_assign_chan(struct ltc2983_data *st,
+ const struct ltc2983_sensor *sensor)
+{
+ struct ltc2983_leak_detector *ld = to_leak_detector(sensor);
+ u32 chan_val;
+ int ret;
+
+ chan_val = LTC2983_CHAN_ASSIGN(ld->r_sense_chan);
+ /* bits 21:19 must be 0b001 (ADT7604 datasheet Table 38) */
+ chan_val |= LTC2983_THERMISTOR_CFG(1);
+ chan_val |= LTC2983_THERMISTOR_EXC_CURRENT(ld->excitation_current);
+
+ ret = __ltc2983_chan_custom_sensor_assign(st, ld->custom, &chan_val);
+ if (ret)
+ return ret;
+
+ return __ltc2983_chan_assign_common(st, sensor, chan_val);
+}
+
static int ltc2983_diode_assign_chan(struct ltc2983_data *st,
const struct ltc2983_sensor *sensor)
{
@@ -656,19 +763,26 @@ static struct ltc2983_sensor *
ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data *st,
const struct ltc2983_sensor *sensor)
{
+ struct device *dev = &st->spi->dev;
struct ltc2983_thermocouple *thermo;
u32 oc_current;
int ret;
- thermo = devm_kzalloc(&st->spi->dev, sizeof(*thermo), GFP_KERNEL);
+ thermo = devm_kzalloc(dev, sizeof(*thermo), GFP_KERNEL);
if (!thermo)
return ERR_PTR(-ENOMEM);
if (fwnode_property_read_bool(child, "adi,single-ended"))
thermo->sensor_config = LTC2983_THERMOCOUPLE_SGL(1);
- ret = fwnode_property_read_u32(child, "adi,sensor-oc-current-microamp", &oc_current);
- if (!ret) {
+ if (fwnode_property_present(child, "adi,sensor-oc-current-microamp")) {
+ ret = fwnode_property_read_u32(child,
+ "adi,sensor-oc-current-microamp",
+ &oc_current);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "Failed to read adi,sensor-oc-current-microamp\n");
+
switch (oc_current) {
case 10:
thermo->sensor_config |=
@@ -687,7 +801,7 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data
LTC2983_THERMOCOUPLE_OC_CURR(3);
break;
default:
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ return dev_err_ptr_probe(dev, -EINVAL,
"Invalid open circuit current:%u\n",
oc_current);
}
@@ -697,8 +811,8 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data
/* validate channel index */
if (!(thermo->sensor_config & LTC2983_THERMOCOUPLE_DIFF_MASK) &&
sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
- "Invalid chann:%d for differential thermocouple\n",
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid channel %d for differential thermocouple\n",
sensor->chan);
struct fwnode_handle *ref __free(fwnode_handle) =
@@ -709,10 +823,10 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data
ret = fwnode_property_read_u32(ref, "reg", &thermo->cold_junction_chan);
if (ret)
/*
- * This would be catched later but we can just return
+ * This would be caught later but we can just return
* the error right away.
*/
- return dev_err_ptr_probe(&st->spi->dev, ret,
+ return dev_err_ptr_probe(dev, ret,
"Property reg must be given\n");
}
@@ -741,7 +855,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
struct ltc2983_rtd *rtd;
int ret = 0;
struct device *dev = &st->spi->dev;
- u32 excitation_current = 0, n_wires = 0;
+ u32 excitation_current = 0, n_wires = 2;
rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL);
if (!rtd)
@@ -758,8 +872,12 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
return dev_err_ptr_probe(dev, ret,
"Property reg must be given\n");
- ret = fwnode_property_read_u32(child, "adi,number-of-wires", &n_wires);
- if (!ret) {
+ if (fwnode_property_present(child, "adi,number-of-wires")) {
+ ret = fwnode_property_read_u32(child, "adi,number-of-wires", &n_wires);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "Failed to read adi,number-of-wires\n");
+
switch (n_wires) {
case 2:
rtd->sensor_config = LTC2983_RTD_N_WIRES(0);
@@ -796,9 +914,9 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
/*
* rtd channel indexes are a bit more complicated to validate.
* For 4wire RTD with rotation, the channel selection cannot be
- * >=19 since the chann + 1 is used in this configuration.
+ * >=19 since the channel + 1 is used in this configuration.
* For 4wire RTDs with kelvin rsense, the rsense channel cannot be
- * <=1 since chanel - 1 and channel - 2 are used.
+ * <=1 since channel - 1 and channel - 2 are used.
*/
if (rtd->sensor_config & LTC2983_RTD_4_WIRE_MASK) {
/* 4-wire */
@@ -813,18 +931,18 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
(rtd->r_sense_chan <= min))
/* kelvin rsense*/
return dev_err_ptr_probe(dev, -EINVAL,
- "Invalid rsense chann:%d to use in kelvin rsense\n",
+ "Invalid channel %d for kelvin rsense\n",
rtd->r_sense_chan);
if (sensor->chan < min || sensor->chan > max)
return dev_err_ptr_probe(dev, -EINVAL,
- "Invalid chann:%d for the rtd config\n",
+ "Invalid channel %d for RTD config\n",
sensor->chan);
} else {
/* same as differential case */
if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
- "Invalid chann:%d for RTD\n",
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid channel %d for RTD\n",
sensor->chan);
}
@@ -841,12 +959,13 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
rtd->sensor.fault_handler = ltc2983_common_fault_handler;
rtd->sensor.assign_chan = ltc2983_rtd_assign_chan;
- ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp",
- &excitation_current);
- if (ret) {
- /* default to 5uA */
- rtd->excitation_current = 1;
- } else {
+ if (fwnode_property_present(child, "adi,excitation-current-microamp")) {
+ ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp",
+ &excitation_current);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "Failed to read adi,excitation-current-microamp\n");
+
switch (excitation_current) {
case 5:
rtd->excitation_current = 0x01;
@@ -873,13 +992,21 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
rtd->excitation_current = 0x08;
break;
default:
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ return dev_err_ptr_probe(dev, -EINVAL,
"Invalid value for excitation current(%u)\n",
excitation_current);
}
+ } else {
+ /* default to 5uA */
+ rtd->excitation_current = 1;
}
- fwnode_property_read_u32(child, "adi,rtd-curve", &rtd->rtd_curve);
+ if (fwnode_property_present(child, "adi,rtd-curve")) {
+ ret = fwnode_property_read_u32(child, "adi,rtd-curve", &rtd->rtd_curve);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "Failed to read adi,rtd-curve\n");
+ }
return &rtd->sensor;
}
@@ -922,8 +1049,8 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s
/* validate channel index */
if (!(thermistor->sensor_config & LTC2983_THERMISTOR_DIFF_MASK) &&
sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
- "Invalid chann:%d for differential thermistor\n",
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid channel %d for differential thermistor\n",
sensor->chan);
/* check custom sensor */
@@ -949,22 +1076,18 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s
thermistor->sensor.fault_handler = ltc2983_common_fault_handler;
thermistor->sensor.assign_chan = ltc2983_thermistor_assign_chan;
- ret = fwnode_property_read_u32(child, "adi,excitation-current-nanoamp",
- &excitation_current);
- if (ret) {
- /* Auto range is not allowed for custom sensors */
- if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART)
- /* default to 1uA */
- thermistor->excitation_current = 0x03;
- else
- /* default to auto-range */
- thermistor->excitation_current = 0x0c;
- } else {
+ if (fwnode_property_present(child, "adi,excitation-current-nanoamp")) {
+ ret = fwnode_property_read_u32(child, "adi,excitation-current-nanoamp",
+ &excitation_current);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "Failed to read adi,excitation-current-nanoamp\n");
+
switch (excitation_current) {
case 0:
/* auto range */
if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART)
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ return dev_err_ptr_probe(dev, -EINVAL,
"Auto Range not allowed for custom sensors\n");
thermistor->excitation_current = 0x0c;
@@ -1003,24 +1126,222 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s
thermistor->excitation_current = 0x0b;
break;
default:
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ return dev_err_ptr_probe(dev, -EINVAL,
"Invalid value for excitation current(%u)\n",
excitation_current);
}
+ } else {
+ /* Auto range is not allowed for custom sensors */
+ if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART)
+ /* default to 1uA */
+ thermistor->excitation_current = 0x03;
+ else
+ /* default to auto-range */
+ thermistor->excitation_current = 0x0c;
}
return &thermistor->sensor;
}
static struct ltc2983_sensor *
+ltc2983_copper_trace_new(const struct fwnode_handle *child, struct ltc2983_data *st,
+ const struct ltc2983_sensor *sensor)
+{
+ struct device *dev = &st->spi->dev;
+ struct ltc2983_copper_trace *ct;
+ int ret;
+
+ if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid channel %d for copper trace\n",
+ sensor->chan);
+
+ ct = devm_kzalloc(dev, sizeof(*ct), GFP_KERNEL);
+ if (!ct)
+ return ERR_PTR(-ENOMEM);
+
+ struct fwnode_handle *ref __free(fwnode_handle) =
+ fwnode_find_reference(child, "adi,rsense-handle", 0);
+ if (IS_ERR(ref))
+ return dev_err_cast_probe(dev, ref,
+ "Property adi,rsense-handle missing or invalid\n");
+
+ ret = fwnode_property_read_u32(ref, "reg", &ct->r_sense_chan);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret, "Property reg must be given\n");
+
+ ct->is_sub_ohm = fwnode_property_read_bool(child, "adi,copper-trace-sub-ohm");
+
+ if (ct->is_sub_ohm && fwnode_property_present(child, "adi,custom-copper-trace"))
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "sub-ohm copper trace cannot have a custom table\n");
+
+ if (!ct->is_sub_ohm) {
+ u32 excitation_current = 0;
+
+ if (!fwnode_property_present(child, "adi,custom-copper-trace"))
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "adi,custom-copper-trace is required for >1 ohm copper trace\n");
+
+ ct->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-copper-trace",
+ false, 2048, false);
+ if (IS_ERR(ct->custom))
+ return ERR_CAST(ct->custom);
+
+ if (fwnode_property_present(child, "adi,excitation-current-microamp")) {
+ ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp",
+ &excitation_current);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "Failed to read adi,excitation-current-microamp\n");
+
+ switch (excitation_current) {
+ case 5:
+ ct->excitation_current = 0x01;
+ break;
+ case 10:
+ ct->excitation_current = 0x02;
+ break;
+ case 25:
+ ct->excitation_current = 0x03;
+ break;
+ case 50:
+ ct->excitation_current = 0x04;
+ break;
+ case 100:
+ ct->excitation_current = 0x05;
+ break;
+ case 250:
+ ct->excitation_current = 0x06;
+ break;
+ case 500:
+ ct->excitation_current = 0x07;
+ break;
+ case 1000:
+ ct->excitation_current = 0x08;
+ break;
+ default:
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid value for excitation current(%u)\n",
+ excitation_current);
+ }
+ } else {
+ /* default to 1mA per datasheet recommendation for copper trace */
+ ct->excitation_current = 0x08;
+ }
+ }
+
+ ct->sensor.fault_handler = ltc2983_common_fault_handler;
+ ct->sensor.assign_chan = ltc2983_copper_trace_assign_chan;
+ if (ct->is_sub_ohm)
+ ct->sensor.n_iio_chan = 1;
+ else
+ ct->sensor.n_iio_chan = 2;
+
+ return &ct->sensor;
+}
+
+static struct ltc2983_sensor *
+ltc2983_leak_detector_new(const struct fwnode_handle *child, struct ltc2983_data *st,
+ const struct ltc2983_sensor *sensor)
+{
+ struct device *dev = &st->spi->dev;
+ struct ltc2983_leak_detector *ld;
+ int ret;
+ u32 excitation_current = 0;
+
+ if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid channel %d for leak detector\n",
+ sensor->chan);
+
+ ld = devm_kzalloc(dev, sizeof(*ld), GFP_KERNEL);
+ if (!ld)
+ return ERR_PTR(-ENOMEM);
+
+ struct fwnode_handle *ref __free(fwnode_handle) =
+ fwnode_find_reference(child, "adi,rsense-handle", 0);
+ if (IS_ERR(ref))
+ return dev_err_cast_probe(dev, ref,
+ "Property adi,rsense-handle missing or invalid\n");
+
+ ret = fwnode_property_read_u32(ref, "reg", &ld->r_sense_chan);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "rsense channel must be configured\n");
+
+ if (!fwnode_property_present(child, "adi,custom-leak-detector"))
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "adi,custom-leak-detector is required for leak detectors\n");
+
+ ld->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-leak-detector",
+ false, 16, false);
+ if (IS_ERR(ld->custom))
+ return ERR_CAST(ld->custom);
+
+ ret = fwnode_property_read_u32(child, "adi,excitation-current-nanoamp",
+ &excitation_current);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "adi,excitation-current-nanoamp is required for leak detectors\n");
+
+ switch (excitation_current) {
+ case 250:
+ ld->excitation_current = 0x01;
+ break;
+ case 500:
+ ld->excitation_current = 0x02;
+ break;
+ case 1000:
+ ld->excitation_current = 0x03;
+ break;
+ case 5000:
+ ld->excitation_current = 0x04;
+ break;
+ case 10000:
+ ld->excitation_current = 0x05;
+ break;
+ case 25000:
+ ld->excitation_current = 0x06;
+ break;
+ case 50000:
+ ld->excitation_current = 0x07;
+ break;
+ case 100000:
+ ld->excitation_current = 0x08;
+ break;
+ case 250000:
+ ld->excitation_current = 0x09;
+ break;
+ case 500000:
+ ld->excitation_current = 0x0a;
+ break;
+ case 1000000:
+ ld->excitation_current = 0x0b;
+ break;
+ default:
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid value for excitation current(%u)\n",
+ excitation_current);
+ }
+
+ ld->sensor.fault_handler = ltc2983_common_fault_handler;
+ ld->sensor.assign_chan = ltc2983_leak_detector_assign_chan;
+ ld->sensor.n_iio_chan = 2;
+
+ return &ld->sensor;
+}
+
+static struct ltc2983_sensor *
ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data *st,
const struct ltc2983_sensor *sensor)
{
+ struct device *dev = &st->spi->dev;
struct ltc2983_diode *diode;
u32 temp = 0, excitation_current = 0;
int ret;
- diode = devm_kzalloc(&st->spi->dev, sizeof(*diode), GFP_KERNEL);
+ diode = devm_kzalloc(dev, sizeof(*diode), GFP_KERNEL);
if (!diode)
return ERR_PTR(-ENOMEM);
@@ -1036,17 +1357,21 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data *
/* validate channel index */
if (!(diode->sensor_config & LTC2983_DIODE_DIFF_MASK) &&
sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
- "Invalid chann:%d for differential thermistor\n",
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid channel %d for differential diode\n",
sensor->chan);
/* set common parameters */
diode->sensor.fault_handler = ltc2983_common_fault_handler;
diode->sensor.assign_chan = ltc2983_diode_assign_chan;
- ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp",
- &excitation_current);
- if (!ret) {
+ if (fwnode_property_present(child, "adi,excitation-current-microamp")) {
+ ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp",
+ &excitation_current);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "Failed to read adi,excitation-current-microamp\n");
+
switch (excitation_current) {
case 10:
diode->excitation_current = 0x00;
@@ -1061,13 +1386,18 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data *
diode->excitation_current = 0x03;
break;
default:
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ return dev_err_ptr_probe(dev, -EINVAL,
"Invalid value for excitation current(%u)\n",
excitation_current);
}
}
- fwnode_property_read_u32(child, "adi,ideal-factor-value", &temp);
+ if (fwnode_property_present(child, "adi,ideal-factor-value")) {
+ ret = fwnode_property_read_u32(child, "adi,ideal-factor-value", &temp);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "Failed to read adi,ideal-factor-value\n");
+ }
/* 2^20 resolution */
diode->ideal_factor_value = __convert_to_raw(temp, 1048576);
@@ -1079,23 +1409,24 @@ static struct ltc2983_sensor *ltc2983_r_sense_new(struct fwnode_handle *child,
struct ltc2983_data *st,
const struct ltc2983_sensor *sensor)
{
+ struct device *dev = &st->spi->dev;
struct ltc2983_rsense *rsense;
int ret;
u32 temp;
- rsense = devm_kzalloc(&st->spi->dev, sizeof(*rsense), GFP_KERNEL);
+ rsense = devm_kzalloc(dev, sizeof(*rsense), GFP_KERNEL);
if (!rsense)
return ERR_PTR(-ENOMEM);
/* validate channel index */
if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
- "Invalid chann:%d for r_sense\n",
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid channel %d for r_sense\n",
sensor->chan);
ret = fwnode_property_read_u32(child, "adi,rsense-val-milli-ohms", &temp);
if (ret)
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ return dev_err_ptr_probe(dev, -EINVAL,
"Property adi,rsense-val-milli-ohms missing\n");
/*
* Times 1000 because we have milli-ohms and __convert_to_raw
@@ -1115,9 +1446,10 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child,
struct ltc2983_data *st,
const struct ltc2983_sensor *sensor)
{
+ struct device *dev = &st->spi->dev;
struct ltc2983_adc *adc;
- adc = devm_kzalloc(&st->spi->dev, sizeof(*adc), GFP_KERNEL);
+ adc = devm_kzalloc(dev, sizeof(*adc), GFP_KERNEL);
if (!adc)
return ERR_PTR(-ENOMEM);
@@ -1125,8 +1457,8 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child,
adc->single_ended = true;
if (!adc->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
- "Invalid chan:%d for differential adc\n",
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid channel %d for differential ADC\n",
sensor->chan);
/* set common parameters */
@@ -1140,9 +1472,10 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child,
struct ltc2983_data *st,
const struct ltc2983_sensor *sensor)
{
+ struct device *dev = &st->spi->dev;
struct ltc2983_temp *temp;
- temp = devm_kzalloc(&st->spi->dev, sizeof(*temp), GFP_KERNEL);
+ temp = devm_kzalloc(dev, sizeof(*temp), GFP_KERNEL);
if (!temp)
return ERR_PTR(-ENOMEM);
@@ -1150,8 +1483,8 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child,
temp->single_ended = true;
if (!temp->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
- return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
- "Invalid chan:%d for differential temp\n",
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid channel %d for differential temp\n",
sensor->chan);
temp->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-temp",
@@ -1167,22 +1500,23 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child,
}
static int ltc2983_chan_read(struct ltc2983_data *st,
- const struct ltc2983_sensor *sensor, int *val)
+ const struct ltc2983_sensor *sensor,
+ u32 base_reg, int *val)
{
+ struct device *dev = &st->spi->dev;
u32 start_conversion = 0;
int ret;
unsigned long time;
start_conversion = LTC2983_STATUS_START(true);
start_conversion |= LTC2983_STATUS_CHAN_SEL(sensor->chan);
- dev_dbg(&st->spi->dev, "Start conversion on chan:%d, status:%02X\n",
+ dev_dbg(dev, "Start conversion on channel:%d, status:%02X\n",
sensor->chan, start_conversion);
+ reinit_completion(&st->completion);
/* start conversion */
ret = regmap_write(st->regmap, LTC2983_STATUS_REG, start_conversion);
if (ret)
return ret;
-
- reinit_completion(&st->completion);
/*
* wait for conversion to complete.
* 300 ms should be more than enough to complete the conversion.
@@ -1192,20 +1526,30 @@ static int ltc2983_chan_read(struct ltc2983_data *st,
time = wait_for_completion_timeout(&st->completion,
msecs_to_jiffies(300));
if (!time) {
- dev_warn(&st->spi->dev, "Conversion timed out\n");
+ dev_warn(dev, "Conversion timed out\n");
return -ETIMEDOUT;
}
/* read the converted data */
- ret = regmap_bulk_read(st->regmap, LTC2983_CHAN_RES_ADDR(sensor->chan),
+ ret = regmap_bulk_read(st->regmap, LTC2983_RESULT_ADDR(sensor->chan, base_reg),
&st->temp, sizeof(st->temp));
if (ret)
return ret;
*val = __be32_to_cpu(st->temp);
+ if (base_reg == ADT7604_RES_RES_START_REG) {
+ /*
+ * Resistance result register gives a plain unsigned value,
+ * D31 is always 0, no valid bit, no fault bits. Read bits[30:0]
+ * directly — the temperature result format does not apply here.
+ */
+ *val &= GENMASK(30, 0);
+ return 0;
+ }
+
if (!(LTC2983_RES_VALID_MASK & *val)) {
- dev_err(&st->spi->dev, "Invalid conversion detected\n");
+ dev_err(dev, "Invalid conversion detected\n");
return -EIO;
}
@@ -1222,19 +1566,28 @@ static int ltc2983_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct ltc2983_data *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
int ret;
/* sanity check */
if (chan->address >= st->num_channels) {
- dev_err(&st->spi->dev, "Invalid chan address:%ld",
- chan->address);
+ dev_err(dev, "Invalid channel address: %ld\n", chan->address);
return -EINVAL;
}
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
- ret = ltc2983_chan_read(st, st->sensors[chan->address], val);
+ switch (chan->type) {
+ case IIO_RESISTANCE:
+ ret = ltc2983_chan_read(st, st->sensors[chan->address],
+ ADT7604_RES_RES_START_REG, val);
+ break;
+ default:
+ ret = ltc2983_chan_read(st, st->sensors[chan->address],
+ LTC2983_TEMP_RES_START_REG, val);
+ break;
+ }
mutex_unlock(&st->lock);
return ret ?: IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@@ -1251,6 +1604,13 @@ static int ltc2983_read_raw(struct iio_dev *indio_dev,
/* 2^21 */
*val2 = 2097152;
return IIO_VAL_FRACTIONAL;
+ case IIO_RESISTANCE:
+ case IIO_COVERAGE:
+ /* value in ohm/percent */
+ *val = 1;
+ /* 2^10 */
+ *val2 = 1024;
+ return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
@@ -1303,7 +1663,7 @@ static int ltc2983_parse_fw(struct ltc2983_data *st)
st->num_channels = device_get_child_node_count(dev);
if (!st->num_channels)
- return dev_err_probe(&st->spi->dev, -EINVAL,
+ return dev_err_probe(dev, -EINVAL,
"At least one channel must be given!\n");
st->sensors = devm_kcalloc(dev, st->num_channels, sizeof(*st->sensors),
@@ -1311,7 +1671,7 @@ static int ltc2983_parse_fw(struct ltc2983_data *st)
if (!st->sensors)
return -ENOMEM;
- st->iio_channels = st->num_channels;
+ st->iio_channels = 0;
device_for_each_child_node_scoped(dev, child) {
struct ltc2983_sensor sensor;
@@ -1324,14 +1684,14 @@ static int ltc2983_parse_fw(struct ltc2983_data *st)
if (sensor.chan < LTC2983_MIN_CHANNELS_NR ||
sensor.chan > st->info->max_channels_nr)
return dev_err_probe(dev, -EINVAL,
- "chan:%d must be from %u to %u\n",
+ "channel:%d must be from %u to %u\n",
sensor.chan,
LTC2983_MIN_CHANNELS_NR,
st->info->max_channels_nr);
if (channel_avail_mask & BIT(sensor.chan))
return dev_err_probe(dev, -EINVAL,
- "chan:%d already in use\n",
+ "channel:%d already in use\n",
sensor.chan);
ret = fwnode_property_read_u32(child, "adi,sensor-type", &sensor.type);
@@ -1339,7 +1699,13 @@ static int ltc2983_parse_fw(struct ltc2983_data *st)
return dev_err_probe(dev, ret,
"adi,sensor-type property must given for child nodes\n");
- dev_dbg(dev, "Create new sensor, type %u, chann %u",
+ if (sensor.type >= LTC2983_SENSOR_NUM ||
+ !(st->info->supported_sensors & BIT_ULL(sensor.type)))
+ return dev_err_probe(dev, -EINVAL,
+ "sensor type %d not supported on %s\n",
+ sensor.type, st->info->name);
+
+ dev_dbg(dev, "Create new sensor, type %u, channel %u",
sensor.type, sensor.chan);
if (sensor.type >= LTC2983_SENSOR_THERMOCOUPLE &&
@@ -1359,13 +1725,14 @@ static int ltc2983_parse_fw(struct ltc2983_data *st)
} else if (sensor.type == LTC2983_SENSOR_SENSE_RESISTOR) {
st->sensors[chan] = ltc2983_r_sense_new(child, st,
&sensor);
- /* don't add rsense to iio */
- 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) {
+ } else if (sensor.type == LTC2983_SENSOR_ACTIVE_TEMP) {
st->sensors[chan] = ltc2983_temp_new(child, st, &sensor);
+ } else if (sensor.type == LTC2983_SENSOR_COPPER_TRACE) {
+ st->sensors[chan] = ltc2983_copper_trace_new(child, st, &sensor);
+ } else if (sensor.type == LTC2983_SENSOR_LEAK_DETECTOR) {
+ st->sensors[chan] = ltc2983_leak_detector_new(child, st, &sensor);
} else {
return dev_err_probe(dev, -EINVAL,
"Unknown sensor type %d\n",
@@ -1380,6 +1747,16 @@ static int ltc2983_parse_fw(struct ltc2983_data *st)
st->sensors[chan]->chan = sensor.chan;
st->sensors[chan]->type = sensor.type;
+ /*
+ * Dedicated functions set n_iio_chan themselves; for all other
+ * sensor types rsense produces 0 channels, everything else 1.
+ */
+ if (!st->sensors[chan]->n_iio_chan) {
+ if (sensor.type != LTC2983_SENSOR_SENSE_RESISTOR)
+ st->sensors[chan]->n_iio_chan = 1;
+ }
+ st->iio_channels += st->sensors[chan]->n_iio_chan;
+
channel_avail_mask |= BIT(sensor.chan);
chan++;
}
@@ -1391,6 +1768,7 @@ 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)
{
+ struct device *dev = &st->spi->dev;
unsigned long time;
unsigned int val;
int ret;
@@ -1410,7 +1788,7 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd,
time = wait_for_completion_timeout(&st->completion,
msecs_to_jiffies(wait_time));
if (!time)
- return dev_err_probe(&st->spi->dev, -ETIMEDOUT,
+ return dev_err_probe(dev, -ETIMEDOUT,
"EEPROM command timed out\n");
ret = regmap_read(st->regmap, status_reg, &val);
@@ -1418,7 +1796,7 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd,
return ret;
if (val & status_fail_mask)
- return dev_err_probe(&st->spi->dev, -EINVAL,
+ return dev_err_probe(dev, -EINVAL,
"EEPROM command failed: 0x%02X\n", val);
return 0;
@@ -1426,7 +1804,9 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd,
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;
+ struct device *dev = &st->spi->dev;
+ u32 iio_chan_t = 0, iio_chan_v = 0, iio_chan_r = 0, iio_chan_c = 0;
+ u32 chan, iio_idx = 0, status;
int ret;
/* make sure the device is up: start bit (7) is 0 and done bit (6) is 1 */
@@ -1434,8 +1814,7 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio)
LTC2983_STATUS_UP(status) == 1, 25000,
25000 * 10);
if (ret)
- return dev_err_probe(&st->spi->dev, ret,
- "Device startup timed out\n");
+ return dev_err_probe(dev, ret, "Device startup timed out\n");
ret = regmap_update_bits(st->regmap, LTC2983_GLOBAL_CONFIG_REG,
LTC2983_NOTCH_FREQ_MASK,
@@ -1474,12 +1853,33 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio)
continue;
/* assign iio channel */
- if (st->sensors[chan]->type != LTC2983_SENSOR_DIRECT_ADC) {
- chan_type = IIO_TEMP;
- iio_chan = &iio_chan_t;
- } else {
+ switch (st->sensors[chan]->type) {
+ case LTC2983_SENSOR_COPPER_TRACE:
+ if (st->sensors[chan]->n_iio_chan == 1) {
+ /* sub-ohm copper traces produce only a resistance result */
+ st->iio_chan[iio_idx++] =
+ LTC2983_CHAN(IIO_RESISTANCE, iio_chan_r++, chan);
+ } else {
+ st->iio_chan[iio_idx++] =
+ LTC2983_CHAN(IIO_TEMP, iio_chan_t++, chan);
+ st->iio_chan[iio_idx++] =
+ LTC2983_CHAN(IIO_RESISTANCE, iio_chan_r++, chan);
+ }
+ continue;
+ case LTC2983_SENSOR_LEAK_DETECTOR:
+ st->iio_chan[iio_idx++] =
+ LTC2983_CHAN(IIO_COVERAGE, iio_chan_c++, chan);
+ st->iio_chan[iio_idx++] =
+ LTC2983_CHAN(IIO_RESISTANCE, iio_chan_r++, chan);
+ continue;
+ case LTC2983_SENSOR_DIRECT_ADC:
chan_type = IIO_VOLTAGE;
iio_chan = &iio_chan_v;
+ break;
+ default:
+ chan_type = IIO_TEMP;
+ iio_chan = &iio_chan_t;
+ break;
}
/*
@@ -1496,6 +1896,7 @@ 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(ADT7604_RES_RES_START_REG, ADT7604_RES_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),
@@ -1535,12 +1936,13 @@ static const struct iio_info ltc2983_iio_info = {
static int ltc2983_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
struct ltc2983_data *st;
struct iio_dev *indio_dev;
struct gpio_desc *gpio;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -1552,7 +1954,7 @@ static int ltc2983_probe(struct spi_device *spi)
st->regmap = devm_regmap_init_spi(spi, &ltc2983_regmap_config);
if (IS_ERR(st->regmap))
- return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
"Failed to initialize regmap\n");
mutex_init(&st->lock);
@@ -1565,11 +1967,11 @@ static int ltc2983_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_regulator_get_enable(&spi->dev, "vdd");
+ ret = devm_regulator_get_enable(dev, "vdd");
if (ret)
return ret;
- gpio = devm_gpiod_get_optional(&st->spi->dev, "reset", GPIOD_OUT_HIGH);
+ gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
@@ -1579,7 +1981,7 @@ static int ltc2983_probe(struct spi_device *spi)
gpiod_set_value_cansleep(gpio, 0);
}
- st->iio_chan = devm_kzalloc(&spi->dev,
+ st->iio_chan = devm_kzalloc(dev,
st->iio_channels * sizeof(*st->iio_chan),
GFP_KERNEL);
if (!st->iio_chan)
@@ -1589,11 +1991,10 @@ static int ltc2983_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler,
+ ret = devm_request_irq(dev, spi->irq, ltc2983_irq_handler,
IRQF_TRIGGER_RISING, st->info->name, st);
if (ret)
- return dev_err_probe(&spi->dev, ret,
- "failed to request an irq\n");
+ return ret;
if (st->info->has_eeprom) {
ret = ltc2983_eeprom_cmd(st, LTC2983_EEPROM_WRITE_CMD,
@@ -1610,7 +2011,7 @@ static int ltc2983_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ltc2983_iio_info;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static int ltc2983_resume(struct device *dev)
@@ -1634,41 +2035,52 @@ 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 adt7604_chip_info_data = {
+ .name = "adt7604",
+ .max_channels_nr = 20,
+ .has_eeprom = true,
+ .supported_sensors = ADT7604_SENSORS,
+};
+
static const struct ltc2983_chip_info ltc2983_chip_info_data = {
.name = "ltc2983",
.max_channels_nr = 20,
+ .supported_sensors = LTC2983_COMMON_SENSORS,
};
static const struct ltc2983_chip_info ltc2984_chip_info_data = {
.name = "ltc2984",
.max_channels_nr = 20,
.has_eeprom = true,
+ .supported_sensors = LTC2983_COMMON_SENSORS,
};
static const struct ltc2983_chip_info ltc2986_chip_info_data = {
.name = "ltc2986",
.max_channels_nr = 10,
- .has_temp = true,
.has_eeprom = true,
+ .supported_sensors = LTC2983_COMMON_SENSORS | BIT_ULL(LTC2983_SENSOR_ACTIVE_TEMP),
};
static const struct ltc2983_chip_info ltm2985_chip_info_data = {
.name = "ltm2985",
.max_channels_nr = 10,
- .has_temp = true,
.has_eeprom = true,
+ .supported_sensors = LTC2983_COMMON_SENSORS | BIT_ULL(LTC2983_SENSOR_ACTIVE_TEMP),
};
static const struct spi_device_id ltc2983_id_table[] = {
- { "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)&ltm2985_chip_info_data },
+ { .name = "adt7604", .driver_data = (kernel_ulong_t)&adt7604_chip_info_data },
+ { .name = "ltc2983", .driver_data = (kernel_ulong_t)&ltc2983_chip_info_data },
+ { .name = "ltc2984", .driver_data = (kernel_ulong_t)&ltc2984_chip_info_data },
+ { .name = "ltc2986", .driver_data = (kernel_ulong_t)&ltc2986_chip_info_data },
+ { .name = "ltm2985", .driver_data = (kernel_ulong_t)&ltm2985_chip_info_data },
{ }
};
MODULE_DEVICE_TABLE(spi, ltc2983_id_table);
static const struct of_device_id ltc2983_of_match[] = {
+ { .compatible = "adi,adt7604", .data = &adt7604_chip_info_data },
{ .compatible = "adi,ltc2983", .data = &ltc2983_chip_info_data },
{ .compatible = "adi,ltc2984", .data = &ltc2984_chip_info_data },
{ .compatible = "adi,ltc2986", .data = &ltc2986_chip_info_data },
diff --git a/drivers/iio/temperature/max30208.c b/drivers/iio/temperature/max30208.c
index 720469f9dc36..6172abc6d533 100644
--- a/drivers/iio/temperature/max30208.c
+++ b/drivers/iio/temperature/max30208.c
@@ -218,7 +218,7 @@ static int max30208_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id max30208_id_table[] = {
- { "max30208" },
+ { .name = "max30208" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max30208_id_table);
diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c
index 7ddec5cbe558..061f6fe6de5e 100644
--- a/drivers/iio/temperature/max31856.c
+++ b/drivers/iio/temperature/max31856.c
@@ -7,7 +7,6 @@
*/
#include <linux/ctype.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
@@ -462,7 +461,7 @@ static int max31856_probe(struct spi_device *spi)
}
static const struct spi_device_id max31856_id[] = {
- { "max31856", 0 },
+ { .name = "max31856" },
{ }
};
MODULE_DEVICE_TABLE(spi, max31856_id);
diff --git a/drivers/iio/temperature/max31865.c b/drivers/iio/temperature/max31865.c
index 5a6fbe3c80e5..f9c93f95d80b 100644
--- a/drivers/iio/temperature/max31865.c
+++ b/drivers/iio/temperature/max31865.c
@@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -325,7 +324,7 @@ static int max31865_probe(struct spi_device *spi)
}
static const struct spi_device_id max31865_id[] = {
- { "max31865", 0 },
+ { .name = "max31865" },
{ }
};
MODULE_DEVICE_TABLE(spi, max31865_id);
diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c
index 205939680fd4..5f216e238d55 100644
--- a/drivers/iio/temperature/maxim_thermocouple.c
+++ b/drivers/iio/temperature/maxim_thermocouple.c
@@ -7,7 +7,6 @@
*/
#include <linux/init.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
@@ -263,22 +262,22 @@ static int maxim_thermocouple_probe(struct spi_device *spi)
}
static const struct spi_device_id maxim_thermocouple_id[] = {
- {"max6675", MAX6675},
- {"max31855", MAX31855},
- {"max31855k", MAX31855K},
- {"max31855j", MAX31855J},
- {"max31855n", MAX31855N},
- {"max31855s", MAX31855S},
- {"max31855t", MAX31855T},
- {"max31855e", MAX31855E},
- {"max31855r", MAX31855R},
+ { .name = "max6675", .driver_data = MAX6675 },
+ { .name = "max31855", .driver_data = MAX31855 },
+ { .name = "max31855k", .driver_data = MAX31855K },
+ { .name = "max31855j", .driver_data = MAX31855J },
+ { .name = "max31855n", .driver_data = MAX31855N },
+ { .name = "max31855s", .driver_data = MAX31855S },
+ { .name = "max31855t", .driver_data = MAX31855T },
+ { .name = "max31855e", .driver_data = MAX31855E },
+ { .name = "max31855r", .driver_data = MAX31855R },
{ }
};
MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id);
static const struct of_device_id maxim_thermocouple_of_match[] = {
- { .compatible = "maxim,max6675" },
- { .compatible = "maxim,max31855" },
+ { .compatible = "maxim,max6675" },
+ { .compatible = "maxim,max31855" },
{ .compatible = "maxim,max31855k" },
{ .compatible = "maxim,max31855j" },
{ .compatible = "maxim,max31855n" },
@@ -286,7 +285,7 @@ static const struct of_device_id maxim_thermocouple_of_match[] = {
{ .compatible = "maxim,max31855t" },
{ .compatible = "maxim,max31855e" },
{ .compatible = "maxim,max31855r" },
- { },
+ { },
};
MODULE_DEVICE_TABLE(of, maxim_thermocouple_of_match);
diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c
index aa42c2b1a369..b0ff0c7b4891 100644
--- a/drivers/iio/temperature/mcp9600.c
+++ b/drivers/iio/temperature/mcp9600.c
@@ -16,7 +16,6 @@
#include <linux/irq.h>
#include <linux/math.h>
#include <linux/minmax.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/iio/events.h>
@@ -297,7 +296,7 @@ static int mcp9600_read_thresh(struct iio_dev *indio_dev,
* Temperature is stored in two’s complement format in
* bits(15:2), LSB is 0.25 degree celsius.
*/
- *val = sign_extend32(FIELD_GET(MCP9600_ALERT_LIMIT_MASK, ret), 13);
+ *val = FIELD_GET_SIGNED(MCP9600_ALERT_LIMIT_MASK, ret);
*val2 = 4;
return IIO_VAL_FRACTIONAL;
case IIO_EV_INFO_HYSTERESIS:
@@ -551,8 +550,8 @@ static const struct mcp_chip_info mcp9601_chip_info = {
};
static const struct i2c_device_id mcp9600_id[] = {
- { "mcp9600", .driver_data = (kernel_ulong_t)&mcp9600_chip_info },
- { "mcp9601", .driver_data = (kernel_ulong_t)&mcp9601_chip_info },
+ { .name = "mcp9600", .driver_data = (kernel_ulong_t)&mcp9600_chip_info },
+ { .name = "mcp9601", .driver_data = (kernel_ulong_t)&mcp9601_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp9600_id);
diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
index 1ad21b73e1b4..27d6ab5f5d7a 100644
--- a/drivers/iio/temperature/mlx90614.c
+++ b/drivers/iio/temperature/mlx90614.c
@@ -28,7 +28,6 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/jiffies.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
@@ -699,8 +698,8 @@ static const struct mlx_chip_info mlx90615_chip_info = {
};
static const struct i2c_device_id mlx90614_id[] = {
- { "mlx90614", .driver_data = (kernel_ulong_t)&mlx90614_chip_info },
- { "mlx90615", .driver_data = (kernel_ulong_t)&mlx90615_chip_info },
+ { .name = "mlx90614", .driver_data = (kernel_ulong_t)&mlx90614_chip_info },
+ { .name = "mlx90615", .driver_data = (kernel_ulong_t)&mlx90615_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, mlx90614_id);
diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c
index b44f7036c2cc..2fde48f337e2 100644
--- a/drivers/iio/temperature/mlx90632.c
+++ b/drivers/iio/temperature/mlx90632.c
@@ -16,7 +16,6 @@
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/limits.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/math64.h>
#include <linux/pm_runtime.h>
@@ -1276,7 +1275,7 @@ static int mlx90632_probe(struct i2c_client *client)
}
static const struct i2c_device_id mlx90632_id[] = {
- { "mlx90632" },
+ { .name = "mlx90632" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mlx90632_id);
diff --git a/drivers/iio/temperature/mlx90635.c b/drivers/iio/temperature/mlx90635.c
index 1c8948ca54df..0f31879a4f64 100644
--- a/drivers/iio/temperature/mlx90635.c
+++ b/drivers/iio/temperature/mlx90635.c
@@ -16,7 +16,6 @@
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/limits.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/math64.h>
#include <linux/pm_runtime.h>
@@ -1026,7 +1025,7 @@ static int mlx90635_probe(struct i2c_client *client)
}
static const struct i2c_device_id mlx90635_id[] = {
- { "mlx90635" },
+ { .name = "mlx90635" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mlx90635_id);
diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c
index d8d8c8936d17..d9f6449ec0d8 100644
--- a/drivers/iio/temperature/tmp006.c
+++ b/drivers/iio/temperature/tmp006.c
@@ -13,7 +13,6 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/pm.h>
#include <linux/bitops.h>
@@ -350,7 +349,7 @@ static int tmp006_probe(struct i2c_client *client)
data->drdy_trig->ops = &tmp006_trigger_ops;
iio_trigger_set_drvdata(data->drdy_trig, indio_dev);
- ret = iio_trigger_register(data->drdy_trig);
+ ret = devm_iio_trigger_register(&client->dev, data->drdy_trig);
if (ret)
return ret;
@@ -391,7 +390,7 @@ static const struct of_device_id tmp006_of_match[] = {
MODULE_DEVICE_TABLE(of, tmp006_of_match);
static const struct i2c_device_id tmp006_id[] = {
- { "tmp006" },
+ { .name = "tmp006" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp006_id);
diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c
index 043283b02c4d..4e743424f88e 100644
--- a/drivers/iio/temperature/tmp007.c
+++ b/drivers/iio/temperature/tmp007.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/bitops.h>
-#include <linux/mod_devicetable.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
@@ -528,10 +527,8 @@ static int tmp007_probe(struct i2c_client *client)
NULL, tmp007_interrupt_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
tmp007_id->name, indio_dev);
- if (ret) {
- dev_err(&client->dev, "irq request error %d\n", -ret);
+ if (ret)
return ret;
- }
}
return devm_iio_device_register(&client->dev, indio_dev);
@@ -563,7 +560,7 @@ static const struct of_device_id tmp007_of_match[] = {
MODULE_DEVICE_TABLE(of, tmp007_of_match);
static const struct i2c_device_id tmp007_id[] = {
- { "tmp007" },
+ { .name = "tmp007" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp007_id);
diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c
index 8972083d903a..74cb8d62bef3 100644
--- a/drivers/iio/temperature/tmp117.c
+++ b/drivers/iio/temperature/tmp117.c
@@ -9,6 +9,7 @@
* Note: This driver assumes that the sensor has been calibrated beforehand.
*/
+#include <linux/array_size.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
@@ -38,6 +39,7 @@
#define TMP116_DEVICE_ID 0x1116
#define TMP117_DEVICE_ID 0x0117
+#define TMP119_DEVICE_ID 0x2117
struct tmp117_data {
struct i2c_client *client;
@@ -139,6 +141,12 @@ static const struct tmp11x_info tmp117_channels_info = {
.num_channels = ARRAY_SIZE(tmp117_channels)
};
+static const struct tmp11x_info tmp119_channels_info = {
+ .name = "tmp119",
+ .channels = tmp117_channels,
+ .num_channels = ARRAY_SIZE(tmp117_channels)
+};
+
static const struct iio_info tmp117_info = {
.read_raw = tmp117_read_raw,
.write_raw = tmp117_write_raw,
@@ -172,6 +180,9 @@ static int tmp117_probe(struct i2c_client *client)
case TMP117_DEVICE_ID:
match_data = &tmp117_channels_info;
break;
+ case TMP119_DEVICE_ID:
+ match_data = &tmp119_channels_info;
+ break;
default:
dev_info(&client->dev,
"Unknown device id (0x%x), use fallback compatible\n",
@@ -204,13 +215,15 @@ static int tmp117_probe(struct i2c_client *client)
static const struct of_device_id tmp117_of_match[] = {
{ .compatible = "ti,tmp116", .data = &tmp116_channels_info },
{ .compatible = "ti,tmp117", .data = &tmp117_channels_info },
+ { .compatible = "ti,tmp119", .data = &tmp119_channels_info },
{ }
};
MODULE_DEVICE_TABLE(of, tmp117_of_match);
static const struct i2c_device_id tmp117_id[] = {
- { "tmp116", (kernel_ulong_t)&tmp116_channels_info },
- { "tmp117", (kernel_ulong_t)&tmp117_channels_info },
+ { .name = "tmp116", .driver_data = (kernel_ulong_t)&tmp116_channels_info },
+ { .name = "tmp117", .driver_data = (kernel_ulong_t)&tmp117_channels_info },
+ { .name = "tmp119", .driver_data = (kernel_ulong_t)&tmp119_channels_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp117_id);
diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c
index 334bba6fdae6..28b3ce022ce7 100644
--- a/drivers/iio/temperature/tsys01.c
+++ b/drivers/iio/temperature/tsys01.c
@@ -13,7 +13,6 @@
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/stat.h>
@@ -119,7 +118,7 @@ static bool tsys01_crc_valid(u16 *n_prom)
u8 sum = 0;
for (cnt = 0; cnt < TSYS01_PROM_WORDS_NB; cnt++)
- sum += ((n_prom[0] >> 8) + (n_prom[0] & 0xFF));
+ sum += ((n_prom[cnt] >> 8) + (n_prom[cnt] & 0xFF));
return (sum == 0);
}
@@ -206,7 +205,7 @@ static int tsys01_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id tsys01_id[] = {
- { "tsys01" },
+ { .name = "tsys01" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tsys01_id);
diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c
index 0cad27205667..3ef72347456e 100644
--- a/drivers/iio/temperature/tsys02d.c
+++ b/drivers/iio/temperature/tsys02d.c
@@ -168,7 +168,7 @@ static int tsys02d_probe(struct i2c_client *client)
}
static const struct i2c_device_id tsys02d_id[] = {
- { "tsys02d" },
+ { .name = "tsys02d" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tsys02d_id);
diff --git a/drivers/iio/test/iio-test-format.c b/drivers/iio/test/iio-test-format.c
index 872dd8582003..e5d0a2ac4670 100644
--- a/drivers/iio/test/iio-test-format.c
+++ b/drivers/iio/test/iio-test-format.c
@@ -200,56 +200,108 @@ static void iio_test_iio_format_value_multiple(struct kunit *test)
static void iio_test_iio_format_value_integer_64(struct kunit *test)
{
int values[2];
- s64 value;
char *buf;
int ret;
buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
- value = 24;
- values[0] = lower_32_bits(value);
- values[1] = upper_32_bits(value);
+ iio_val_s64_decompose(24, &values[0], &values[1]);
ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values);
IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "24\n");
- value = -24;
- values[0] = lower_32_bits(value);
- values[1] = upper_32_bits(value);
+ iio_val_s64_decompose(-24, &values[0], &values[1]);
ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values);
IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-24\n");
- value = 0;
- values[0] = lower_32_bits(value);
- values[1] = upper_32_bits(value);
+ iio_val_s64_decompose(0, &values[0], &values[1]);
ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values);
IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0\n");
- value = UINT_MAX;
- values[0] = lower_32_bits(value);
- values[1] = upper_32_bits(value);
+ iio_val_s64_decompose(UINT_MAX, &values[0], &values[1]);
ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values);
IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "4294967295\n");
- value = -((s64)UINT_MAX);
- values[0] = lower_32_bits(value);
- values[1] = upper_32_bits(value);
+ iio_val_s64_decompose(-((s64)UINT_MAX), &values[0], &values[1]);
ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values);
IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-4294967295\n");
- value = LLONG_MAX;
- values[0] = lower_32_bits(value);
- values[1] = upper_32_bits(value);
+ iio_val_s64_decompose(LLONG_MAX, &values[0], &values[1]);
ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values);
IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372036854775807\n");
- value = LLONG_MIN;
- values[0] = lower_32_bits(value);
- values[1] = upper_32_bits(value);
+ iio_val_s64_decompose(LLONG_MIN, &values[0], &values[1]);
ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values);
IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372036854775808\n");
}
+static void iio_test_iio_format_value_decimal_64(struct kunit *test)
+{
+ int values[2];
+ char *buf;
+ int ret;
+
+ buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
+
+ /* DECIMAL64_MILLI: positive >= 1, value 1.234 */
+ iio_val_s64_decompose(1234, &values[0], &values[1]);
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.234\n");
+
+ /* DECIMAL64_MICRO: positive >= 1, value 3.141592 */
+ iio_val_s64_decompose(3141592, &values[0], &values[1]);
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "3.141592\n");
+
+ /* DECIMAL64_MILLI: positive < 1, value 0.042 */
+ iio_val_s64_decompose(42, &values[0], &values[1]);
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.042\n");
+
+ /* DECIMAL64_MILLI: negative <= -1, value -1.234 */
+ iio_val_s64_decompose(-1234, &values[0], &values[1]);
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-1.234\n");
+
+ /* DECIMAL64_MILLI: negative > -1, value -0.123 */
+ iio_val_s64_decompose(-123, &values[0], &values[1]);
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.123\n");
+
+ /* DECIMAL64_MILLI: zero */
+ iio_val_s64_decompose(0, &values[0], &values[1]);
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000\n");
+
+ /* DECIMAL64_NANO: value 1.000000001 */
+ iio_val_s64_decompose(1000000001, &values[0], &values[1]);
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_NANO, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.000000001\n");
+
+ /* DECIMAL64_MICRO: large value using upper 32 bits */
+ iio_val_s64_decompose(5000000000000042LL, &values[0], &values[1]);
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "5000000000.000042\n");
+
+ /* limits */
+ iio_val_s64_decompose(LLONG_MAX, &values[0], &values[1]);
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_PICO, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372.036854775807\n");
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_NANO, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372036.854775807\n");
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372036854.775807\n");
+
+ iio_val_s64_decompose(LLONG_MIN, &values[0], &values[1]);
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_PICO, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372.036854775808\n");
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_NANO, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372036.854775808\n");
+ ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372036854.775808\n");
+}
+
static struct kunit_case iio_format_test_cases[] = {
KUNIT_CASE(iio_test_iio_format_value_integer),
KUNIT_CASE(iio_test_iio_format_value_fixedpoint),
@@ -257,6 +309,7 @@ static struct kunit_case iio_format_test_cases[] = {
KUNIT_CASE(iio_test_iio_format_value_fractional_log2),
KUNIT_CASE(iio_test_iio_format_value_multiple),
KUNIT_CASE(iio_test_iio_format_value_integer_64),
+ KUNIT_CASE(iio_test_iio_format_value_decimal_64),
{ }
};
diff --git a/drivers/iio/test/iio-test-gts.c b/drivers/iio/test/iio-test-gts.c
index 11250bc905c9..6ffff85ba853 100644
--- a/drivers/iio/test/iio-test-gts.c
+++ b/drivers/iio/test/iio-test-gts.c
@@ -20,7 +20,7 @@
*
* If yes, then adding a test is probably a good idea but please stop for a
* moment and consider the effort of changing all the tests when code gets
- * refactored. Eventually it neeeds to be.
+ * refactored. Eventually it needs to be.
*/
#define TEST_TSEL_50 1
diff --git a/drivers/iio/test/iio-test-rescale.c b/drivers/iio/test/iio-test-rescale.c
index ac6942cf1e44..bcd4a607be19 100644
--- a/drivers/iio/test/iio-test-rescale.c
+++ b/drivers/iio/test/iio-test-rescale.c
@@ -575,7 +575,7 @@ static const struct rescale_tc_data offset_cases[] = {
static void case_to_desc(const struct rescale_tc_data *t, char *desc)
{
- strcpy(desc, t->name);
+ strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
}
KUNIT_ARRAY_PARAM(iio_rescale_scale, scale_cases, case_to_desc);
diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
index 7ecb69725b1d..52899c22d57c 100644
--- a/drivers/iio/trigger/Kconfig
+++ b/drivers/iio/trigger/Kconfig
@@ -16,15 +16,6 @@ config IIO_HRTIMER_TRIGGER
To compile this driver as a module, choose M here: the
module will be called iio-trig-hrtimer.
-config IIO_INTERRUPT_TRIGGER
- tristate "Generic interrupt trigger"
- help
- Provides support for using an interrupt of any type as an IIO
- trigger. This may be provided by a gpio driver for example.
-
- To compile this driver as a module, choose M here: the
- module will be called iio-trig-interrupt.
-
config IIO_STM32_LPTIMER_TRIGGER
tristate "STM32 Low-Power Timer Trigger"
depends on MFD_STM32_LPTIMER || COMPILE_TEST
diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile
index f3d11acb8a0b..fc1fd5661c94 100644
--- a/drivers/iio/trigger/Makefile
+++ b/drivers/iio/trigger/Makefile
@@ -6,7 +6,6 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
-obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
obj-$(CONFIG_IIO_STM32_LPTIMER_TRIGGER) += stm32-lptimer-trigger.o
obj-$(CONFIG_IIO_STM32_TIMER_TRIGGER) += stm32-timer-trigger.o
obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c
deleted file mode 100644
index a100c2e3a0d9..000000000000
--- a/drivers/iio/trigger/iio-trig-interrupt.c
+++ /dev/null
@@ -1,109 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Industrial I/O - generic interrupt based trigger support
- *
- * Copyright (c) 2008-2013 Jonathan Cameron
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/trigger.h>
-
-
-struct iio_interrupt_trigger_info {
- unsigned int irq;
-};
-
-static irqreturn_t iio_interrupt_trigger_poll(int irq, void *private)
-{
- iio_trigger_poll(private);
- return IRQ_HANDLED;
-}
-
-static int iio_interrupt_trigger_probe(struct platform_device *pdev)
-{
- struct iio_interrupt_trigger_info *trig_info;
- struct iio_trigger *trig;
- unsigned long irqflags;
- struct resource *irq_res;
- int irq, ret = 0;
-
- irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-
- if (irq_res == NULL)
- return -ENODEV;
-
- irqflags = (irq_res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED;
-
- irq = irq_res->start;
-
- trig = iio_trigger_alloc(NULL, "irqtrig%d", irq);
- if (!trig) {
- ret = -ENOMEM;
- goto error_ret;
- }
-
- trig_info = kzalloc_obj(*trig_info);
- if (!trig_info) {
- ret = -ENOMEM;
- goto error_free_trigger;
- }
- iio_trigger_set_drvdata(trig, trig_info);
- trig_info->irq = irq;
- ret = request_irq(irq, iio_interrupt_trigger_poll,
- irqflags, trig->name, trig);
- if (ret) {
- dev_err(&pdev->dev,
- "request IRQ-%d failed", irq);
- goto error_free_trig_info;
- }
-
- ret = iio_trigger_register(trig);
- if (ret)
- goto error_release_irq;
- platform_set_drvdata(pdev, trig);
-
- return 0;
-
-/* First clean up the partly allocated trigger */
-error_release_irq:
- free_irq(irq, trig);
-error_free_trig_info:
- kfree(trig_info);
-error_free_trigger:
- iio_trigger_free(trig);
-error_ret:
- return ret;
-}
-
-static void iio_interrupt_trigger_remove(struct platform_device *pdev)
-{
- struct iio_trigger *trig;
- struct iio_interrupt_trigger_info *trig_info;
-
- trig = platform_get_drvdata(pdev);
- trig_info = iio_trigger_get_drvdata(trig);
- iio_trigger_unregister(trig);
- free_irq(trig_info->irq, trig);
- kfree(trig_info);
- iio_trigger_free(trig);
-}
-
-static struct platform_driver iio_interrupt_trigger_driver = {
- .probe = iio_interrupt_trigger_probe,
- .remove = iio_interrupt_trigger_remove,
- .driver = {
- .name = "iio_interrupt_trigger",
- },
-};
-
-module_platform_driver(iio_interrupt_trigger_driver);
-
-MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
-MODULE_DESCRIPTION("Interrupt trigger for the iio subsystem");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c
index c7bab18221c7..828890fe353c 100644
--- a/drivers/iio/trigger/stm32-lptimer-trigger.c
+++ b/drivers/iio/trigger/stm32-lptimer-trigger.c
@@ -12,7 +12,6 @@
#include <linux/export.h>
#include <linux/iio/timer/stm32-lptim-trigger.h>
#include <linux/mfd/stm32-lptimer.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index 3b9a3a6cbb25..4f6ff1e72f2e 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -12,7 +12,6 @@
#include <linux/iio/timer/stm32-timer-trigger.h>
#include <linux/iio/trigger.h>
#include <linux/mfd/stm32-timers.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>