summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS8
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio140
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8133
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-distance-srf088
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-humidity (renamed from Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc2010)3
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc100x9
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-lptimer-stm3262
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-proximity14
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-proximity-as39359
-rw-r--r--Documentation/devicetree/bindings/counter/interrupt-counter.yaml62
-rw-r--r--Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml68
-rw-r--r--Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml1
-rw-r--r--Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml181
-rw-r--r--Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml9
-rw-r--r--Documentation/devicetree/bindings/iio/proximity/google,cros-ec-mkbp-proximity.yaml37
-rw-r--r--Documentation/devicetree/bindings/iio/st,st-sensors.yaml1
-rw-r--r--Documentation/devicetree/bindings/mfd/google,cros-ec.yaml7
-rw-r--r--Documentation/driver-api/driver-model/devres.rst3
-rw-r--r--Documentation/driver-api/iio/buffers.rst15
-rw-r--r--Documentation/iio/iio_configfs.rst3
-rw-r--r--Documentation/userspace-api/ioctl/ioctl-number.rst1
-rw-r--r--MAINTAINERS22
-rw-r--r--drivers/counter/104-quad-8.c653
-rw-r--r--drivers/counter/Kconfig14
-rw-r--r--drivers/counter/Makefile1
-rw-r--r--drivers/counter/interrupt-cnt.c244
-rw-r--r--drivers/counter/stm32-lptimer-cnt.c297
-rw-r--r--drivers/firmware/arm_scmi/driver.c2
-rw-r--r--drivers/hwmon/ntc_thermistor.c27
-rw-r--r--drivers/iio/Kconfig1
-rw-r--r--drivers/iio/Makefile1
-rw-r--r--drivers/iio/accel/Kconfig18
-rw-r--r--drivers/iio/accel/Makefile2
-rw-r--r--drivers/iio/accel/adxl372.c2
-rw-r--r--drivers/iio/accel/bma180.c3
-rw-r--r--drivers/iio/accel/bma220_spi.c2
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c19
-rw-r--r--drivers/iio/accel/bmi088-accel-core.c567
-rw-r--r--drivers/iio/accel/bmi088-accel-spi.c83
-rw-r--r--drivers/iio/accel/bmi088-accel.h18
-rw-r--r--drivers/iio/accel/cros_ec_accel_legacy.c2
-rw-r--r--drivers/iio/accel/da280.c2
-rw-r--r--drivers/iio/accel/da311.c2
-rw-r--r--drivers/iio/accel/dmard10.c2
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c23
-rw-r--r--drivers/iio/accel/kxcjk-1013.c16
-rw-r--r--drivers/iio/accel/mc3230.c2
-rw-r--r--drivers/iio/accel/mma7660.c2
-rw-r--r--drivers/iio/accel/mma8452.c47
-rw-r--r--drivers/iio/accel/mxc4005.c1
-rw-r--r--drivers/iio/accel/sca3000.c27
-rw-r--r--drivers/iio/accel/ssp_accel_sensor.c14
-rw-r--r--drivers/iio/accel/stk8312.c3
-rw-r--r--drivers/iio/accel/stk8ba50.c3
-rw-r--r--drivers/iio/adc/Kconfig12
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/ad7124.c459
-rw-r--r--drivers/iio/adc/ad7292.c2
-rw-r--r--drivers/iio/adc/ad7606.c1
-rw-r--r--drivers/iio/adc/ad7766.c1
-rw-r--r--drivers/iio/adc/ad7768-1.c1
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c6
-rw-r--r--drivers/iio/adc/adi-axi-adc.c14
-rw-r--r--drivers/iio/adc/at91_adc.c3
-rw-r--r--drivers/iio/adc/cpcap-adc.c2
-rw-r--r--drivers/iio/adc/ina2xx-adc.c14
-rw-r--r--drivers/iio/adc/max1027.c1
-rw-r--r--drivers/iio/adc/mt6360-adc.c3
-rw-r--r--drivers/iio/adc/npcm_adc.c15
-rw-r--r--drivers/iio/adc/palmas_gpadc.c18
-rw-r--r--drivers/iio/adc/spear_adc.c20
-rw-r--r--drivers/iio/adc/stm32-adc.c39
-rw-r--r--drivers/iio/adc/ti-adc084s021.c6
-rw-r--r--drivers/iio/adc/ti-ads131e08.c948
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c18
-rw-r--r--drivers/iio/adc/xilinx-xadc-core.c1
-rw-r--r--drivers/iio/buffer/industrialio-buffer-dmaengine.c35
-rw-r--r--drivers/iio/buffer/industrialio-triggered-buffer.c10
-rw-r--r--drivers/iio/buffer/kfifo_buf.c45
-rw-r--r--drivers/iio/chemical/atlas-sensor.c1
-rw-r--r--drivers/iio/chemical/bme680_i2c.c3
-rw-r--r--drivers/iio/chemical/bme680_spi.c3
-rw-r--r--drivers/iio/chemical/ccs811.c1
-rw-r--r--drivers/iio/chemical/scd30_core.c1
-rw-r--r--drivers/iio/chemical/scd30_serial.c2
-rw-r--r--drivers/iio/common/Kconfig1
-rw-r--r--drivers/iio/common/Makefile1
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c3
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c3
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c33
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-attributes.c83
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c4
-rw-r--r--drivers/iio/common/scmi_sensors/Kconfig18
-rw-r--r--drivers/iio/common/scmi_sensors/Makefile5
-rw-r--r--drivers/iio/common/scmi_sensors/scmi_iio.c672
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_buffer.c2
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_trigger.c4
-rw-r--r--drivers/iio/dac/Kconfig5
-rw-r--r--drivers/iio/dac/ad5504.c2
-rw-r--r--drivers/iio/dac/ad5686.c12
-rw-r--r--drivers/iio/dac/ad5686.h2
-rw-r--r--drivers/iio/dac/ad5696-i2c.c6
-rw-r--r--drivers/iio/dac/ad5770r.c2
-rw-r--r--drivers/iio/dac/ad5791.c2
-rw-r--r--drivers/iio/dac/max517.c10
-rw-r--r--drivers/iio/dummy/iio_simple_dummy_buffer.c68
-rw-r--r--drivers/iio/gyro/adxrs290.c1
-rw-r--r--drivers/iio/gyro/bmg160_core.c2
-rw-r--r--drivers/iio/gyro/fxas21002c_core.c1
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c19
-rw-r--r--drivers/iio/gyro/itg3200_buffer.c3
-rw-r--r--drivers/iio/gyro/ssp_gyro_sensor.c14
-rw-r--r--drivers/iio/health/afe4403.c1
-rw-r--r--drivers/iio/health/afe4404.c1
-rw-r--r--drivers/iio/health/max30100.c16
-rw-r--r--drivers/iio/health/max30102.c16
-rw-r--r--drivers/iio/humidity/am2315.c2
-rw-r--r--drivers/iio/humidity/hid-sensor-humidity.c16
-rw-r--r--drivers/iio/humidity/hts221_buffer.c1
-rw-r--r--drivers/iio/iio_core.h32
-rw-r--r--drivers/iio/iio_core_trigger.h4
-rw-r--r--drivers/iio/imu/adis16400.c22
-rw-r--r--drivers/iio/imu/adis16475.c118
-rw-r--r--drivers/iio/imu/adis16480.c133
-rw-r--r--drivers/iio/imu/adis_trigger.c10
-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_accel.c14
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c13
-rw-r--r--drivers/iio/imu/kmx61.c1
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c15
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c3
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c3
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c3
-rw-r--r--drivers/iio/industrialio-buffer.c496
-rw-r--r--drivers/iio/industrialio-core.c132
-rw-r--r--drivers/iio/industrialio-event.c6
-rw-r--r--drivers/iio/industrialio-trigger.c40
-rw-r--r--drivers/iio/inkern.c16
-rw-r--r--drivers/iio/light/acpi-als.c117
-rw-r--r--drivers/iio/light/apds9960.c16
-rw-r--r--drivers/iio/light/cros_ec_light_prox.c3
-rw-r--r--drivers/iio/light/gp2ap002.c3
-rw-r--r--drivers/iio/light/gp2ap020a00f.c1
-rw-r--r--drivers/iio/light/hid-sensor-als.c34
-rw-r--r--drivers/iio/light/hid-sensor-prox.c32
-rw-r--r--drivers/iio/light/opt3001.c2
-rw-r--r--drivers/iio/light/rpr0521.c1
-rw-r--r--drivers/iio/light/si1145.c1
-rw-r--r--drivers/iio/light/st_uvis25_core.c1
-rw-r--r--drivers/iio/light/stk3310.c2
-rw-r--r--drivers/iio/light/vcnl4000.c1
-rw-r--r--drivers/iio/light/vcnl4035.c1
-rw-r--r--drivers/iio/magnetometer/bmc150_magn.c1
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c32
-rw-r--r--drivers/iio/magnetometer/rm3100-core.c1
-rw-r--r--drivers/iio/magnetometer/st_magn.h1
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c1
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c5
-rw-r--r--drivers/iio/magnetometer/st_magn_spi.c5
-rw-r--r--drivers/iio/orientation/hid-sensor-incl-3d.c20
-rw-r--r--drivers/iio/orientation/hid-sensor-rotation.c37
-rw-r--r--drivers/iio/position/hid-sensor-custom-intel-hinge.c20
-rw-r--r--drivers/iio/potentiometer/max5481.c4
-rw-r--r--drivers/iio/potentiometer/max5487.c4
-rw-r--r--drivers/iio/potentiostat/lmp91000.c3
-rw-r--r--drivers/iio/pressure/cros_ec_baro.c3
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c20
-rw-r--r--drivers/iio/pressure/zpa2326.c5
-rw-r--r--drivers/iio/proximity/Kconfig11
-rw-r--r--drivers/iio/proximity/Makefile1
-rw-r--r--drivers/iio/proximity/as3935.c1
-rw-r--r--drivers/iio/proximity/cros_ec_mkbp_proximity.c271
-rw-r--r--drivers/iio/proximity/sx9310.c1
-rw-r--r--drivers/iio/proximity/sx9500.c3
-rw-r--r--drivers/iio/proximity/vcnl3020.c97
-rw-r--r--drivers/iio/temperature/hid-sensor-temperature.c16
-rw-r--r--drivers/iio/temperature/tmp007.c36
-rw-r--r--drivers/iio/test/Kconfig9
-rw-r--r--drivers/iio/test/Makefile7
-rw-r--r--drivers/iio/test/iio-test-format.c198
-rw-r--r--drivers/iio/trigger/iio-trig-hrtimer.c37
-rw-r--r--drivers/iio/trigger/iio-trig-interrupt.c2
-rw-r--r--drivers/iio/trigger/iio-trig-loop.c2
-rw-r--r--drivers/iio/trigger/iio-trig-sysfs.c3
-rw-r--r--drivers/rtc/rtc-hid-sensor-time.c4
-rw-r--r--drivers/staging/iio/TODO4
-rw-r--r--drivers/staging/iio/frequency/ad9832.c4
-rw-r--r--drivers/staging/iio/frequency/ad9834.c67
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c23
-rw-r--r--include/linux/hid-sensor-hub.h9
-rw-r--r--include/linux/hid-sensor-ids.h1
-rw-r--r--include/linux/iio/adc/adi-axi-adc.h2
-rw-r--r--include/linux/iio/buffer-dmaengine.h7
-rw-r--r--include/linux/iio/buffer.h4
-rw-r--r--include/linux/iio/buffer_impl.h21
-rw-r--r--include/linux/iio/common/cros_ec_sensors_core.h3
-rw-r--r--include/linux/iio/consumer.h15
-rw-r--r--include/linux/iio/iio-opaque.h14
-rw-r--r--include/linux/iio/iio.h7
-rw-r--r--include/linux/iio/imu/adis.h10
-rw-r--r--include/linux/iio/kfifo_buf.h11
-rw-r--r--include/linux/iio/sysfs.h3
-rw-r--r--include/linux/iio/trigger.h3
-rw-r--r--include/linux/iio/types.h1
-rw-r--r--include/linux/platform_data/cros_ec_commands.h1
-rw-r--r--include/uapi/linux/iio/buffer.h10
-rw-r--r--tools/iio/Makefile1
-rw-r--r--tools/iio/iio_event_monitor.c69
-rw-r--r--tools/iio/iio_generic_buffer.c153
-rw-r--r--tools/iio/iio_utils.c18
-rw-r--r--tools/iio/iio_utils.h9
212 files changed, 5949 insertions, 2277 deletions
diff --git a/CREDITS b/CREDITS
index cef83b958cbe..91ea9b780bd9 100644
--- a/CREDITS
+++ b/CREDITS
@@ -2536,6 +2536,14 @@ D: Linux/PARISC hacker
D: AD1889 sound driver
S: Ottawa, Canada
+N: Peter Meerwald-Stadler
+E: pmeerw@pmeerw.net
+W: https://pmeerw.net
+D: IIO reviewing, drivers
+S: Schießstandstr. 3a
+S: A-5061 Elsbethen
+S: Austria
+
N: Dirk Melchers
E: dirk@merlin.nbg.sub.org
D: 8 bit XT hard disk driver for OMTI5520
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index d957f5da5c04..affd4ce871d7 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -33,6 +33,52 @@ Description:
Description of the physical chip / device for device X.
Typically a part number.
+What: /sys/bus/iio/devices/iio:deviceX/label
+KernelVersion: 5.8
+Contact: linux-iio@vger.kernel.org
+Description:
+ Optional symbolic label for a device.
+ This is useful for userspace to be able to better identify an
+ individual device.
+
+ The contents of the label are free-form, but there are some
+ standardized uses:
+
+ For proximity sensors which give the proximity (of a person) to
+ a certain wlan or wwan antenna the following standardized labels
+ are used:
+
+ * "proximity-wifi"
+ * "proximity-lte"
+ * "proximity-wifi-lte"
+ * "proximity-wifi-left"
+ * "proximity-wifi-right"
+
+ These are used to indicate to userspace that these proximity
+ sensors may be used to tune transmit power to ensure that
+ Specific Absorption Rate (SAR) limits are honored.
+ The "-left" and "-right" labels are for devices with multiple
+ antennas.
+
+ In some laptops/tablets the standardized proximity sensor labels
+ instead indicate proximity to a specific part of the device:
+
+ * "proximity-palmrest" indicates proximity to the keyboard's palmrest
+ * "proximity-palmrest-left" indicates proximity to the left part of the palmrest
+ * "proximity-palmrest-right" indicates proximity to the right part of the palmrest
+ * "proximity-lap" indicates the device is being used on someone's lap
+
+ Note "proximity-lap" is special in that its value may be
+ calculated by firmware from other sensor readings, rather then
+ being a raw sensor reading.
+
+ For accelerometers used in 2-in-1s with 360° (yoga-style) hinges,
+ which have an accelerometer in both their base and their display,
+ the following standardized labels are used:
+
+ * "accel-base"
+ * "accel-display"
+
What: /sys/bus/iio/devices/iio:deviceX/current_timestamp_clock
KernelVersion: 4.5
Contact: linux-iio@vger.kernel.org
@@ -1118,12 +1164,16 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/buffer/length
KernelVersion: 2.6.35
+What: /sys/bus/iio/devices/iio:deviceX/bufferY/length
+KernelVersion: 5.11
Contact: linux-iio@vger.kernel.org
Description:
Number of scans contained by the buffer.
What: /sys/bus/iio/devices/iio:deviceX/buffer/enable
KernelVersion: 2.6.35
+What: /sys/bus/iio/devices/iio:deviceX/bufferY/enable
+KernelVersion: 5.11
Contact: linux-iio@vger.kernel.org
Description:
Actually start the buffer capture up. Will start trigger
@@ -1131,11 +1181,16 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/scan_elements
KernelVersion: 2.6.37
+What: /sys/bus/iio/devices/iio:deviceX/bufferY
+KernelVersion: 5.11
Contact: linux-iio@vger.kernel.org
Description:
Directory containing interfaces for elements that will be
captured for a single triggered sample set in the buffer.
+ Since kernel 5.11 the scan_elements attributes are merged into
+ the bufferY directory, to be configurable per buffer.
+
What: /sys/.../iio:deviceX/scan_elements/in_accel_x_en
What: /sys/.../iio:deviceX/scan_elements/in_accel_y_en
What: /sys/.../iio:deviceX/scan_elements/in_accel_z_en
@@ -1164,6 +1219,34 @@ What: /sys/.../iio:deviceX/scan_elements/in_pressure_en
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_en
What: /sys/.../iio:deviceX/scan_elements/in_proximity_en
KernelVersion: 2.6.37
+What: /sys/.../iio:deviceX/bufferY/in_accel_x_en
+What: /sys/.../iio:deviceX/bufferY/in_accel_y_en
+What: /sys/.../iio:deviceX/bufferY/in_accel_z_en
+What: /sys/.../iio:deviceX/bufferY/in_anglvel_x_en
+What: /sys/.../iio:deviceX/bufferY/in_anglvel_y_en
+What: /sys/.../iio:deviceX/bufferY/in_anglvel_z_en
+What: /sys/.../iio:deviceX/bufferY/in_magn_x_en
+What: /sys/.../iio:deviceX/bufferY/in_magn_y_en
+What: /sys/.../iio:deviceX/bufferY/in_magn_z_en
+What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_magnetic_en
+What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_true_en
+What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_magnetic_tilt_comp_en
+What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_true_tilt_comp_en
+What: /sys/.../iio:deviceX/bufferY/in_timestamp_en
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_supply_en
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_en
+What: /sys/.../iio:deviceX/bufferY/in_voltageY-voltageZ_en
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_i_en
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_q_en
+What: /sys/.../iio:deviceX/bufferY/in_voltage_i_en
+What: /sys/.../iio:deviceX/bufferY/in_voltage_q_en
+What: /sys/.../iio:deviceX/bufferY/in_incli_x_en
+What: /sys/.../iio:deviceX/bufferY/in_incli_y_en
+What: /sys/.../iio:deviceX/bufferY/in_pressureY_en
+What: /sys/.../iio:deviceX/bufferY/in_pressure_en
+What: /sys/.../iio:deviceX/bufferY/in_rot_quaternion_en
+What: /sys/.../iio:deviceX/bufferY/in_proximity_en
+KernelVersion: 5.11
Contact: linux-iio@vger.kernel.org
Description:
Scan element control for triggered data capture.
@@ -1185,6 +1268,23 @@ What: /sys/.../iio:deviceX/scan_elements/in_pressure_type
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_type
What: /sys/.../iio:deviceX/scan_elements/in_proximity_type
KernelVersion: 2.6.37
+What: /sys/.../iio:deviceX/bufferY/in_accel_type
+What: /sys/.../iio:deviceX/bufferY/in_anglvel_type
+What: /sys/.../iio:deviceX/bufferY/in_magn_type
+What: /sys/.../iio:deviceX/bufferY/in_incli_type
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_type
+What: /sys/.../iio:deviceX/bufferY/in_voltage_type
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_supply_type
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_i_type
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_q_type
+What: /sys/.../iio:deviceX/bufferY/in_voltage_i_type
+What: /sys/.../iio:deviceX/bufferY/in_voltage_q_type
+What: /sys/.../iio:deviceX/bufferY/in_timestamp_type
+What: /sys/.../iio:deviceX/bufferY/in_pressureY_type
+What: /sys/.../iio:deviceX/bufferY/in_pressure_type
+What: /sys/.../iio:deviceX/bufferY/in_rot_quaternion_type
+What: /sys/.../iio:deviceX/bufferY/in_proximity_type
+KernelVersion: 5.11
Contact: linux-iio@vger.kernel.org
Description:
Description of the scan element data storage within the buffer
@@ -1241,6 +1341,33 @@ What: /sys/.../iio:deviceX/scan_elements/in_pressure_index
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_index
What: /sys/.../iio:deviceX/scan_elements/in_proximity_index
KernelVersion: 2.6.37
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_index
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_supply_index
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_i_index
+What: /sys/.../iio:deviceX/bufferY/in_voltageY_q_index
+What: /sys/.../iio:deviceX/bufferY/in_voltage_i_index
+What: /sys/.../iio:deviceX/bufferY/in_voltage_q_index
+What: /sys/.../iio:deviceX/bufferY/in_accel_x_index
+What: /sys/.../iio:deviceX/bufferY/in_accel_y_index
+What: /sys/.../iio:deviceX/bufferY/in_accel_z_index
+What: /sys/.../iio:deviceX/bufferY/in_anglvel_x_index
+What: /sys/.../iio:deviceX/bufferY/in_anglvel_y_index
+What: /sys/.../iio:deviceX/bufferY/in_anglvel_z_index
+What: /sys/.../iio:deviceX/bufferY/in_magn_x_index
+What: /sys/.../iio:deviceX/bufferY/in_magn_y_index
+What: /sys/.../iio:deviceX/bufferY/in_magn_z_index
+What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_magnetic_index
+What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_true_index
+What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_magnetic_tilt_comp_index
+What: /sys/.../iio:deviceX/bufferY/in_rot_from_north_true_tilt_comp_index
+What: /sys/.../iio:deviceX/bufferY/in_incli_x_index
+What: /sys/.../iio:deviceX/bufferY/in_incli_y_index
+What: /sys/.../iio:deviceX/bufferY/in_timestamp_index
+What: /sys/.../iio:deviceX/bufferY/in_pressureY_index
+What: /sys/.../iio:deviceX/bufferY/in_pressure_index
+What: /sys/.../iio:deviceX/bufferY/in_rot_quaternion_index
+What: /sys/.../iio:deviceX/bufferY/in_proximity_index
+KernelVersion: 5.11
Contact: linux-iio@vger.kernel.org
Description:
A single positive integer specifying the position of this
@@ -1455,6 +1582,8 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/buffer/watermark
KernelVersion: 4.2
+What: /sys/bus/iio/devices/iio:deviceX/bufferY/watermark
+KernelVersion: 5.11
Contact: linux-iio@vger.kernel.org
Description:
A single positive integer specifying the maximum number of scan
@@ -1473,6 +1602,8 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/buffer/data_available
KernelVersion: 4.16
+What: /sys/bus/iio/devices/iio:deviceX/bufferY/data_available
+KernelVersion: 5.11
Contact: linux-iio@vger.kernel.org
Description:
A read-only value indicating the bytes of data available in the
@@ -1823,3 +1954,12 @@ Description:
hinge, keyboard, screen. It means the three channels
each correspond respectively to hinge angle, keyboard angle,
and screen angle.
+
+What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_hysteresis_relative
+What: /sys/bus/iio/devices/iio:deviceX/in_intensity_hysteresis_relative
+KernelVersion: 5.12
+Contact: linux-iio@vger.kernel.org
+Description:
+ Specify the percent for light sensor relative to the channel
+ absolute value that a data field should change before an event
+ is generated. Units are a percentage of the prior reading.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 b/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8
deleted file mode 100644
index bac3d0d48b7b..000000000000
--- a/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8
+++ /dev/null
@@ -1,133 +0,0 @@
-What: /sys/bus/iio/devices/iio:deviceX/in_count_count_mode_available
-What: /sys/bus/iio/devices/iio:deviceX/in_count_noise_error_available
-What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available
-What: /sys/bus/iio/devices/iio:deviceX/in_index_index_polarity_available
-What: /sys/bus/iio/devices/iio:deviceX/in_index_synchronous_mode_available
-KernelVersion: 4.10
-Contact: linux-iio@vger.kernel.org
-Description:
- This interface is deprecated; please use the Counter subsystem.
-
- Discrete set of available values for the respective counter
- configuration are listed in this file.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_countY_count_mode
-KernelVersion: 4.10
-Contact: linux-iio@vger.kernel.org
-Description:
- This interface is deprecated; please use the Counter subsystem.
-
- Count mode for channel Y. Four count modes are available:
- normal, range limit, non-recycle, and modulo-n. The preset value
- for channel Y is used by the count mode where required.
-
- Normal:
- Counting is continuous in either direction.
-
- Range Limit:
- An upper or lower limit is set, mimicking limit switches
- in the mechanical counterpart. The upper limit is set to
- the preset value, while the lower limit is set to 0. The
- counter freezes at count = preset when counting up, and
- at count = 0 when counting down. At either of these
- limits, the counting is resumed only when the count
- direction is reversed.
-
- Non-recycle:
- Counter is disabled whenever a 24-bit count overflow or
- underflow takes place. The counter is re-enabled when a
- new count value is loaded to the counter via a preset
- operation or write to raw.
-
- Modulo-N:
- A count boundary is set between 0 and the preset value.
- The counter is reset to 0 at count = preset when
- counting up, while the counter is set to the preset
- value at count = 0 when counting down; the counter does
- not freeze at the bundary points, but counts
- continuously throughout.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_countY_noise_error
-KernelVersion: 4.10
-Contact: linux-iio@vger.kernel.org
-Description:
- This interface is deprecated; please use the Counter subsystem.
-
- Read-only attribute that indicates whether excessive noise is
- present at the channel Y count inputs in quadrature clock mode;
- irrelevant in non-quadrature clock mode.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_countY_preset
-KernelVersion: 4.10
-Contact: linux-iio@vger.kernel.org
-Description:
- This interface is deprecated; please use the Counter subsystem.
-
- If the counter device supports preset registers, the preset
- count for channel Y is provided by this attribute.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_countY_quadrature_mode
-KernelVersion: 4.10
-Contact: linux-iio@vger.kernel.org
-Description:
- This interface is deprecated; please use the Counter subsystem.
-
- Configure channel Y counter for non-quadrature or quadrature
- clock mode. Selecting non-quadrature clock mode will disable
- synchronous load mode. In quadrature clock mode, the channel Y
- scale attribute selects the encoder phase division (scale of 1
- selects full-cycle, scale of 0.5 selects half-cycle, scale of
- 0.25 selects quarter-cycle) processed by the channel Y counter.
-
- Non-quadrature:
- The filter and decoder circuit are bypassed. Encoder A
- input serves as the count input and B as the UP/DOWN
- direction control input, with B = 1 selecting UP Count
- mode and B = 0 selecting Down Count mode.
-
- Quadrature:
- Encoder A and B inputs are digitally filtered and
- decoded for UP/DN clock.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_countY_set_to_preset_on_index
-KernelVersion: 4.10
-Contact: linux-iio@vger.kernel.org
-Description:
- This interface is deprecated; please use the Counter subsystem.
-
- Whether to set channel Y counter with channel Y preset value
- when channel Y index input is active, or continuously count.
- Valid attribute values are boolean.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_indexY_index_polarity
-KernelVersion: 4.10
-Contact: linux-iio@vger.kernel.org
-Description:
- This interface is deprecated; please use the Counter subsystem.
-
- Active level of channel Y index input; irrelevant in
- non-synchronous load mode.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_indexY_synchronous_mode
-KernelVersion: 4.10
-Contact: linux-iio@vger.kernel.org
-Description:
- This interface is deprecated; please use the Counter subsystem.
-
- Configure channel Y counter for non-synchronous or synchronous
- load mode. Synchronous load mode cannot be selected in
- non-quadrature clock mode.
-
- Non-synchronous:
- A logic low level is the active level at this index
- input. The index function (as enabled via
- set_to_preset_on_index) is performed directly on the
- active level of the index input.
-
- Synchronous:
- Intended for interfacing with encoder Index output in
- quadrature clock mode. The active level is configured
- via index_polarity. The index function (as enabled via
- set_to_preset_on_index) is performed synchronously with
- the quadrature clock on the active level of the index
- input.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-distance-srf08 b/Documentation/ABI/testing/sysfs-bus-iio-distance-srf08
index 40df5c9fef99..9dae94aa880b 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio-distance-srf08
+++ b/Documentation/ABI/testing/sysfs-bus-iio-distance-srf08
@@ -1,11 +1,3 @@
-What: /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
-Date: January 2017
-KernelVersion: 4.11
-Contact: linux-iio@vger.kernel.org
-Description:
- Show or set the gain boost of the amp, from 0-31 range.
- default 31
-
What: /sys/bus/iio/devices/iio:deviceX/sensor_max_range
Date: January 2017
KernelVersion: 4.11
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc2010 b/Documentation/ABI/testing/sysfs-bus-iio-humidity
index 5b78af5f341d..cb0d7e75d297 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc2010
+++ b/Documentation/ABI/testing/sysfs-bus-iio-humidity
@@ -6,4 +6,5 @@ Description:
Controls the heater device within the humidity sensor to get
rid of excess condensation.
- Valid control values are 0 = OFF, and 1 = ON.
+ In some devices, this is just a switch in which case 0 = OFF,
+ and 1 = ON.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc100x b/Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc100x
deleted file mode 100644
index b72bb62552cf..000000000000
--- a/Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc100x
+++ /dev/null
@@ -1,9 +0,0 @@
-What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw
-What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw_available
-KernelVersion: 4.3
-Contact: linux-iio@vger.kernel.org
-Description:
- Controls the heater device within the humidity sensor to get
- rid of excess condensation.
-
- Valid control values are 0 = OFF, and 1 = ON.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-lptimer-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-lptimer-stm32
deleted file mode 100644
index 73498ff666bd..000000000000
--- a/Documentation/ABI/testing/sysfs-bus-iio-lptimer-stm32
+++ /dev/null
@@ -1,62 +0,0 @@
-What: /sys/bus/iio/devices/iio:deviceX/in_count0_preset
-KernelVersion: 4.13
-Contact: fabrice.gasnier@st.com
-Description:
- Reading returns the current preset value. Writing sets the
- preset value. Encoder counts continuously from 0 to preset
- value, depending on direction (up/down).
-
-What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available
-KernelVersion: 4.13
-Contact: fabrice.gasnier@st.com
-Description:
- Reading returns the list possible quadrature modes.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_count0_quadrature_mode
-KernelVersion: 4.13
-Contact: fabrice.gasnier@st.com
-Description:
- Configure the device counter quadrature modes:
-
- - non-quadrature:
- Encoder IN1 input servers as the count input (up
- direction).
-
- - quadrature:
- Encoder IN1 and IN2 inputs are mixed to get direction
- and count.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_count_polarity_available
-KernelVersion: 4.13
-Contact: fabrice.gasnier@st.com
-Description:
- Reading returns the list possible active edges.
-
-What: /sys/bus/iio/devices/iio:deviceX/in_count0_polarity
-KernelVersion: 4.13
-Contact: fabrice.gasnier@st.com
-Description:
- Configure the device encoder/counter active edge:
-
- - rising-edge
- - falling-edge
- - both-edges
-
- In non-quadrature mode, device counts up on active edge.
-
- In quadrature mode, encoder counting scenarios are as follows:
-
- +---------+----------+--------------------+--------------------+
- | Active | Level on | IN1 signal | IN2 signal |
- | edge | opposite +----------+---------+----------+---------+
- | | signal | Rising | Falling | Rising | Falling |
- +---------+----------+----------+---------+----------+---------+
- | Rising | High -> | Down | - | Up | - |
- | edge | Low -> | Up | - | Down | - |
- +---------+----------+----------+---------+----------+---------+
- | Falling | High -> | - | Up | - | Down |
- | edge | Low -> | - | Down | - | Up |
- +---------+----------+----------+---------+----------+---------+
- | Both | High -> | Down | Up | Up | Down |
- | edges | Low -> | Up | Down | Down | Up |
- +---------+----------+----------+---------+----------+---------+
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-proximity b/Documentation/ABI/testing/sysfs-bus-iio-proximity
index 2172f3bb9c64..3aac6dab8775 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio-proximity
+++ b/Documentation/ABI/testing/sysfs-bus-iio-proximity
@@ -8,3 +8,17 @@ Description:
considered close to the device. If the value read from the
sensor is above or equal to the value in this file an object
should typically be considered near.
+
+What: /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
+Date: March 2014
+KernelVersion: 3.15
+Contact: linux-iio@vger.kernel.org
+Description:
+ Proximity sensors sometimes have a controllable amplifier
+ on the signal from which time of flight measurements are
+ taken.
+ The appropriate values to take is dependent on both the
+ sensor and it's operating environment:
+ * as3935 (0-31 range)
+ 18 = indoors (default)
+ 14 = outdoors
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
index c59d95346341..1e5c40775a6c 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
+++ b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
@@ -6,15 +6,6 @@ Description:
Get the current distance in meters of storm (1km steps)
1000-40000 = distance in meters
-What: /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
-Date: March 2014
-KernelVersion: 3.15
-Contact: Matt Ranostay <matt.ranostay@konsulko.com>
-Description:
- Show or set the gain boost of the amp, from 0-31 range.
- 18 = indoors (default)
- 14 = outdoors
-
What /sys/bus/iio/devices/iio:deviceX/noise_level_tripped
Date: May 2017
KernelVersion: 4.13
diff --git a/Documentation/devicetree/bindings/counter/interrupt-counter.yaml b/Documentation/devicetree/bindings/counter/interrupt-counter.yaml
new file mode 100644
index 000000000000..fd075d104631
--- /dev/null
+++ b/Documentation/devicetree/bindings/counter/interrupt-counter.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/counter/interrupt-counter.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Interrupt counter
+
+maintainers:
+ - Oleksij Rempel <o.rempel@pengutronix.de>
+
+description: |
+ A generic interrupt counter to measure interrupt frequency. It was developed
+ and used for agricultural devices to measure rotation speed of wheels or
+ other tools. Since the direction of rotation is not important, only one
+ signal line is needed.
+ Interrupts or gpios are required. If both are defined, the interrupt will
+ take precedence for counting interrupts.
+
+properties:
+ compatible:
+ const: interrupt-counter
+
+ interrupts:
+ maxItems: 1
+
+ gpios:
+ maxItems: 1
+
+required:
+ - compatible
+
+anyOf:
+ - required: [ interrupts-extended ]
+ - required: [ interrupts ]
+ - required: [ gpios ]
+
+additionalProperties: false
+
+examples:
+ - |
+
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/gpio/gpio.h>
+
+ counter-0 {
+ compatible = "interrupt-counter";
+ interrupts-extended = <&gpio 0 IRQ_TYPE_EDGE_RISING>;
+ };
+
+ counter-1 {
+ compatible = "interrupt-counter";
+ gpios = <&gpio 2 GPIO_ACTIVE_HIGH>;
+ };
+
+ counter-2 {
+ compatible = "interrupt-counter";
+ interrupts-extended = <&gpio 2 IRQ_TYPE_EDGE_RISING>;
+ gpios = <&gpio 2 GPIO_ACTIVE_HIGH>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
new file mode 100644
index 000000000000..911a1ae9c83f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/accel/bosch,bmi088.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/accel/bosch,bmi088.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bosch BMI088 IMU accelerometer part
+
+maintainers:
+ - Mike Looijmans <mike.looijmans@topic.nl>
+
+description: |
+ Acceleration part of the IMU sensor with an SPI interface
+ Specifications about the sensor can be found at:
+ https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdf
+
+properties:
+ compatible:
+ enum:
+ - bosch,bmi088-accel
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency: true
+
+ vdd-supply: true
+
+ vddio-supply: true
+
+ interrupts:
+ minItems: 1
+ maxItems: 2
+ description: |
+ Type should be either IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_LEVEL_LOW.
+ Two configurable interrupt lines exist.
+
+ interrupt-names:
+ description: Specify which interrupt line is in use.
+ items:
+ enum:
+ - INT1
+ - INT2
+ minItems: 1
+ maxItems: 2
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bmi088-accel@1 {
+ compatible = "bosch,bmi088-accel";
+ reg = <1>;
+ spi-max-frequency = <10000000>;
+ interrupt-parent = <&gpio6>;
+ interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "INT2";
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml
index 5b21a9fba5dd..b939f9652e3a 100644
--- a/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml
@@ -34,6 +34,7 @@ properties:
- items:
- enum:
- mediatek,mt8183-auxadc
+ - mediatek,mt8195-auxadc
- mediatek,mt8516-auxadc
- const: mediatek,mt8173-auxadc
diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml
new file mode 100644
index 000000000000..e0670e3fbb72
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml
@@ -0,0 +1,181 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/ti,ads131e08.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments ADS131E0x 4-, 6- and 8-Channel ADCs
+
+maintainers:
+ - Tomislav Denis <tomislav.denis@avl.com>
+
+description: |
+ The ADS131E0x are a family of multichannel, simultaneous sampling,
+ 24-bit, delta-sigma, analog-to-digital converters (ADCs) with a
+ built-in programmable gain amplifier (PGA), internal reference
+ and an onboard oscillator.
+ The communication with ADC chip is via the SPI bus (mode 1).
+
+ https://www.ti.com/lit/ds/symlink/ads131e08.pdf
+
+properties:
+ compatible:
+ enum:
+ - ti,ads131e04
+ - ti,ads131e06
+ - ti,ads131e08
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency: true
+
+ spi-cpha: true
+
+ clocks:
+ description: |
+ Device tree identifier to the clock source (2.048 MHz).
+ Note: clock source is selected using CLKSEL pin.
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: adc-clk
+
+ interrupts:
+ description: |
+ IRQ line for the ADC data ready.
+ maxItems: 1
+
+ vref-supply:
+ description: |
+ Optional external voltage reference. If not supplied, internal voltage
+ reference is used.
+
+ ti,vref-internal:
+ description: |
+ Select the internal voltage reference value.
+ 0: 2.4V
+ 1: 4.0V
+ If this field is left empty, 2.4V is selected.
+ Note: internal voltage reference is used only if vref-supply is not supplied.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1]
+ default: 0
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - spi-cpha
+ - clocks
+ - clock-names
+ - interrupts
+
+patternProperties:
+ "^channel@([0-7])$":
+ $ref: "adc.yaml"
+ type: object
+ description: |
+ Represents the external channels which are connected to the ADC.
+
+ properties:
+ reg:
+ description: |
+ The channel number.
+ Up to 4 channels, numbered from 0 to 3 for ti,ads131e04.
+ Up to 6 channels, numbered from 0 to 5 for ti,ads131e06.
+ Up to 8 channels, numbered from 0 to 7 for ti,ads131e08.
+ items:
+ minimum: 0
+ maximum: 7
+
+ ti,gain:
+ description: |
+ The PGA gain value for the channel.
+ If this field is left empty, PGA gain 1 is used.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [1, 2, 4, 8, 12]
+ default: 1
+
+ ti,mux:
+ description: |
+ Channel input selection(muliplexer).
+ 0: Normal input.
+ 1: Input shorted to (VREFP + VREFN) / 2 (for offset or noise measurements).
+ 3: MVDD (for supply measurement)
+ 4: Temperature sensor
+ If this field is left empty, normal input is selected.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1, 3, 4]
+ default: 0
+
+ required:
+ - reg
+
+ additionalProperties: false
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@0 {
+ compatible = "ti,ads131e08";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ spi-cpha;
+ clocks = <&clk2048k>;
+ clock-names = "adc-clk";
+ interrupt-parent = <&gpio5>;
+ interrupts = <28 IRQ_TYPE_EDGE_FALLING>;
+ vref-supply = <&adc_vref>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@0 {
+ reg = <0>;
+ };
+
+ channel@1 {
+ reg = <1>;
+ };
+
+ channel@2 {
+ reg = <2>;
+ ti,gain = <2>;
+ };
+
+ channel@3 {
+ reg = <3>;
+ };
+
+ channel@4 {
+ reg = <4>;
+ };
+
+ channel@5 {
+ reg = <5>;
+ };
+
+ channel@6 {
+ reg = <6>;
+ };
+
+ channel@7 {
+ reg = <7>;
+ ti,mux = <4>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
index 79fba1508e89..a7574210175a 100644
--- a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
@@ -71,15 +71,6 @@ properties:
minimum: 0
maximum: 3
- adi,scaled-output-hz:
- description:
- This property must be present if the clock mode is scaled-sync through
- clock-names property. In this mode, the input clock can have a range
- of 1Hz to 128HZ which must be scaled to originate an allowable sample
- rate. This property specifies that rate.
- minimum: 1900
- maximum: 2100
-
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/iio/proximity/google,cros-ec-mkbp-proximity.yaml b/Documentation/devicetree/bindings/iio/proximity/google,cros-ec-mkbp-proximity.yaml
new file mode 100644
index 000000000000..099b4be927d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/proximity/google,cros-ec-mkbp-proximity.yaml
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+
+$id: http://devicetree.org/schemas/iio/proximity/google,cros-ec-mkbp-proximity.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ChromeOS EC MKBP Proximity Sensor
+
+maintainers:
+ - Stephen Boyd <swboyd@chromium.org>
+ - Benson Leung <bleung@chromium.org>
+ - Enric Balletbo i Serra <enric.balletbo@collabora.com>
+
+description: |
+ Google's ChromeOS EC sometimes has the ability to detect user proximity.
+ This is implemented on the EC as near/far logic and exposed to the OS
+ via an MKBP switch bit.
+
+properties:
+ compatible:
+ const: google,cros-ec-mkbp-proximity
+
+ label:
+ description: Name for proximity sensor
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ proximity {
+ compatible = "google,cros-ec-mkbp-proximity";
+ label = "proximity-wifi-lte";
+ };
diff --git a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml
index db291a9390b7..7e98f47987dc 100644
--- a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml
+++ b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml
@@ -66,6 +66,7 @@ properties:
- st,lis3mdl-magn
- st,lis2mdl
- st,lsm9ds1-magn
+ - st,iis2mdc
# Pressure sensors
- st,lps001wp-press
- st,lps25h-press
diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
index 76bf16ee27ec..4dfa70a013ae 100644
--- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
+++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
@@ -94,6 +94,9 @@ properties:
keyboard-controller:
$ref: "/schemas/input/google,cros-ec-keyb.yaml#"
+ proximity:
+ $ref: "/schemas/iio/proximity/google,cros-ec-mkbp-proximity.yaml#"
+
codecs:
type: object
additionalProperties: false
@@ -180,6 +183,10 @@ examples:
interrupts = <99 0>;
interrupt-parent = <&gpio7>;
spi-max-frequency = <5000000>;
+
+ proximity {
+ compatible = "google,cros-ec-mkbp-proximity";
+ };
};
};
diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
index cd8b6e657b94..5f8c6c303ff2 100644
--- a/Documentation/driver-api/driver-model/devres.rst
+++ b/Documentation/driver-api/driver-model/devres.rst
@@ -285,7 +285,8 @@ I2C
IIO
devm_iio_device_alloc()
devm_iio_device_register()
- devm_iio_kfifo_allocate()
+ devm_iio_dmaengine_buffer_setup()
+ devm_iio_kfifo_buffer_setup()
devm_iio_triggered_buffer_setup()
devm_iio_trigger_alloc()
devm_iio_trigger_register()
diff --git a/Documentation/driver-api/iio/buffers.rst b/Documentation/driver-api/iio/buffers.rst
index 3ddebddc02ca..e83026aebe97 100644
--- a/Documentation/driver-api/iio/buffers.rst
+++ b/Documentation/driver-api/iio/buffers.rst
@@ -28,24 +28,26 @@ IIO buffer setup
The meta information associated with a channel reading placed in a buffer is
called a scan element. The important bits configuring scan elements are
exposed to userspace applications via the
-:file:`/sys/bus/iio/iio:device{X}/scan_elements/*` directory. This file contains
+:file:`/sys/bus/iio/iio:device{X}/scan_elements/` directory. This directory contains
attributes of the following form:
* :file:`enable`, used for enabling a channel. If and only if its attribute
is non *zero*, then a triggered capture will contain data samples for this
channel.
+* :file:`index`, the scan_index of the channel.
* :file:`type`, description of the scan element data storage within the buffer
and hence the form in which it is read from user space.
- Format is [be|le]:[s|u]bits/storagebitsXrepeat[>>shift] .
+ Format is [be|le]:[s|u]bits/storagebits[Xrepeat][>>shift] .
+
* *be* or *le*, specifies big or little endian.
* *s* or *u*, specifies if signed (2's complement) or unsigned.
* *bits*, is the number of valid data bits.
* *storagebits*, is the number of bits (after padding) that it occupies in the
- buffer.
- * *shift*, if specified, is the shift that needs to be applied prior to
- masking out unused bits.
+ buffer.
* *repeat*, specifies the number of bits/storagebits repetitions. When the
- repeat element is 0 or 1, then the repeat value is omitted.
+ repeat element is 0 or 1, then the repeat value is omitted.
+ * *shift*, if specified, is the shift that needs to be applied prior to
+ masking out unused bits.
For example, a driver for a 3-axis accelerometer with 12 bit resolution where
data is stored in two 8-bits registers as follows::
@@ -122,4 +124,3 @@ More details
.. kernel-doc:: include/linux/iio/buffer.h
.. kernel-doc:: drivers/iio/industrialio-buffer.c
:export:
-
diff --git a/Documentation/iio/iio_configfs.rst b/Documentation/iio/iio_configfs.rst
index 3a5d76f9e2b9..b276397af797 100644
--- a/Documentation/iio/iio_configfs.rst
+++ b/Documentation/iio/iio_configfs.rst
@@ -71,7 +71,7 @@ kernel module following the interface in include/linux/iio/sw_trigger.h::
.ops = &iio_trig_sample_ops,
};
-module_iio_sw_trigger_driver(iio_trig_sample);
+ module_iio_sw_trigger_driver(iio_trig_sample);
Each trigger type has its own directory under /config/iio/triggers. Loading
iio-trig-sample module will create 'trig-sample' trigger type directory
@@ -99,3 +99,4 @@ Each trigger can have one or more attributes specific to the trigger type.
"hrtimer" trigger type doesn't have any configurable attribute from /config dir.
It does introduce the sampling_frequency attribute to trigger directory.
+That attribute sets the polling frequency in Hz, with mHz precision.
diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
index 599bd4493944..96b2ae9f277f 100644
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
@@ -245,6 +245,7 @@ Code Seq# Include File Comments
'i' 00-3F linux/i2o-dev.h conflict!
'i' 0B-1F linux/ipmi.h conflict!
'i' 80-8F linux/i8k.h
+'i' 90-9F `linux/iio/*.h` IIO
'j' 00-3F linux/joystick.h
'k' 00-0F linux/spi/spidev.h conflict!
'k' 00-05 video/kyro.h conflict!
diff --git a/MAINTAINERS b/MAINTAINERS
index cf3bbd1ba7da..00272c2f5393 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -300,7 +300,6 @@ M: Syed Nayyar Waris <syednwaris@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-counter-104-quad-8
-F: Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8
F: drivers/counter/104-quad-8.c
ACCES PCI-IDIO-16 GPIO DRIVER
@@ -8683,10 +8682,15 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
F: drivers/iio/multiplexer/iio-mux.c
+IIO SCMI BASED DRIVER
+M: Jyoti Bhayana <jbhayana@google.com>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: drivers/iio/common/scmi_sensors/scmi_iio.c
+
IIO SUBSYSTEM AND DRIVERS
M: Jonathan Cameron <jic23@kernel.org>
R: Lars-Peter Clausen <lars@metafoo.de>
-R: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
L: linux-iio@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
@@ -9281,6 +9285,13 @@ F: include/dt-bindings/interconnect/
F: include/linux/interconnect-provider.h
F: include/linux/interconnect.h
+INTERRUPT COUNTER DRIVER
+M: Oleksij Rempel <o.rempel@pengutronix.de>
+R: Pengutronix Kernel Team <kernel@pengutronix.de>
+L: linux-iio@vger.kernel.org
+F: Documentation/devicetree/bindings/counter/interrupt-counter.yaml
+F: drivers/counter/interrupt-cnt.c
+
INVENSENSE ICM-426xx IMU DRIVER
M: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
L: linux-iio@vger.kernel.org
@@ -17820,6 +17831,13 @@ M: Robert Richter <rric@kernel.org>
S: Odd Fixes
F: drivers/gpio/gpio-thunderx.c
+TI ADS131E0X ADC SERIES DRIVER
+M: Tomislav Denis <tomislav.denis@avl.com>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml
+F: drivers/iio/adc/ti-ads131e08.c
+
TI AM437X VPFE DRIVER
M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
L: linux-media@vger.kernel.org
diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
index 78766b6ec271..9691f8612be8 100644
--- a/drivers/counter/104-quad-8.c
+++ b/drivers/counter/104-quad-8.c
@@ -9,8 +9,6 @@
#include <linux/counter.h>
#include <linux/device.h>
#include <linux/errno.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/types.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/isa.h>
@@ -29,7 +27,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
#define QUAD8_NUM_COUNTERS 8
/**
- * struct quad8_iio - IIO device private data structure
+ * struct quad8 - device private data structure
* @counter: instance of the counter_device
* @fck_prescaler: array of filter clock prescaler configurations
* @preset: array of preset values
@@ -41,9 +39,9 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
* @synchronous_mode: array of index function synchronous mode configurations
* @index_polarity: array of index function polarity configurations
* @cable_fault_enable: differential encoder cable status enable configurations
- * @base: base port address of the IIO device
+ * @base: base port address of the device
*/
-struct quad8_iio {
+struct quad8 {
struct mutex lock;
struct counter_device counter;
unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
@@ -98,532 +96,10 @@ struct quad8_iio {
#define QUAD8_CMR_QUADRATURE_X2 0x10
#define QUAD8_CMR_QUADRATURE_X4 0x18
-
-static int quad8_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int *val, int *val2, long mask)
-{
- struct quad8_iio *const priv = iio_priv(indio_dev);
- const int base_offset = priv->base + 2 * chan->channel;
- unsigned int flags;
- unsigned int borrow;
- unsigned int carry;
- int i;
-
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- if (chan->type == IIO_INDEX) {
- *val = !!(inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS)
- & BIT(chan->channel));
- return IIO_VAL_INT;
- }
-
- flags = inb(base_offset + 1);
- borrow = flags & QUAD8_FLAG_BT;
- carry = !!(flags & QUAD8_FLAG_CT);
-
- /* Borrow XOR Carry effectively doubles count range */
- *val = (borrow ^ carry) << 24;
-
- mutex_lock(&priv->lock);
-
- /* Reset Byte Pointer; transfer Counter to Output Latch */
- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
- base_offset + 1);
-
- for (i = 0; i < 3; i++)
- *val |= (unsigned int)inb(base_offset) << (8 * i);
-
- mutex_unlock(&priv->lock);
-
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_ENABLE:
- *val = priv->ab_enable[chan->channel];
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_SCALE:
- *val = 1;
- *val2 = priv->quadrature_scale[chan->channel];
- return IIO_VAL_FRACTIONAL_LOG2;
- }
-
- return -EINVAL;
-}
-
-static int quad8_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int val, int val2, long mask)
-{
- struct quad8_iio *const priv = iio_priv(indio_dev);
- const int base_offset = priv->base + 2 * chan->channel;
- int i;
- unsigned int ior_cfg;
-
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- if (chan->type == IIO_INDEX)
- return -EINVAL;
-
- /* Only 24-bit values are supported */
- if ((unsigned int)val > 0xFFFFFF)
- return -EINVAL;
-
- mutex_lock(&priv->lock);
-
- /* Reset Byte Pointer */
- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
-
- /* Counter can only be set via Preset Register */
- for (i = 0; i < 3; i++)
- outb(val >> (8 * i), base_offset);
-
- /* Transfer Preset Register to Counter */
- outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1);
-
- /* Reset Byte Pointer */
- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
-
- /* Set Preset Register back to original value */
- val = priv->preset[chan->channel];
- for (i = 0; i < 3; i++)
- outb(val >> (8 * i), base_offset);
-
- /* Reset Borrow, Carry, Compare, and Sign flags */
- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);
- /* Reset Error flag */
- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1);
-
- mutex_unlock(&priv->lock);
-
- return 0;
- case IIO_CHAN_INFO_ENABLE:
- /* only boolean values accepted */
- if (val < 0 || val > 1)
- return -EINVAL;
-
- mutex_lock(&priv->lock);
-
- priv->ab_enable[chan->channel] = val;
-
- ior_cfg = val | priv->preset_enable[chan->channel] << 1;
-
- /* Load I/O control configuration */
- outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1);
-
- mutex_unlock(&priv->lock);
-
- return 0;
- case IIO_CHAN_INFO_SCALE:
- mutex_lock(&priv->lock);
-
- /* Quadrature scaling only available in quadrature mode */
- if (!priv->quadrature_mode[chan->channel] &&
- (val2 || val != 1)) {
- mutex_unlock(&priv->lock);
- return -EINVAL;
- }
-
- /* Only three gain states (1, 0.5, 0.25) */
- if (val == 1 && !val2)
- priv->quadrature_scale[chan->channel] = 0;
- else if (!val)
- switch (val2) {
- case 500000:
- priv->quadrature_scale[chan->channel] = 1;
- break;
- case 250000:
- priv->quadrature_scale[chan->channel] = 2;
- break;
- default:
- mutex_unlock(&priv->lock);
- return -EINVAL;
- }
- else {
- mutex_unlock(&priv->lock);
- return -EINVAL;
- }
-
- mutex_unlock(&priv->lock);
- return 0;
- }
-
- return -EINVAL;
-}
-
-static const struct iio_info quad8_info = {
- .read_raw = quad8_read_raw,
- .write_raw = quad8_write_raw
-};
-
-static ssize_t quad8_read_preset(struct iio_dev *indio_dev, uintptr_t private,
- const struct iio_chan_spec *chan, char *buf)
-{
- const struct quad8_iio *const priv = iio_priv(indio_dev);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset[chan->channel]);
-}
-
-static ssize_t quad8_write_preset(struct iio_dev *indio_dev, uintptr_t private,
- const struct iio_chan_spec *chan, const char *buf, size_t len)
-{
- struct quad8_iio *const priv = iio_priv(indio_dev);
- const int base_offset = priv->base + 2 * chan->channel;
- unsigned int preset;
- int ret;
- int i;
-
- ret = kstrtouint(buf, 0, &preset);
- if (ret)
- return ret;
-
- /* Only 24-bit values are supported */
- if (preset > 0xFFFFFF)
- return -EINVAL;
-
- mutex_lock(&priv->lock);
-
- priv->preset[chan->channel] = preset;
-
- /* Reset Byte Pointer */
- outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
-
- /* Set Preset Register */
- for (i = 0; i < 3; i++)
- outb(preset >> (8 * i), base_offset);
-
- mutex_unlock(&priv->lock);
-
- return len;
-}
-
-static ssize_t quad8_read_set_to_preset_on_index(struct iio_dev *indio_dev,
- uintptr_t private, const struct iio_chan_spec *chan, char *buf)
-{
- const struct quad8_iio *const priv = iio_priv(indio_dev);
-
- return snprintf(buf, PAGE_SIZE, "%u\n",
- !priv->preset_enable[chan->channel]);
-}
-
-static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev,
- uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
- size_t len)
-{
- struct quad8_iio *const priv = iio_priv(indio_dev);
- const int base_offset = priv->base + 2 * chan->channel + 1;
- bool preset_enable;
- int ret;
- unsigned int ior_cfg;
-
- ret = kstrtobool(buf, &preset_enable);
- if (ret)
- return ret;
-
- /* Preset enable is active low in Input/Output Control register */
- preset_enable = !preset_enable;
-
- mutex_lock(&priv->lock);
-
- priv->preset_enable[chan->channel] = preset_enable;
-
- ior_cfg = priv->ab_enable[chan->channel] |
- (unsigned int)preset_enable << 1;
-
- /* Load I/O control configuration to Input / Output Control Register */
- outb(QUAD8_CTR_IOR | ior_cfg, base_offset);
-
- mutex_unlock(&priv->lock);
-
- return len;
-}
-
-static const char *const quad8_noise_error_states[] = {
- "No excessive noise is present at the count inputs",
- "Excessive noise is present at the count inputs"
-};
-
-static int quad8_get_noise_error(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
-{
- struct quad8_iio *const priv = iio_priv(indio_dev);
- const int base_offset = priv->base + 2 * chan->channel + 1;
-
- return !!(inb(base_offset) & QUAD8_FLAG_E);
-}
-
-static const struct iio_enum quad8_noise_error_enum = {
- .items = quad8_noise_error_states,
- .num_items = ARRAY_SIZE(quad8_noise_error_states),
- .get = quad8_get_noise_error
-};
-
-static const char *const quad8_count_direction_states[] = {
- "down",
- "up"
-};
-
-static int quad8_get_count_direction(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
-{
- struct quad8_iio *const priv = iio_priv(indio_dev);
- const int base_offset = priv->base + 2 * chan->channel + 1;
-
- return !!(inb(base_offset) & QUAD8_FLAG_UD);
-}
-
-static const struct iio_enum quad8_count_direction_enum = {
- .items = quad8_count_direction_states,
- .num_items = ARRAY_SIZE(quad8_count_direction_states),
- .get = quad8_get_count_direction
-};
-
-static const char *const quad8_count_modes[] = {
- "normal",
- "range limit",
- "non-recycle",
- "modulo-n"
-};
-
-static int quad8_set_count_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, unsigned int cnt_mode)
-{
- struct quad8_iio *const priv = iio_priv(indio_dev);
- unsigned int mode_cfg = cnt_mode << 1;
- const int base_offset = priv->base + 2 * chan->channel + 1;
-
- mutex_lock(&priv->lock);
-
- priv->count_mode[chan->channel] = cnt_mode;
-
- /* Add quadrature mode configuration */
- if (priv->quadrature_mode[chan->channel])
- mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3;
-
- /* Load mode configuration to Counter Mode Register */
- outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
-
- mutex_unlock(&priv->lock);
-
- return 0;
-}
-
-static int quad8_get_count_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
-{
- const struct quad8_iio *const priv = iio_priv(indio_dev);
-
- return priv->count_mode[chan->channel];
-}
-
-static const struct iio_enum quad8_count_mode_enum = {
- .items = quad8_count_modes,
- .num_items = ARRAY_SIZE(quad8_count_modes),
- .set = quad8_set_count_mode,
- .get = quad8_get_count_mode
-};
-
-static const char *const quad8_synchronous_modes[] = {
- "non-synchronous",
- "synchronous"
-};
-
-static int quad8_set_synchronous_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, unsigned int synchronous_mode)
-{
- struct quad8_iio *const priv = iio_priv(indio_dev);
- const int base_offset = priv->base + 2 * chan->channel + 1;
- unsigned int idr_cfg = synchronous_mode;
-
- mutex_lock(&priv->lock);
-
- idr_cfg |= priv->index_polarity[chan->channel] << 1;
-
- /* Index function must be non-synchronous in non-quadrature mode */
- if (synchronous_mode && !priv->quadrature_mode[chan->channel]) {
- mutex_unlock(&priv->lock);
- return -EINVAL;
- }
-
- priv->synchronous_mode[chan->channel] = synchronous_mode;
-
- /* Load Index Control configuration to Index Control Register */
- outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
-
- mutex_unlock(&priv->lock);
-
- return 0;
-}
-
-static int quad8_get_synchronous_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
-{
- const struct quad8_iio *const priv = iio_priv(indio_dev);
-
- return priv->synchronous_mode[chan->channel];
-}
-
-static const struct iio_enum quad8_synchronous_mode_enum = {
- .items = quad8_synchronous_modes,
- .num_items = ARRAY_SIZE(quad8_synchronous_modes),
- .set = quad8_set_synchronous_mode,
- .get = quad8_get_synchronous_mode
-};
-
-static const char *const quad8_quadrature_modes[] = {
- "non-quadrature",
- "quadrature"
-};
-
-static int quad8_set_quadrature_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, unsigned int quadrature_mode)
-{
- struct quad8_iio *const priv = iio_priv(indio_dev);
- const int base_offset = priv->base + 2 * chan->channel + 1;
- unsigned int mode_cfg;
-
- mutex_lock(&priv->lock);
-
- mode_cfg = priv->count_mode[chan->channel] << 1;
-
- if (quadrature_mode)
- mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3;
- else {
- /* Quadrature scaling only available in quadrature mode */
- priv->quadrature_scale[chan->channel] = 0;
-
- /* Synchronous function not supported in non-quadrature mode */
- if (priv->synchronous_mode[chan->channel])
- quad8_set_synchronous_mode(indio_dev, chan, 0);
- }
-
- priv->quadrature_mode[chan->channel] = quadrature_mode;
-
- /* Load mode configuration to Counter Mode Register */
- outb(QUAD8_CTR_CMR | mode_cfg, base_offset);
-
- mutex_unlock(&priv->lock);
-
- return 0;
-}
-
-static int quad8_get_quadrature_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
-{
- const struct quad8_iio *const priv = iio_priv(indio_dev);
-
- return priv->quadrature_mode[chan->channel];
-}
-
-static const struct iio_enum quad8_quadrature_mode_enum = {
- .items = quad8_quadrature_modes,
- .num_items = ARRAY_SIZE(quad8_quadrature_modes),
- .set = quad8_set_quadrature_mode,
- .get = quad8_get_quadrature_mode
-};
-
-static const char *const quad8_index_polarity_modes[] = {
- "negative",
- "positive"
-};
-
-static int quad8_set_index_polarity(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, unsigned int index_polarity)
-{
- struct quad8_iio *const priv = iio_priv(indio_dev);
- const int base_offset = priv->base + 2 * chan->channel + 1;
- unsigned int idr_cfg = index_polarity << 1;
-
- mutex_lock(&priv->lock);
-
- idr_cfg |= priv->synchronous_mode[chan->channel];
-
- priv->index_polarity[chan->channel] = index_polarity;
-
- /* Load Index Control configuration to Index Control Register */
- outb(QUAD8_CTR_IDR | idr_cfg, base_offset);
-
- mutex_unlock(&priv->lock);
-
- return 0;
-}
-
-static int quad8_get_index_polarity(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
-{
- const struct quad8_iio *const priv = iio_priv(indio_dev);
-
- return priv->index_polarity[chan->channel];
-}
-
-static const struct iio_enum quad8_index_polarity_enum = {
- .items = quad8_index_polarity_modes,
- .num_items = ARRAY_SIZE(quad8_index_polarity_modes),
- .set = quad8_set_index_polarity,
- .get = quad8_get_index_polarity
-};
-
-static const struct iio_chan_spec_ext_info quad8_count_ext_info[] = {
- {
- .name = "preset",
- .shared = IIO_SEPARATE,
- .read = quad8_read_preset,
- .write = quad8_write_preset
- },
- {
- .name = "set_to_preset_on_index",
- .shared = IIO_SEPARATE,
- .read = quad8_read_set_to_preset_on_index,
- .write = quad8_write_set_to_preset_on_index
- },
- IIO_ENUM("noise_error", IIO_SEPARATE, &quad8_noise_error_enum),
- IIO_ENUM_AVAILABLE("noise_error", &quad8_noise_error_enum),
- IIO_ENUM("count_direction", IIO_SEPARATE, &quad8_count_direction_enum),
- IIO_ENUM_AVAILABLE("count_direction", &quad8_count_direction_enum),
- IIO_ENUM("count_mode", IIO_SEPARATE, &quad8_count_mode_enum),
- IIO_ENUM_AVAILABLE("count_mode", &quad8_count_mode_enum),
- IIO_ENUM("quadrature_mode", IIO_SEPARATE, &quad8_quadrature_mode_enum),
- IIO_ENUM_AVAILABLE("quadrature_mode", &quad8_quadrature_mode_enum),
- {}
-};
-
-static const struct iio_chan_spec_ext_info quad8_index_ext_info[] = {
- IIO_ENUM("synchronous_mode", IIO_SEPARATE,
- &quad8_synchronous_mode_enum),
- IIO_ENUM_AVAILABLE("synchronous_mode", &quad8_synchronous_mode_enum),
- IIO_ENUM("index_polarity", IIO_SEPARATE, &quad8_index_polarity_enum),
- IIO_ENUM_AVAILABLE("index_polarity", &quad8_index_polarity_enum),
- {}
-};
-
-#define QUAD8_COUNT_CHAN(_chan) { \
- .type = IIO_COUNT, \
- .channel = (_chan), \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), \
- .ext_info = quad8_count_ext_info, \
- .indexed = 1 \
-}
-
-#define QUAD8_INDEX_CHAN(_chan) { \
- .type = IIO_INDEX, \
- .channel = (_chan), \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .ext_info = quad8_index_ext_info, \
- .indexed = 1 \
-}
-
-static const struct iio_chan_spec quad8_channels[] = {
- QUAD8_COUNT_CHAN(0), QUAD8_INDEX_CHAN(0),
- QUAD8_COUNT_CHAN(1), QUAD8_INDEX_CHAN(1),
- QUAD8_COUNT_CHAN(2), QUAD8_INDEX_CHAN(2),
- QUAD8_COUNT_CHAN(3), QUAD8_INDEX_CHAN(3),
- QUAD8_COUNT_CHAN(4), QUAD8_INDEX_CHAN(4),
- QUAD8_COUNT_CHAN(5), QUAD8_INDEX_CHAN(5),
- QUAD8_COUNT_CHAN(6), QUAD8_INDEX_CHAN(6),
- QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7)
-};
-
static int quad8_signal_read(struct counter_device *counter,
struct counter_signal *signal, enum counter_signal_value *val)
{
- const struct quad8_iio *const priv = counter->priv;
+ const struct quad8 *const priv = counter->priv;
unsigned int state;
/* Only Index signal levels can be read */
@@ -641,7 +117,7 @@ static int quad8_signal_read(struct counter_device *counter,
static int quad8_count_read(struct counter_device *counter,
struct counter_count *count, unsigned long *val)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
const int base_offset = priv->base + 2 * count->id;
unsigned int flags;
unsigned int borrow;
@@ -672,7 +148,7 @@ static int quad8_count_read(struct counter_device *counter,
static int quad8_count_write(struct counter_device *counter,
struct counter_count *count, unsigned long val)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
const int base_offset = priv->base + 2 * count->id;
int i;
@@ -727,7 +203,7 @@ static enum counter_count_function quad8_count_functions_list[] = {
static int quad8_function_get(struct counter_device *counter,
struct counter_count *count, size_t *function)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
const int id = count->id;
mutex_lock(&priv->lock);
@@ -755,7 +231,7 @@ static int quad8_function_get(struct counter_device *counter,
static int quad8_function_set(struct counter_device *counter,
struct counter_count *count, size_t function)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
const int id = count->id;
unsigned int *const quadrature_mode = priv->quadrature_mode + id;
unsigned int *const scale = priv->quadrature_scale + id;
@@ -811,7 +287,7 @@ static int quad8_function_set(struct counter_device *counter,
static void quad8_direction_get(struct counter_device *counter,
struct counter_count *count, enum counter_count_direction *direction)
{
- const struct quad8_iio *const priv = counter->priv;
+ const struct quad8 *const priv = counter->priv;
unsigned int ud_flag;
const unsigned int flag_addr = priv->base + 2 * count->id + 1;
@@ -845,7 +321,7 @@ static int quad8_action_get(struct counter_device *counter,
struct counter_count *count, struct counter_synapse *synapse,
size_t *action)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
int err;
size_t function = 0;
const size_t signal_a_id = count->synapses[0].signal->id;
@@ -905,10 +381,15 @@ static const struct counter_ops quad8_ops = {
.action_get = quad8_action_get
};
+static const char *const quad8_index_polarity_modes[] = {
+ "negative",
+ "positive"
+};
+
static int quad8_index_polarity_get(struct counter_device *counter,
struct counter_signal *signal, size_t *index_polarity)
{
- const struct quad8_iio *const priv = counter->priv;
+ const struct quad8 *const priv = counter->priv;
const size_t channel_id = signal->id - 16;
*index_polarity = priv->index_polarity[channel_id];
@@ -919,7 +400,7 @@ static int quad8_index_polarity_get(struct counter_device *counter,
static int quad8_index_polarity_set(struct counter_device *counter,
struct counter_signal *signal, size_t index_polarity)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
const size_t channel_id = signal->id - 16;
const int base_offset = priv->base + 2 * channel_id + 1;
unsigned int idr_cfg = index_polarity << 1;
@@ -945,10 +426,15 @@ static struct counter_signal_enum_ext quad8_index_pol_enum = {
.set = quad8_index_polarity_set
};
+static const char *const quad8_synchronous_modes[] = {
+ "non-synchronous",
+ "synchronous"
+};
+
static int quad8_synchronous_mode_get(struct counter_device *counter,
struct counter_signal *signal, size_t *synchronous_mode)
{
- const struct quad8_iio *const priv = counter->priv;
+ const struct quad8 *const priv = counter->priv;
const size_t channel_id = signal->id - 16;
*synchronous_mode = priv->synchronous_mode[channel_id];
@@ -959,7 +445,7 @@ static int quad8_synchronous_mode_get(struct counter_device *counter,
static int quad8_synchronous_mode_set(struct counter_device *counter,
struct counter_signal *signal, size_t synchronous_mode)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
const size_t channel_id = signal->id - 16;
const int base_offset = priv->base + 2 * channel_id + 1;
unsigned int idr_cfg = synchronous_mode;
@@ -1001,7 +487,7 @@ static ssize_t quad8_count_floor_read(struct counter_device *counter,
static int quad8_count_mode_get(struct counter_device *counter,
struct counter_count *count, size_t *cnt_mode)
{
- const struct quad8_iio *const priv = counter->priv;
+ const struct quad8 *const priv = counter->priv;
/* Map 104-QUAD-8 count mode to Generic Counter count mode */
switch (priv->count_mode[count->id]) {
@@ -1025,7 +511,7 @@ static int quad8_count_mode_get(struct counter_device *counter,
static int quad8_count_mode_set(struct counter_device *counter,
struct counter_count *count, size_t cnt_mode)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
unsigned int mode_cfg;
const int base_offset = priv->base + 2 * count->id + 1;
@@ -1084,7 +570,7 @@ static ssize_t quad8_count_direction_read(struct counter_device *counter,
static ssize_t quad8_count_enable_read(struct counter_device *counter,
struct counter_count *count, void *private, char *buf)
{
- const struct quad8_iio *const priv = counter->priv;
+ const struct quad8 *const priv = counter->priv;
return sprintf(buf, "%u\n", priv->ab_enable[count->id]);
}
@@ -1092,7 +578,7 @@ static ssize_t quad8_count_enable_read(struct counter_device *counter,
static ssize_t quad8_count_enable_write(struct counter_device *counter,
struct counter_count *count, void *private, const char *buf, size_t len)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
const int base_offset = priv->base + 2 * count->id;
int err;
bool ab_enable;
@@ -1116,10 +602,15 @@ static ssize_t quad8_count_enable_write(struct counter_device *counter,
return len;
}
+static const char *const quad8_noise_error_states[] = {
+ "No excessive noise is present at the count inputs",
+ "Excessive noise is present at the count inputs"
+};
+
static int quad8_error_noise_get(struct counter_device *counter,
struct counter_count *count, size_t *noise_error)
{
- const struct quad8_iio *const priv = counter->priv;
+ const struct quad8 *const priv = counter->priv;
const int base_offset = priv->base + 2 * count->id + 1;
*noise_error = !!(inb(base_offset) & QUAD8_FLAG_E);
@@ -1136,18 +627,18 @@ static struct counter_count_enum_ext quad8_error_noise_enum = {
static ssize_t quad8_count_preset_read(struct counter_device *counter,
struct counter_count *count, void *private, char *buf)
{
- const struct quad8_iio *const priv = counter->priv;
+ const struct quad8 *const priv = counter->priv;
return sprintf(buf, "%u\n", priv->preset[count->id]);
}
-static void quad8_preset_register_set(struct quad8_iio *quad8iio, int id,
- unsigned int preset)
+static void quad8_preset_register_set(struct quad8 *priv, int id,
+ unsigned int preset)
{
- const unsigned int base_offset = quad8iio->base + 2 * id;
+ const unsigned int base_offset = priv->base + 2 * id;
int i;
- quad8iio->preset[id] = preset;
+ priv->preset[id] = preset;
/* Reset Byte Pointer */
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
@@ -1160,7 +651,7 @@ static void quad8_preset_register_set(struct quad8_iio *quad8iio, int id,
static ssize_t quad8_count_preset_write(struct counter_device *counter,
struct counter_count *count, void *private, const char *buf, size_t len)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
unsigned int preset;
int ret;
@@ -1184,7 +675,7 @@ static ssize_t quad8_count_preset_write(struct counter_device *counter,
static ssize_t quad8_count_ceiling_read(struct counter_device *counter,
struct counter_count *count, void *private, char *buf)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
mutex_lock(&priv->lock);
@@ -1205,7 +696,7 @@ static ssize_t quad8_count_ceiling_read(struct counter_device *counter,
static ssize_t quad8_count_ceiling_write(struct counter_device *counter,
struct counter_count *count, void *private, const char *buf, size_t len)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
unsigned int ceiling;
int ret;
@@ -1235,7 +726,7 @@ static ssize_t quad8_count_ceiling_write(struct counter_device *counter,
static ssize_t quad8_count_preset_enable_read(struct counter_device *counter,
struct counter_count *count, void *private, char *buf)
{
- const struct quad8_iio *const priv = counter->priv;
+ const struct quad8 *const priv = counter->priv;
return sprintf(buf, "%u\n", !priv->preset_enable[count->id]);
}
@@ -1243,7 +734,7 @@ static ssize_t quad8_count_preset_enable_read(struct counter_device *counter,
static ssize_t quad8_count_preset_enable_write(struct counter_device *counter,
struct counter_count *count, void *private, const char *buf, size_t len)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
const int base_offset = priv->base + 2 * count->id + 1;
bool preset_enable;
int ret;
@@ -1274,7 +765,7 @@ static ssize_t quad8_signal_cable_fault_read(struct counter_device *counter,
struct counter_signal *signal,
void *private, char *buf)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
const size_t channel_id = signal->id / 2;
bool disabled;
unsigned int status;
@@ -1304,7 +795,7 @@ static ssize_t quad8_signal_cable_fault_enable_read(
struct counter_device *counter, struct counter_signal *signal,
void *private, char *buf)
{
- const struct quad8_iio *const priv = counter->priv;
+ const struct quad8 *const priv = counter->priv;
const size_t channel_id = signal->id / 2;
const unsigned int enb = !!(priv->cable_fault_enable & BIT(channel_id));
@@ -1315,7 +806,7 @@ static ssize_t quad8_signal_cable_fault_enable_write(
struct counter_device *counter, struct counter_signal *signal,
void *private, const char *buf, size_t len)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
const size_t channel_id = signal->id / 2;
bool enable;
int ret;
@@ -1345,7 +836,7 @@ static ssize_t quad8_signal_cable_fault_enable_write(
static ssize_t quad8_signal_fck_prescaler_read(struct counter_device *counter,
struct counter_signal *signal, void *private, char *buf)
{
- const struct quad8_iio *const priv = counter->priv;
+ const struct quad8 *const priv = counter->priv;
const size_t channel_id = signal->id / 2;
return sprintf(buf, "%u\n", priv->fck_prescaler[channel_id]);
@@ -1355,7 +846,7 @@ static ssize_t quad8_signal_fck_prescaler_write(struct counter_device *counter,
struct counter_signal *signal, void *private, const char *buf,
size_t len)
{
- struct quad8_iio *const priv = counter->priv;
+ struct quad8 *const priv = counter->priv;
const size_t channel_id = signal->id / 2;
const int base_offset = priv->base + 2 * channel_id;
u8 prescaler;
@@ -1531,11 +1022,9 @@ static struct counter_count quad8_counts[] = {
static int quad8_probe(struct device *dev, unsigned int id)
{
- struct iio_dev *indio_dev;
- struct quad8_iio *quad8iio;
+ struct quad8 *priv;
int i, j;
unsigned int base_offset;
- int err;
if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
@@ -1543,32 +1032,23 @@ static int quad8_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
- /* Allocate IIO device; this also allocates driver data structure */
- indio_dev = devm_iio_device_alloc(dev, sizeof(*quad8iio));
- if (!indio_dev)
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- /* Initialize IIO device */
- indio_dev->info = &quad8_info;
- indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->num_channels = ARRAY_SIZE(quad8_channels);
- indio_dev->channels = quad8_channels;
- indio_dev->name = dev_name(dev);
-
/* Initialize Counter device and driver data */
- quad8iio = iio_priv(indio_dev);
- quad8iio->counter.name = dev_name(dev);
- quad8iio->counter.parent = dev;
- quad8iio->counter.ops = &quad8_ops;
- quad8iio->counter.counts = quad8_counts;
- quad8iio->counter.num_counts = ARRAY_SIZE(quad8_counts);
- quad8iio->counter.signals = quad8_signals;
- quad8iio->counter.num_signals = ARRAY_SIZE(quad8_signals);
- quad8iio->counter.priv = quad8iio;
- quad8iio->base = base[id];
+ priv->counter.name = dev_name(dev);
+ priv->counter.parent = dev;
+ priv->counter.ops = &quad8_ops;
+ priv->counter.counts = quad8_counts;
+ priv->counter.num_counts = ARRAY_SIZE(quad8_counts);
+ priv->counter.signals = quad8_signals;
+ priv->counter.num_signals = ARRAY_SIZE(quad8_signals);
+ priv->counter.priv = priv;
+ priv->base = base[id];
/* Initialize mutex */
- mutex_init(&quad8iio->lock);
+ mutex_init(&priv->lock);
/* Reset all counters and disable interrupt function */
outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
@@ -1602,13 +1082,8 @@ static int quad8_probe(struct device *dev, unsigned int id)
/* Enable all counters */
outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
- /* Register IIO device */
- err = devm_iio_device_register(dev, indio_dev);
- if (err)
- return err;
-
/* Register Counter device */
- return devm_counter_register(dev, &quad8iio->counter);
+ return devm_counter_register(dev, &priv->counter);
}
static struct isa_driver quad8_driver = {
@@ -1621,5 +1096,5 @@ static struct isa_driver quad8_driver = {
module_isa_driver(quad8_driver, num_quad8);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
-MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver");
+MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
index 2de53ab0dd25..5328705aa09c 100644
--- a/drivers/counter/Kconfig
+++ b/drivers/counter/Kconfig
@@ -14,7 +14,7 @@ if COUNTER
config 104_QUAD_8
tristate "ACCES 104-QUAD-8 driver"
- depends on PC104 && X86 && IIO
+ depends on PC104 && X86
select ISA_BUS_API
help
Say yes here to build support for the ACCES 104-QUAD-8 quadrature
@@ -29,6 +29,16 @@ config 104_QUAD_8
The base port addresses for the devices may be configured via the base
array module parameter.
+config INTERRUPT_CNT
+ tristate "Interrupt counter driver"
+ depends on GPIOLIB
+ help
+ Select this option to enable interrupt counter driver. Any interrupt
+ source can be used by this driver as the event source.
+
+ To compile this driver as a module, choose M here: the
+ module will be called interrupt-cnt.
+
config STM32_TIMER_CNT
tristate "STM32 Timer encoder counter driver"
depends on MFD_STM32_TIMERS || COMPILE_TEST
@@ -41,7 +51,7 @@ config STM32_TIMER_CNT
config STM32_LPTIMER_CNT
tristate "STM32 LP Timer encoder counter driver"
- depends on (MFD_STM32_LPTIMER || COMPILE_TEST) && IIO
+ depends on MFD_STM32_LPTIMER || COMPILE_TEST
help
Select this option to enable STM32 Low-Power Timer quadrature encoder
and counter driver.
diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
index 0a393f71e481..cb646ed2f039 100644
--- a/drivers/counter/Makefile
+++ b/drivers/counter/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_COUNTER) += counter.o
obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o
+obj-$(CONFIG_INTERRUPT_CNT) += interrupt-cnt.o
obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o
obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o
obj-$(CONFIG_TI_EQEP) += ti-eqep.o
diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c
new file mode 100644
index 000000000000..a99ee7996977
--- /dev/null
+++ b/drivers/counter/interrupt-cnt.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
+ */
+
+#include <linux/counter.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define INTERRUPT_CNT_NAME "interrupt-cnt"
+
+struct interrupt_cnt_priv {
+ atomic_t count;
+ struct counter_device counter;
+ struct gpio_desc *gpio;
+ int irq;
+ bool enabled;
+ struct counter_signal signals;
+ struct counter_synapse synapses;
+ struct counter_count cnts;
+};
+
+static irqreturn_t interrupt_cnt_isr(int irq, void *dev_id)
+{
+ struct interrupt_cnt_priv *priv = dev_id;
+
+ atomic_inc(&priv->count);
+
+ return IRQ_HANDLED;
+}
+
+static ssize_t interrupt_cnt_enable_read(struct counter_device *counter,
+ struct counter_count *count,
+ void *private, char *buf)
+{
+ struct interrupt_cnt_priv *priv = counter->priv;
+
+ return sysfs_emit(buf, "%d\n", priv->enabled);
+}
+
+static ssize_t interrupt_cnt_enable_write(struct counter_device *counter,
+ struct counter_count *count,
+ void *private, const char *buf,
+ size_t len)
+{
+ struct interrupt_cnt_priv *priv = counter->priv;
+ bool enable;
+ ssize_t ret;
+
+ ret = kstrtobool(buf, &enable);
+ if (ret)
+ return ret;
+
+ if (priv->enabled == enable)
+ return len;
+
+ if (enable) {
+ priv->enabled = true;
+ enable_irq(priv->irq);
+ } else {
+ disable_irq(priv->irq);
+ priv->enabled = false;
+ }
+
+ return len;
+}
+
+static const struct counter_count_ext interrupt_cnt_ext[] = {
+ {
+ .name = "enable",
+ .read = interrupt_cnt_enable_read,
+ .write = interrupt_cnt_enable_write,
+ },
+};
+
+static enum counter_synapse_action interrupt_cnt_synapse_actionss[] = {
+ COUNTER_SYNAPSE_ACTION_RISING_EDGE,
+};
+
+static int interrupt_cnt_action_get(struct counter_device *counter,
+ struct counter_count *count,
+ struct counter_synapse *synapse,
+ size_t *action)
+{
+ *action = 0;
+
+ return 0;
+}
+
+static int interrupt_cnt_read(struct counter_device *counter,
+ struct counter_count *count, unsigned long *val)
+{
+ struct interrupt_cnt_priv *priv = counter->priv;
+
+ *val = atomic_read(&priv->count);
+
+ return 0;
+}
+
+static int interrupt_cnt_write(struct counter_device *counter,
+ struct counter_count *count,
+ const unsigned long val)
+{
+ struct interrupt_cnt_priv *priv = counter->priv;
+
+ atomic_set(&priv->count, val);
+
+ return 0;
+}
+
+static enum counter_count_function interrupt_cnt_functions[] = {
+ COUNTER_COUNT_FUNCTION_INCREASE,
+};
+
+static int interrupt_cnt_function_get(struct counter_device *counter,
+ struct counter_count *count,
+ size_t *function)
+{
+ *function = 0;
+
+ return 0;
+}
+
+static int interrupt_cnt_signal_read(struct counter_device *counter,
+ struct counter_signal *signal,
+ enum counter_signal_value *val)
+{
+ struct interrupt_cnt_priv *priv = counter->priv;
+ int ret;
+
+ if (!priv->gpio)
+ return -EINVAL;
+
+ ret = gpiod_get_value(priv->gpio);
+ if (ret < 0)
+ return ret;
+
+ *val = ret ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
+
+ return 0;
+}
+
+static const struct counter_ops interrupt_cnt_ops = {
+ .action_get = interrupt_cnt_action_get,
+ .count_read = interrupt_cnt_read,
+ .count_write = interrupt_cnt_write,
+ .function_get = interrupt_cnt_function_get,
+ .signal_read = interrupt_cnt_signal_read,
+};
+
+static int interrupt_cnt_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct interrupt_cnt_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->irq = platform_get_irq_optional(pdev, 0);
+ if (priv->irq == -ENXIO)
+ priv->irq = 0;
+ else if (priv->irq < 0)
+ return dev_err_probe(dev, priv->irq, "failed to get IRQ\n");
+
+ priv->gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_IN);
+ if (IS_ERR(priv->gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->gpio), "failed to get GPIO\n");
+
+ if (!priv->irq && !priv->gpio) {
+ dev_err(dev, "IRQ and GPIO are not found. At least one source should be provided\n");
+ return -ENODEV;
+ }
+
+ if (!priv->irq) {
+ int irq = gpiod_to_irq(priv->gpio);
+
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "failed to get IRQ from GPIO\n");
+
+ priv->irq = irq;
+ }
+
+ priv->signals.name = devm_kasprintf(dev, GFP_KERNEL, "IRQ %d",
+ priv->irq);
+ if (!priv->signals.name)
+ return -ENOMEM;
+
+ priv->counter.signals = &priv->signals;
+ priv->counter.num_signals = 1;
+
+ priv->synapses.actions_list = interrupt_cnt_synapse_actionss;
+ priv->synapses.num_actions = ARRAY_SIZE(interrupt_cnt_synapse_actionss);
+ priv->synapses.signal = &priv->signals;
+
+ priv->cnts.name = "Channel 0 Count";
+ priv->cnts.functions_list = interrupt_cnt_functions;
+ priv->cnts.num_functions = ARRAY_SIZE(interrupt_cnt_functions);
+ priv->cnts.synapses = &priv->synapses;
+ priv->cnts.num_synapses = 1;
+ priv->cnts.ext = interrupt_cnt_ext;
+ priv->cnts.num_ext = ARRAY_SIZE(interrupt_cnt_ext);
+
+ priv->counter.priv = priv;
+ priv->counter.name = dev_name(dev);
+ priv->counter.parent = dev;
+ priv->counter.ops = &interrupt_cnt_ops;
+ priv->counter.counts = &priv->cnts;
+ priv->counter.num_counts = 1;
+
+ irq_set_status_flags(priv->irq, IRQ_NOAUTOEN);
+ ret = devm_request_irq(dev, priv->irq, interrupt_cnt_isr,
+ IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
+ dev_name(dev), priv);
+ if (ret)
+ return ret;
+
+ return devm_counter_register(dev, &priv->counter);
+}
+
+static const struct of_device_id interrupt_cnt_of_match[] = {
+ { .compatible = "interrupt-counter", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, interrupt_cnt_of_match);
+
+static struct platform_driver interrupt_cnt_driver = {
+ .probe = interrupt_cnt_probe,
+ .driver = {
+ .name = INTERRUPT_CNT_NAME,
+ .of_match_table = interrupt_cnt_of_match,
+ },
+};
+module_platform_driver(interrupt_cnt_driver);
+
+MODULE_ALIAS("platform:interrupt-counter");
+MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
+MODULE_DESCRIPTION("Interrupt counter driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c
index fd6828e2d34f..937439635d53 100644
--- a/drivers/counter/stm32-lptimer-cnt.c
+++ b/drivers/counter/stm32-lptimer-cnt.c
@@ -12,8 +12,8 @@
#include <linux/bitfield.h>
#include <linux/counter.h>
-#include <linux/iio/iio.h>
#include <linux/mfd/stm32-lptimer.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -107,249 +107,27 @@ static int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable)
return regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, val);
}
-static int stm32_lptim_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
-{
- struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
- int ret;
-
- switch (mask) {
- case IIO_CHAN_INFO_ENABLE:
- if (val < 0 || val > 1)
- return -EINVAL;
-
- /* Check nobody uses the timer, or already disabled/enabled */
- ret = stm32_lptim_is_enabled(priv);
- if ((ret < 0) || (!ret && !val))
- return ret;
- if (val && ret)
- return -EBUSY;
-
- ret = stm32_lptim_setup(priv, val);
- if (ret)
- return ret;
- return stm32_lptim_set_enable_state(priv, val);
-
- default:
- return -EINVAL;
- }
-}
-
-static int stm32_lptim_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2, long mask)
-{
- struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
- u32 dat;
- int ret;
-
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- ret = regmap_read(priv->regmap, STM32_LPTIM_CNT, &dat);
- if (ret)
- return ret;
- *val = dat;
- return IIO_VAL_INT;
-
- case IIO_CHAN_INFO_ENABLE:
- ret = stm32_lptim_is_enabled(priv);
- if (ret < 0)
- return ret;
- *val = ret;
- return IIO_VAL_INT;
-
- case IIO_CHAN_INFO_SCALE:
- /* Non-quadrature mode: scale = 1 */
- *val = 1;
- *val2 = 0;
- if (priv->quadrature_mode) {
- /*
- * Quadrature encoder mode:
- * - both edges, quarter cycle, scale is 0.25
- * - either rising/falling edge scale is 0.5
- */
- if (priv->polarity > 1)
- *val2 = 2;
- else
- *val2 = 1;
- }
- return IIO_VAL_FRACTIONAL_LOG2;
-
- default:
- return -EINVAL;
- }
-}
-
-static const struct iio_info stm32_lptim_cnt_iio_info = {
- .read_raw = stm32_lptim_read_raw,
- .write_raw = stm32_lptim_write_raw,
-};
-
-static const char *const stm32_lptim_quadrature_modes[] = {
- "non-quadrature",
- "quadrature",
-};
-
-static int stm32_lptim_get_quadrature_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
-{
- struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
-
- return priv->quadrature_mode;
-}
-
-static int stm32_lptim_set_quadrature_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan,
- unsigned int type)
-{
- struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
-
- if (stm32_lptim_is_enabled(priv))
- return -EBUSY;
-
- priv->quadrature_mode = type;
-
- return 0;
-}
-
-static const struct iio_enum stm32_lptim_quadrature_mode_en = {
- .items = stm32_lptim_quadrature_modes,
- .num_items = ARRAY_SIZE(stm32_lptim_quadrature_modes),
- .get = stm32_lptim_get_quadrature_mode,
- .set = stm32_lptim_set_quadrature_mode,
-};
-
-static const char * const stm32_lptim_cnt_polarity[] = {
- "rising-edge", "falling-edge", "both-edges",
-};
-
-static int stm32_lptim_cnt_get_polarity(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
-{
- struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
-
- return priv->polarity;
-}
-
-static int stm32_lptim_cnt_set_polarity(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan,
- unsigned int type)
-{
- struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
-
- if (stm32_lptim_is_enabled(priv))
- return -EBUSY;
-
- priv->polarity = type;
-
- return 0;
-}
-
-static const struct iio_enum stm32_lptim_cnt_polarity_en = {
- .items = stm32_lptim_cnt_polarity,
- .num_items = ARRAY_SIZE(stm32_lptim_cnt_polarity),
- .get = stm32_lptim_cnt_get_polarity,
- .set = stm32_lptim_cnt_set_polarity,
-};
-
-static ssize_t stm32_lptim_cnt_get_ceiling(struct stm32_lptim_cnt *priv,
- char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", priv->ceiling);
-}
-
-static ssize_t stm32_lptim_cnt_set_ceiling(struct stm32_lptim_cnt *priv,
- const char *buf, size_t len)
-{
- int ret;
-
- if (stm32_lptim_is_enabled(priv))
- return -EBUSY;
-
- ret = kstrtouint(buf, 0, &priv->ceiling);
- if (ret)
- return ret;
-
- if (priv->ceiling > STM32_LPTIM_MAX_ARR)
- return -EINVAL;
-
- return len;
-}
-
-static ssize_t stm32_lptim_cnt_get_preset_iio(struct iio_dev *indio_dev,
- uintptr_t private,
- const struct iio_chan_spec *chan,
- char *buf)
-{
- struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
-
- return stm32_lptim_cnt_get_ceiling(priv, buf);
-}
-
-static ssize_t stm32_lptim_cnt_set_preset_iio(struct iio_dev *indio_dev,
- uintptr_t private,
- const struct iio_chan_spec *chan,
- const char *buf, size_t len)
-{
- struct stm32_lptim_cnt *priv = iio_priv(indio_dev);
-
- return stm32_lptim_cnt_set_ceiling(priv, buf, len);
-}
-
-/* LP timer with encoder */
-static const struct iio_chan_spec_ext_info stm32_lptim_enc_ext_info[] = {
- {
- .name = "preset",
- .shared = IIO_SEPARATE,
- .read = stm32_lptim_cnt_get_preset_iio,
- .write = stm32_lptim_cnt_set_preset_iio,
- },
- IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en),
- IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en),
- IIO_ENUM("quadrature_mode", IIO_SEPARATE,
- &stm32_lptim_quadrature_mode_en),
- IIO_ENUM_AVAILABLE("quadrature_mode", &stm32_lptim_quadrature_mode_en),
- {}
-};
-
-static const struct iio_chan_spec stm32_lptim_enc_channels = {
- .type = IIO_COUNT,
- .channel = 0,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_ENABLE) |
- BIT(IIO_CHAN_INFO_SCALE),
- .ext_info = stm32_lptim_enc_ext_info,
- .indexed = 1,
-};
-
-/* LP timer without encoder (counter only) */
-static const struct iio_chan_spec_ext_info stm32_lptim_cnt_ext_info[] = {
- {
- .name = "preset",
- .shared = IIO_SEPARATE,
- .read = stm32_lptim_cnt_get_preset_iio,
- .write = stm32_lptim_cnt_set_preset_iio,
- },
- IIO_ENUM("polarity", IIO_SEPARATE, &stm32_lptim_cnt_polarity_en),
- IIO_ENUM_AVAILABLE("polarity", &stm32_lptim_cnt_polarity_en),
- {}
-};
-
-static const struct iio_chan_spec stm32_lptim_cnt_channels = {
- .type = IIO_COUNT,
- .channel = 0,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_ENABLE) |
- BIT(IIO_CHAN_INFO_SCALE),
- .ext_info = stm32_lptim_cnt_ext_info,
- .indexed = 1,
-};
-
/**
* enum stm32_lptim_cnt_function - enumerates LPTimer counter & encoder modes
* @STM32_LPTIM_COUNTER_INCREASE: up count on IN1 rising, falling or both edges
* @STM32_LPTIM_ENCODER_BOTH_EDGE: count on both edges (IN1 & IN2 quadrature)
+ *
+ * In non-quadrature mode, device counts up on active edge.
+ * In quadrature mode, encoder counting scenarios are as follows:
+ * +---------+----------+--------------------+--------------------+
+ * | Active | Level on | IN1 signal | IN2 signal |
+ * | edge | opposite +----------+---------+----------+---------+
+ * | | signal | Rising | Falling | Rising | Falling |
+ * +---------+----------+----------+---------+----------+---------+
+ * | Rising | High -> | Down | - | Up | - |
+ * | edge | Low -> | Up | - | Down | - |
+ * +---------+----------+----------+---------+----------+---------+
+ * | Falling | High -> | - | Up | - | Down |
+ * | edge | Low -> | - | Down | - | Up |
+ * +---------+----------+----------+---------+----------+---------+
+ * | Both | High -> | Down | Up | Up | Down |
+ * | edges | Low -> | Up | Down | Down | Up |
+ * +---------+----------+----------+---------+----------+---------+
*/
enum stm32_lptim_cnt_function {
STM32_LPTIM_COUNTER_INCREASE,
@@ -484,7 +262,7 @@ static ssize_t stm32_lptim_cnt_ceiling_read(struct counter_device *counter,
{
struct stm32_lptim_cnt *const priv = counter->priv;
- return stm32_lptim_cnt_get_ceiling(priv, buf);
+ return snprintf(buf, PAGE_SIZE, "%u\n", priv->ceiling);
}
static ssize_t stm32_lptim_cnt_ceiling_write(struct counter_device *counter,
@@ -493,8 +271,22 @@ static ssize_t stm32_lptim_cnt_ceiling_write(struct counter_device *counter,
const char *buf, size_t len)
{
struct stm32_lptim_cnt *const priv = counter->priv;
+ unsigned int ceiling;
+ int ret;
+
+ if (stm32_lptim_is_enabled(priv))
+ return -EBUSY;
+
+ ret = kstrtouint(buf, 0, &ceiling);
+ if (ret)
+ return ret;
+
+ if (ceiling > STM32_LPTIM_MAX_ARR)
+ return -EINVAL;
+
+ priv->ceiling = ceiling;
- return stm32_lptim_cnt_set_ceiling(priv, buf, len);
+ return len;
}
static const struct counter_count_ext stm32_lptim_cnt_ext[] = {
@@ -630,32 +422,19 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev)
{
struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);
struct stm32_lptim_cnt *priv;
- struct iio_dev *indio_dev;
- int ret;
if (IS_ERR_OR_NULL(ddata))
return -EINVAL;
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
- if (!indio_dev)
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- priv = iio_priv(indio_dev);
priv->dev = &pdev->dev;
priv->regmap = ddata->regmap;
priv->clk = ddata->clk;
priv->ceiling = STM32_LPTIM_MAX_ARR;
- /* Initialize IIO device */
- indio_dev->name = dev_name(&pdev->dev);
- indio_dev->dev.of_node = pdev->dev.of_node;
- indio_dev->info = &stm32_lptim_cnt_iio_info;
- if (ddata->has_encoder)
- indio_dev->channels = &stm32_lptim_enc_channels;
- else
- indio_dev->channels = &stm32_lptim_cnt_channels;
- indio_dev->num_channels = 1;
-
/* Initialize Counter device */
priv->counter.name = dev_name(&pdev->dev);
priv->counter.parent = &pdev->dev;
@@ -673,10 +452,6 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
- ret = devm_iio_device_register(&pdev->dev, indio_dev);
- if (ret)
- return ret;
-
return devm_counter_register(&pdev->dev, &priv->counter);
}
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index cacdf1589b10..3e748e57deab 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -741,7 +741,7 @@ static struct scmi_prot_devnames devnames[] = {
{ SCMI_PROTOCOL_SYSTEM, { "syspower" },},
{ SCMI_PROTOCOL_PERF, { "cpufreq" },},
{ SCMI_PROTOCOL_CLOCK, { "clocks" },},
- { SCMI_PROTOCOL_SENSOR, { "hwmon" },},
+ { SCMI_PROTOCOL_SENSOR, { "hwmon", "iiodev" },},
{ SCMI_PROTOCOL_RESET, { "reset" },},
{ SCMI_PROTOCOL_VOLTAGE, { "regulator" },},
};
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index 3aad62a0e661..8587189c7f15 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -326,18 +326,27 @@ struct ntc_data {
static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
{
struct iio_channel *channel = pdata->chan;
- int raw, uv, ret;
+ int uv, ret;
- ret = iio_read_channel_raw(channel, &raw);
+ ret = iio_read_channel_processed_scale(channel, &uv, 1000);
if (ret < 0) {
- pr_err("read channel() error: %d\n", ret);
- return ret;
- }
+ int raw;
- ret = iio_convert_raw_to_processed(channel, raw, &uv, 1000);
- if (ret < 0) {
- /* Assume 12 bit ADC with vref at pullup_uv */
- uv = (pdata->pullup_uv * (s64)raw) >> 12;
+ /*
+ * This fallback uses a raw read and then
+ * assumes the ADC is 12 bits, scaling with
+ * a factor 1000 to get to microvolts.
+ */
+ ret = iio_read_channel_raw(channel, &raw);
+ if (ret < 0) {
+ pr_err("read channel() error: %d\n", ret);
+ return ret;
+ }
+ ret = iio_convert_raw_to_processed(channel, raw, &uv, 1000);
+ if (ret < 0) {
+ /* Assume 12 bit ADC with vref at pullup_uv */
+ uv = (pdata->pullup_uv * (s64)raw) >> 12;
+ }
}
return uv;
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 267553386c71..b35e0c33b5e2 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -85,6 +85,7 @@ source "drivers/iio/light/Kconfig"
source "drivers/iio/magnetometer/Kconfig"
source "drivers/iio/multiplexer/Kconfig"
source "drivers/iio/orientation/Kconfig"
+source "drivers/iio/test/Kconfig"
if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
endif #IIO_TRIGGER
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 1712011c0f4a..2561325aaa74 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -38,4 +38,5 @@ obj-y += pressure/
obj-y += proximity/
obj-y += resolver/
obj-y += temperature/
+obj-y += test/
obj-y += trigger/
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 2e0c62c39155..cceda3cecbcf 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -157,6 +157,24 @@ config BMC150_ACCEL_SPI
tristate
select REGMAP_SPI
+config BMI088_ACCEL
+ tristate "Bosch BMI088 Accelerometer Driver"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ select REGMAP
+ select BMI088_ACCEL_SPI
+ help
+ Say yes here to build support for the Bosch BMI088 accelerometer.
+
+ This is a combo module with both accelerometer and gyroscope. This
+ driver only implements the accelerometer part, which has its own
+ address and register map. BMG160 provides the gyroscope driver.
+
+config BMI088_ACCEL_SPI
+ tristate
+ select REGMAP_SPI
+
config DA280
tristate "MiraMEMS DA280 3-axis 14-bit digital accelerometer driver"
depends on I2C
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 4f6c1ebe13b0..32cd1342a31a 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -20,6 +20,8 @@ obj-$(CONFIG_BMA400_SPI) += bma400_spi.o
obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
+obj-$(CONFIG_BMI088_ACCEL) += bmi088-accel-core.o
+obj-$(CONFIG_BMI088_ACCEL_SPI) += bmi088-accel-spi.o
obj-$(CONFIG_DA280) += da280.o
obj-$(CONFIG_DA311) += da311.o
obj-$(CONFIG_DMARD06) += dmard06.o
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
index 8ba1453b8dbf..9c9a896a872a 100644
--- a/drivers/iio/accel/adxl372.c
+++ b/drivers/iio/accel/adxl372.c
@@ -1236,8 +1236,6 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
st->dready_trig->ops = &adxl372_trigger_ops;
st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops;
- st->dready_trig->dev.parent = dev;
- st->peak_datardy_trig->dev.parent = dev;
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);
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index 71f85a3e525b..b8a7469cdae4 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -1044,7 +1044,7 @@ static int bma180_probe(struct i2c_client *client,
indio_dev->info = &bma180_info;
if (client->irq > 0) {
- data->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
+ data->trig = iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
indio_dev->id);
if (!data->trig) {
ret = -ENOMEM;
@@ -1059,7 +1059,6 @@ static int bma180_probe(struct i2c_client *client,
goto err_trigger_free;
}
- data->trig->dev.parent = dev;
data->trig->ops = &bma180_trigger_ops;
iio_trigger_set_drvdata(data->trig, indio_dev);
indio_dev->trig = iio_trigger_get(data->trig);
diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c
index 3c9b0c6954e6..36fc9876dbca 100644
--- a/drivers/iio/accel/bma220_spi.c
+++ b/drivers/iio/accel/bma220_spi.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* BMA220 Digital triaxial acceleration sensor driver
*
* Copyright (c) 2016,2020 Intel Corporation.
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 7e425ebcd7ea..04d85ce34e9f 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -443,26 +443,32 @@ static bool bmc150_apply_acpi_orientation(struct device *dev,
struct iio_mount_matrix *orientation)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct acpi_device *adev = ACPI_COMPANION(dev);
+ char *name, *alt_name, *label, *str;
union acpi_object *obj, *elements;
- char *name, *alt_name, *str;
acpi_status status;
int i, j, val[3];
if (!adev || !acpi_dev_hid_uid_match(adev, "BOSC0200", NULL))
return false;
- if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0)
+ if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0) {
alt_name = "ROMK";
- else
+ label = "accel-base";
+ } else {
alt_name = "ROMS";
+ label = "accel-display";
+ }
- if (acpi_has_method(adev->handle, "ROTM"))
+ if (acpi_has_method(adev->handle, "ROTM")) {
name = "ROTM";
- else if (acpi_has_method(adev->handle, alt_name))
+ } else if (acpi_has_method(adev->handle, alt_name)) {
name = alt_name;
- else
+ indio_dev->label = label;
+ } else {
return false;
+ }
status = acpi_evaluate_object(adev->handle, name, NULL, &buffer);
if (ACPI_FAILURE(status)) {
@@ -1472,7 +1478,6 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
break;
}
- t->indio_trig->dev.parent = dev;
t->indio_trig->ops = &bmc150_accel_trigger_ops;
t->intr = bmc150_accel_triggers[i].intr;
t->data = data;
diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c
new file mode 100644
index 000000000000..12d00658e46f
--- /dev/null
+++ b/drivers/iio/accel/bmi088-accel-core.c
@@ -0,0 +1,567 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
+ * - BMI088
+ *
+ * Copyright (c) 2018-2021, Topic Embedded Products
+ */
+
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#include "bmi088-accel.h"
+
+#define BMI088_ACCEL_REG_CHIP_ID 0x00
+#define BMI088_ACCEL_REG_ERROR 0x02
+
+#define BMI088_ACCEL_REG_INT_STATUS 0x1D
+#define BMI088_ACCEL_INT_STATUS_BIT_DRDY BIT(7)
+
+#define BMI088_ACCEL_REG_RESET 0x7E
+#define BMI088_ACCEL_RESET_VAL 0xB6
+
+#define BMI088_ACCEL_REG_PWR_CTRL 0x7D
+#define BMI088_ACCEL_REG_PWR_CONF 0x7C
+
+#define BMI088_ACCEL_REG_INT_MAP_DATA 0x58
+#define BMI088_ACCEL_INT_MAP_DATA_BIT_INT1_DRDY BIT(2)
+#define BMI088_ACCEL_INT_MAP_DATA_BIT_INT2_FWM BIT(5)
+
+#define BMI088_ACCEL_REG_INT1_IO_CONF 0x53
+#define BMI088_ACCEL_INT1_IO_CONF_BIT_ENABLE_OUT BIT(3)
+#define BMI088_ACCEL_INT1_IO_CONF_BIT_LVL BIT(1)
+
+#define BMI088_ACCEL_REG_INT2_IO_CONF 0x54
+#define BMI088_ACCEL_INT2_IO_CONF_BIT_ENABLE_OUT BIT(3)
+#define BMI088_ACCEL_INT2_IO_CONF_BIT_LVL BIT(1)
+
+#define BMI088_ACCEL_REG_ACC_CONF 0x40
+#define BMI088_ACCEL_MODE_ODR_MASK 0x0f
+
+#define BMI088_ACCEL_REG_ACC_RANGE 0x41
+#define BMI088_ACCEL_RANGE_3G 0x00
+#define BMI088_ACCEL_RANGE_6G 0x01
+#define BMI088_ACCEL_RANGE_12G 0x02
+#define BMI088_ACCEL_RANGE_24G 0x03
+
+#define BMI088_ACCEL_REG_TEMP 0x22
+#define BMI088_ACCEL_REG_TEMP_SHIFT 5
+#define BMI088_ACCEL_TEMP_UNIT 125
+#define BMI088_ACCEL_TEMP_OFFSET 23000
+
+#define BMI088_ACCEL_REG_XOUT_L 0x12
+#define BMI088_ACCEL_AXIS_TO_REG(axis) \
+ (BMI088_ACCEL_REG_XOUT_L + (axis * 2))
+
+#define BMI088_ACCEL_MAX_STARTUP_TIME_US 1000
+#define BMI088_AUTO_SUSPEND_DELAY_MS 2000
+
+#define BMI088_ACCEL_REG_FIFO_STATUS 0x0E
+#define BMI088_ACCEL_REG_FIFO_CONFIG0 0x48
+#define BMI088_ACCEL_REG_FIFO_CONFIG1 0x49
+#define BMI088_ACCEL_REG_FIFO_DATA 0x3F
+#define BMI088_ACCEL_FIFO_LENGTH 100
+
+#define BMI088_ACCEL_FIFO_MODE_FIFO 0x40
+#define BMI088_ACCEL_FIFO_MODE_STREAM 0x80
+
+enum bmi088_accel_axis {
+ AXIS_X,
+ AXIS_Y,
+ AXIS_Z,
+};
+
+static const int bmi088_sample_freqs[] = {
+ 12, 500000,
+ 25, 0,
+ 50, 0,
+ 100, 0,
+ 200, 0,
+ 400, 0,
+ 800, 0,
+ 1600, 0,
+};
+
+/* Available OSR (over sampling rate) sets the 3dB cut-off frequency */
+enum bmi088_osr_modes {
+ BMI088_ACCEL_MODE_OSR_NORMAL = 0xA,
+ BMI088_ACCEL_MODE_OSR_2 = 0x9,
+ BMI088_ACCEL_MODE_OSR_4 = 0x8,
+};
+
+/* Available ODR (output data rates) in Hz */
+enum bmi088_odr_modes {
+ BMI088_ACCEL_MODE_ODR_12_5 = 0x5,
+ BMI088_ACCEL_MODE_ODR_25 = 0x6,
+ BMI088_ACCEL_MODE_ODR_50 = 0x7,
+ BMI088_ACCEL_MODE_ODR_100 = 0x8,
+ BMI088_ACCEL_MODE_ODR_200 = 0x9,
+ BMI088_ACCEL_MODE_ODR_400 = 0xa,
+ BMI088_ACCEL_MODE_ODR_800 = 0xb,
+ BMI088_ACCEL_MODE_ODR_1600 = 0xc,
+};
+
+struct bmi088_scale_info {
+ int scale;
+ u8 reg_range;
+};
+
+struct bmi088_accel_chip_info {
+ const char *name;
+ u8 chip_id;
+ const struct iio_chan_spec *channels;
+ int num_channels;
+};
+
+struct bmi088_accel_data {
+ struct regmap *regmap;
+ const struct bmi088_accel_chip_info *chip_info;
+ u8 buffer[2] ____cacheline_aligned; /* shared DMA safe buffer */
+};
+
+static const struct regmap_range bmi088_volatile_ranges[] = {
+ /* All registers below 0x40 are volatile, except the CHIP ID. */
+ regmap_reg_range(BMI088_ACCEL_REG_ERROR, 0x3f),
+ /* Mark the RESET as volatile too, it is self-clearing */
+ regmap_reg_range(BMI088_ACCEL_REG_RESET, BMI088_ACCEL_REG_RESET),
+};
+
+static const struct regmap_access_table bmi088_volatile_table = {
+ .yes_ranges = bmi088_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(bmi088_volatile_ranges),
+};
+
+const struct regmap_config bmi088_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x7E,
+ .volatile_table = &bmi088_volatile_table,
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(bmi088_regmap_conf);
+
+static int bmi088_accel_power_up(struct bmi088_accel_data *data)
+{
+ int ret;
+
+ /* Enable accelerometer and temperature sensor */
+ ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CTRL, 0x4);
+ if (ret)
+ return ret;
+
+ /* Datasheet recommends to wait at least 5ms before communication */
+ usleep_range(5000, 6000);
+
+ /* Disable suspend mode */
+ ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CONF, 0x0);
+ if (ret)
+ return ret;
+
+ /* Recommended at least 1ms before further communication */
+ usleep_range(1000, 1200);
+
+ return 0;
+}
+
+static int bmi088_accel_power_down(struct bmi088_accel_data *data)
+{
+ int ret;
+
+ /* Enable suspend mode */
+ ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CONF, 0x3);
+ if (ret)
+ return ret;
+
+ /* Recommended at least 1ms before further communication */
+ usleep_range(1000, 1200);
+
+ /* Disable accelerometer and temperature sensor */
+ ret = regmap_write(data->regmap, BMI088_ACCEL_REG_PWR_CTRL, 0x0);
+ if (ret)
+ return ret;
+
+ /* Datasheet recommends to wait at least 5ms before communication */
+ usleep_range(5000, 6000);
+
+ return 0;
+}
+
+static int bmi088_accel_get_sample_freq(struct bmi088_accel_data *data,
+ int *val, int *val2)
+{
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(data->regmap, BMI088_ACCEL_REG_ACC_CONF,
+ &value);
+ if (ret)
+ return ret;
+
+ value &= BMI088_ACCEL_MODE_ODR_MASK;
+ value -= BMI088_ACCEL_MODE_ODR_12_5;
+ value <<= 1;
+
+ if (value >= ARRAY_SIZE(bmi088_sample_freqs) - 1)
+ return -EINVAL;
+
+ *val = bmi088_sample_freqs[value];
+ *val2 = bmi088_sample_freqs[value + 1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int bmi088_accel_set_sample_freq(struct bmi088_accel_data *data, int val)
+{
+ unsigned int regval;
+ int index = 0;
+
+ while (index < ARRAY_SIZE(bmi088_sample_freqs) &&
+ bmi088_sample_freqs[index] != val)
+ index += 2;
+
+ if (index >= ARRAY_SIZE(bmi088_sample_freqs))
+ return -EINVAL;
+
+ regval = (index >> 1) + BMI088_ACCEL_MODE_ODR_12_5;
+
+ return regmap_update_bits(data->regmap, BMI088_ACCEL_REG_ACC_CONF,
+ BMI088_ACCEL_MODE_ODR_MASK, regval);
+}
+
+static int bmi088_accel_get_temp(struct bmi088_accel_data *data, int *val)
+{
+ int ret;
+ s16 temp;
+
+ ret = regmap_bulk_read(data->regmap, BMI088_ACCEL_REG_TEMP,
+ &data->buffer, sizeof(__be16));
+ if (ret)
+ return ret;
+
+ /* data->buffer is cacheline aligned */
+ temp = be16_to_cpu(*(__be16 *)data->buffer);
+
+ *val = temp >> BMI088_ACCEL_REG_TEMP_SHIFT;
+
+ return IIO_VAL_INT;
+}
+
+static int bmi088_accel_get_axis(struct bmi088_accel_data *data,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ int ret;
+ s16 raw_val;
+
+ ret = regmap_bulk_read(data->regmap,
+ BMI088_ACCEL_AXIS_TO_REG(chan->scan_index),
+ data->buffer, sizeof(__le16));
+ if (ret)
+ return ret;
+
+ raw_val = le16_to_cpu(*(__le16 *)data->buffer);
+ *val = raw_val;
+
+ return IIO_VAL_INT;
+}
+
+static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct bmi088_accel_data *data = iio_priv(indio_dev);
+ struct device *dev = regmap_get_device(data->regmap);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_TEMP:
+ pm_runtime_get_sync(dev);
+ ret = bmi088_accel_get_temp(data, val);
+ goto out_read_raw_pm_put;
+ case IIO_ACCEL:
+ pm_runtime_get_sync(dev);
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ goto out_read_raw_pm_put;
+
+ ret = bmi088_accel_get_axis(data, chan, val);
+ iio_device_release_direct_mode(indio_dev);
+ if (!ret)
+ ret = IIO_VAL_INT;
+
+ goto out_read_raw_pm_put;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ switch (chan->type) {
+ case IIO_TEMP:
+ /* Offset applies before scale */
+ *val = BMI088_ACCEL_TEMP_OFFSET/BMI088_ACCEL_TEMP_UNIT;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_TEMP:
+ /* 0.125 degrees per LSB */
+ *val = BMI088_ACCEL_TEMP_UNIT;
+ return IIO_VAL_INT;
+ case IIO_ACCEL:
+ pm_runtime_get_sync(dev);
+ ret = regmap_read(data->regmap,
+ BMI088_ACCEL_REG_ACC_RANGE, val);
+ if (ret)
+ goto out_read_raw_pm_put;
+
+ *val2 = 15 - (*val & 0x3);
+ *val = 3 * 980;
+ ret = IIO_VAL_FRACTIONAL_LOG2;
+
+ goto out_read_raw_pm_put;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ pm_runtime_get_sync(dev);
+ ret = bmi088_accel_get_sample_freq(data, val, val2);
+ goto out_read_raw_pm_put;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+
+out_read_raw_pm_put:
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
+}
+
+static int bmi088_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_SAMP_FREQ:
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *vals = bmi088_sample_freqs;
+ *length = ARRAY_SIZE(bmi088_sample_freqs);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bmi088_accel_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct bmi088_accel_data *data = iio_priv(indio_dev);
+ struct device *dev = regmap_get_device(data->regmap);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ pm_runtime_get_sync(dev);
+ ret = bmi088_accel_set_sample_freq(data, val);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+#define BMI088_ACCEL_CHANNEL(_axis) { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##_axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = AXIS_##_axis, \
+}
+
+static const struct iio_chan_spec bmi088_accel_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .scan_index = -1,
+ },
+ BMI088_ACCEL_CHANNEL(X),
+ BMI088_ACCEL_CHANNEL(Y),
+ BMI088_ACCEL_CHANNEL(Z),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct bmi088_accel_chip_info bmi088_accel_chip_info_tbl[] = {
+ [0] = {
+ .name = "bmi088a",
+ .chip_id = 0x1E,
+ .channels = bmi088_accel_channels,
+ .num_channels = ARRAY_SIZE(bmi088_accel_channels),
+ },
+};
+
+static const struct iio_info bmi088_accel_info = {
+ .read_raw = bmi088_accel_read_raw,
+ .write_raw = bmi088_accel_write_raw,
+ .read_avail = bmi088_accel_read_avail,
+};
+
+static const unsigned long bmi088_accel_scan_masks[] = {
+ BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
+ 0
+};
+
+static int bmi088_accel_chip_init(struct bmi088_accel_data *data)
+{
+ struct device *dev = regmap_get_device(data->regmap);
+ int ret, i;
+ unsigned int val;
+
+ /* Do a dummy read to enable SPI interface, won't harm I2C */
+ regmap_read(data->regmap, BMI088_ACCEL_REG_INT_STATUS, &val);
+
+ /*
+ * Reset chip to get it in a known good state. A delay of 1ms after
+ * reset is required according to the data sheet
+ */
+ ret = regmap_write(data->regmap, BMI088_ACCEL_REG_RESET,
+ BMI088_ACCEL_RESET_VAL);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ /* Do a dummy read again after a reset to enable the SPI interface */
+ regmap_read(data->regmap, BMI088_ACCEL_REG_INT_STATUS, &val);
+
+ /* Read chip ID */
+ ret = regmap_read(data->regmap, BMI088_ACCEL_REG_CHIP_ID, &val);
+ if (ret) {
+ dev_err(dev, "Error: Reading chip id\n");
+ return ret;
+ }
+
+ /* Validate chip ID */
+ for (i = 0; i < ARRAY_SIZE(bmi088_accel_chip_info_tbl); i++) {
+ if (bmi088_accel_chip_info_tbl[i].chip_id == val) {
+ data->chip_info = &bmi088_accel_chip_info_tbl[i];
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(bmi088_accel_chip_info_tbl)) {
+ dev_err(dev, "Invalid chip %x\n", val);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap,
+ int irq, const char *name, bool block_supported)
+{
+ struct bmi088_accel_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);
+ dev_set_drvdata(dev, indio_dev);
+
+ data->regmap = regmap;
+
+ ret = bmi088_accel_chip_init(data);
+ if (ret)
+ return ret;
+
+ indio_dev->dev.parent = dev;
+ indio_dev->channels = data->chip_info->channels;
+ indio_dev->num_channels = data->chip_info->num_channels;
+ indio_dev->name = name ? name : data->chip_info->name;
+ indio_dev->available_scan_masks = bmi088_accel_scan_masks;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &bmi088_accel_info;
+
+ /* Enable runtime PM */
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_enable(dev);
+ /* We need ~6ms to startup, so set the delay to 6 seconds */
+ pm_runtime_set_autosuspend_delay(dev, 6000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_put(dev);
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ dev_err(dev, "Unable to register iio device\n");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(bmi088_accel_core_probe);
+
+
+int bmi088_accel_core_remove(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct bmi088_accel_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
+ bmi088_accel_power_down(data);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bmi088_accel_core_remove);
+
+static int __maybe_unused bmi088_accel_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct bmi088_accel_data *data = iio_priv(indio_dev);
+
+ return bmi088_accel_power_down(data);
+}
+
+static int __maybe_unused bmi088_accel_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct bmi088_accel_data *data = iio_priv(indio_dev);
+
+ return bmi088_accel_power_up(data);
+}
+
+const struct dev_pm_ops bmi088_accel_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(bmi088_accel_runtime_suspend,
+ bmi088_accel_runtime_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(bmi088_accel_pm_ops);
+
+MODULE_AUTHOR("Niek van Agt <niek.van.agt@topicproducts.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMI088 accelerometer driver (core)");
diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c
new file mode 100644
index 000000000000..dd1e3f6cf211
--- /dev/null
+++ b/drivers/iio/accel/bmi088-accel-spi.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
+ * - BMI088
+ *
+ * Copyright (c) 2018-2020, Topic Embedded Products
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#include "bmi088-accel.h"
+
+static int bmi088_regmap_spi_write(void *context, const void *data, size_t count)
+{
+ struct spi_device *spi = context;
+
+ /* Write register is same as generic SPI */
+ return spi_write(spi, data, count);
+}
+
+static int bmi088_regmap_spi_read(void *context, const void *reg,
+ size_t reg_size, void *val, size_t val_size)
+{
+ struct spi_device *spi = context;
+ u8 addr[2];
+
+ addr[0] = *(u8 *)reg;
+ addr[0] |= BIT(7); /* Set RW = '1' */
+ addr[1] = 0; /* Read requires a dummy byte transfer */
+
+ return spi_write_then_read(spi, addr, sizeof(addr), val, val_size);
+}
+
+static struct regmap_bus bmi088_regmap_bus = {
+ .write = bmi088_regmap_spi_write,
+ .read = bmi088_regmap_spi_read,
+};
+
+static int bmi088_accel_probe(struct spi_device *spi)
+{
+ struct regmap *regmap;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+
+ regmap = devm_regmap_init(&spi->dev, &bmi088_regmap_bus,
+ spi, &bmi088_regmap_conf);
+
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "Failed to initialize spi regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ return bmi088_accel_core_probe(&spi->dev, regmap, spi->irq, id->name,
+ true);
+}
+
+static int bmi088_accel_remove(struct spi_device *spi)
+{
+ return bmi088_accel_core_remove(&spi->dev);
+}
+
+static const struct spi_device_id bmi088_accel_id[] = {
+ {"bmi088-accel", },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, bmi088_accel_id);
+
+static struct spi_driver bmi088_accel_driver = {
+ .driver = {
+ .name = "bmi088_accel_spi",
+ .pm = &bmi088_accel_pm_ops,
+ },
+ .probe = bmi088_accel_probe,
+ .remove = bmi088_accel_remove,
+ .id_table = bmi088_accel_id,
+};
+module_spi_driver(bmi088_accel_driver);
+
+MODULE_AUTHOR("Niek van Agt <niek.van.agt@topicproducts.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMI088 accelerometer driver (SPI)");
diff --git a/drivers/iio/accel/bmi088-accel.h b/drivers/iio/accel/bmi088-accel.h
new file mode 100644
index 000000000000..5c25f16b672c
--- /dev/null
+++ b/drivers/iio/accel/bmi088-accel.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef BMI088_ACCEL_H
+#define BMI088_ACCEL_H
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+struct device;
+
+extern const struct regmap_config bmi088_regmap_conf;
+extern const struct dev_pm_ops bmi088_accel_pm_ops;
+
+int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
+ const char *name, bool block_supported);
+int bmi088_accel_core_remove(struct device *dev);
+
+#endif /* BMI088_ACCEL_H */
diff --git a/drivers/iio/accel/cros_ec_accel_legacy.c b/drivers/iio/accel/cros_ec_accel_legacy.c
index 8f1232c38e0d..b6f3471b62dc 100644
--- a/drivers/iio/accel/cros_ec_accel_legacy.c
+++ b/drivers/iio/accel/cros_ec_accel_legacy.c
@@ -215,7 +215,7 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
return -ENOMEM;
ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
- cros_ec_sensors_capture, NULL, false);
+ cros_ec_sensors_capture, NULL);
if (ret)
return ret;
diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c
index 4472dde6899e..5edff9ba72da 100644
--- a/drivers/iio/accel/da280.c
+++ b/drivers/iio/accel/da280.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* IIO driver for the MiraMEMS DA280 3-axis accelerometer and
* IIO driver for the MiraMEMS DA226 2-axis accelerometer
*
diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c
index 3b3df620ba27..92593a1cd1aa 100644
--- a/drivers/iio/accel/da311.c
+++ b/drivers/iio/accel/da311.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* IIO driver for the MiraMEMS DA311 3-axis accelerometer
*
* Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com>
diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c
index 90206f015857..e84bf8db1e89 100644
--- a/drivers/iio/accel/dmard10.c
+++ b/drivers/iio/accel/dmard10.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* IIO driver for the 3-axis accelerometer Domintech ARD10.
*
* Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com>
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 5d63ed19e6e2..2f9465cb382f 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -43,6 +43,10 @@ static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = {
HID_USAGE_SENSOR_ACCEL_Z_AXIS
};
+static const u32 accel_3d_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_DATA_ACCELERATION,
+};
+
/* Channel definitions */
static const struct iio_chan_spec accel_3d_channels[] = {
{
@@ -317,18 +321,6 @@ static int accel_3d_parse_report(struct platform_device *pdev,
&st->accel[CHANNEL_SCAN_INDEX_X],
&st->scale_pre_decml, &st->scale_post_decml);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->common_attributes.sensitivity.index < 0) {
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_DATA_ACCELERATION,
- &st->common_attributes.sensitivity);
- dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
- st->common_attributes.sensitivity.index,
- st->common_attributes.sensitivity.report_id);
- }
-
return ret;
}
@@ -366,8 +358,11 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
channel_size = sizeof(gravity_channels);
indio_dev->num_channels = ARRAY_SIZE(gravity_channels);
}
- ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage,
- &accel_state->common_attributes);
+ ret = hid_sensor_parse_common_attributes(hsdev,
+ hsdev->usage,
+ &accel_state->common_attributes,
+ accel_3d_sensitivity_addresses,
+ ARRAY_SIZE(accel_3d_sensitivity_addresses));
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 2fadafc860fd..ff724bc17a45 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -1284,7 +1284,8 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private)
static const char *kxcjk1013_match_acpi_device(struct device *dev,
enum kx_chipset *chipset,
- enum kx_acpi_type *acpi_type)
+ enum kx_acpi_type *acpi_type,
+ const char **label)
{
const struct acpi_device_id *id;
@@ -1292,10 +1293,14 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev,
if (!id)
return NULL;
- if (strcmp(id->id, "SMO8500") == 0)
+ if (strcmp(id->id, "SMO8500") == 0) {
*acpi_type = ACPI_SMO8500;
- else if (strcmp(id->id, "KIOX010A") == 0)
+ } else if (strcmp(id->id, "KIOX010A") == 0) {
*acpi_type = ACPI_KIOX010A;
+ *label = "accel-display";
+ } else if (strcmp(id->id, "KIOX020A") == 0) {
+ *label = "accel-base";
+ }
*chipset = (enum kx_chipset)id->driver_data;
@@ -1368,7 +1373,8 @@ static int kxcjk1013_probe(struct i2c_client *client,
} else if (ACPI_HANDLE(&client->dev)) {
name = kxcjk1013_match_acpi_device(&client->dev,
&data->chipset,
- &data->acpi_type);
+ &data->acpi_type,
+ &indio_dev->label);
} else
return -ENODEV;
@@ -1413,7 +1419,6 @@ static int kxcjk1013_probe(struct i2c_client *client,
goto err_poweroff;
}
- data->dready_trig->dev.parent = &client->dev;
data->dready_trig->ops = &kxcjk1013_trigger_ops;
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
indio_dev->trig = data->dready_trig;
@@ -1422,7 +1427,6 @@ static int kxcjk1013_probe(struct i2c_client *client,
if (ret)
goto err_poweroff;
- data->motion_trig->dev.parent = &client->dev;
data->motion_trig->ops = &kxcjk1013_trigger_ops;
iio_trigger_set_drvdata(data->motion_trig, indio_dev);
ret = iio_trigger_register(data->motion_trig);
diff --git a/drivers/iio/accel/mc3230.c b/drivers/iio/accel/mc3230.c
index 46e4283fc037..735002b716f3 100644
--- a/drivers/iio/accel/mc3230.c
+++ b/drivers/iio/accel/mc3230.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/**
+/*
* mCube MC3230 3-Axis Accelerometer
*
* Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com>
diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c
index b3c9136d51ec..47f5cd66e996 100644
--- a/drivers/iio/accel/mma7660.c
+++ b/drivers/iio/accel/mma7660.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* Freescale MMA7660FC 3-Axis Accelerometer
*
* Copyright (c) 2016, Intel Corporation.
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index b0176d936423..4d307dfb9169 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -58,7 +58,7 @@
#define MMA8452_FF_MT_THS 0x17
#define MMA8452_FF_MT_THS_MASK 0x7f
#define MMA8452_FF_MT_COUNT 0x18
-#define MMA8452_FF_MT_CHAN_SHIFT 3
+#define MMA8452_FF_MT_CHAN_SHIFT 3
#define MMA8452_TRANSIENT_CFG 0x1d
#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
@@ -70,7 +70,7 @@
#define MMA8452_TRANSIENT_THS 0x1f
#define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0)
#define MMA8452_TRANSIENT_COUNT 0x20
-#define MMA8452_TRANSIENT_CHAN_SHIFT 1
+#define MMA8452_TRANSIENT_CHAN_SHIFT 1
#define MMA8452_CTRL_REG1 0x2a
#define MMA8452_CTRL_ACTIVE BIT(0)
#define MMA8452_CTRL_DR_MASK GENMASK(5, 3)
@@ -134,33 +134,33 @@ struct mma8452_data {
* used for different chips and the relevant registers are included here.
*/
struct mma8452_event_regs {
- u8 ev_cfg;
- u8 ev_cfg_ele;
- u8 ev_cfg_chan_shift;
- u8 ev_src;
- u8 ev_ths;
- u8 ev_ths_mask;
- u8 ev_count;
+ u8 ev_cfg;
+ u8 ev_cfg_ele;
+ u8 ev_cfg_chan_shift;
+ u8 ev_src;
+ u8 ev_ths;
+ u8 ev_ths_mask;
+ u8 ev_count;
};
static const struct mma8452_event_regs ff_mt_ev_regs = {
- .ev_cfg = MMA8452_FF_MT_CFG,
- .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE,
- .ev_cfg_chan_shift = MMA8452_FF_MT_CHAN_SHIFT,
- .ev_src = MMA8452_FF_MT_SRC,
- .ev_ths = MMA8452_FF_MT_THS,
- .ev_ths_mask = MMA8452_FF_MT_THS_MASK,
- .ev_count = MMA8452_FF_MT_COUNT
+ .ev_cfg = MMA8452_FF_MT_CFG,
+ .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE,
+ .ev_cfg_chan_shift = MMA8452_FF_MT_CHAN_SHIFT,
+ .ev_src = MMA8452_FF_MT_SRC,
+ .ev_ths = MMA8452_FF_MT_THS,
+ .ev_ths_mask = MMA8452_FF_MT_THS_MASK,
+ .ev_count = MMA8452_FF_MT_COUNT
};
static const struct mma8452_event_regs trans_ev_regs = {
- .ev_cfg = MMA8452_TRANSIENT_CFG,
- .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
- .ev_cfg_chan_shift = MMA8452_TRANSIENT_CHAN_SHIFT,
- .ev_src = MMA8452_TRANSIENT_SRC,
- .ev_ths = MMA8452_TRANSIENT_THS,
- .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
- .ev_count = MMA8452_TRANSIENT_COUNT,
+ .ev_cfg = MMA8452_TRANSIENT_CFG,
+ .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
+ .ev_cfg_chan_shift = MMA8452_TRANSIENT_CHAN_SHIFT,
+ .ev_src = MMA8452_TRANSIENT_SRC,
+ .ev_ths = MMA8452_TRANSIENT_THS,
+ .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
+ .ev_count = MMA8452_TRANSIENT_COUNT,
};
/**
@@ -1465,7 +1465,6 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev)
if (!trig)
return -ENOMEM;
- trig->dev.parent = &data->client->dev;
trig->ops = &mma8452_trigger_ops;
iio_trigger_set_drvdata(trig, indio_dev);
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index 0f8fd687866d..fb3cbaa62bd8 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -450,7 +450,6 @@ static int mxc4005_probe(struct i2c_client *client,
return ret;
}
- data->dready_trig->dev.parent = &client->dev;
data->dready_trig->ops = &mxc4005_trigger_ops;
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
indio_dev->trig = data->dready_trig;
diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c
index 194738660523..cb753a43533c 100644
--- a/drivers/iio/accel/sca3000.c
+++ b/drivers/iio/accel/sca3000.c
@@ -351,7 +351,7 @@ static int __sca3000_unlock_reg_lock(struct sca3000_state *st)
}
/**
- * sca3000_write_ctrl_reg() write to a lock protect ctrl register
+ * sca3000_write_ctrl_reg() - write to a lock protect ctrl register
* @st: Driver specific device instance data.
* @sel: selects which registers we wish to write to
* @val: the value to be written
@@ -389,7 +389,7 @@ error_ret:
}
/**
- * sca3000_read_ctrl_reg() read from lock protected control register.
+ * sca3000_read_ctrl_reg() - read from lock protected control register.
* @st: Driver specific device instance data.
* @ctrl_reg: Which ctrl register do we want to read.
*
@@ -421,7 +421,7 @@ error_ret:
}
/**
- * sca3000_show_rev() - sysfs interface to read the chip revision number
+ * sca3000_print_rev() - sysfs interface to read the chip revision number
* @indio_dev: Device instance specific generic IIO data.
* Driver specific device instance data can be obtained via
* via iio_priv(indio_dev)
@@ -902,7 +902,7 @@ static int sca3000_read_event_value(struct iio_dev *indio_dev,
}
/**
- * sca3000_write_value() - control of threshold and period
+ * sca3000_write_event_value() - control of threshold and period
* @indio_dev: Device instance specific IIO information.
* @chan: Description of the channel for which the event is being
* configured.
@@ -1272,20 +1272,6 @@ static int sca3000_write_event_config(struct iio_dev *indio_dev,
return ret;
}
-static int sca3000_configure_ring(struct iio_dev *indio_dev)
-{
- struct iio_buffer *buffer;
-
- buffer = devm_iio_kfifo_allocate(&indio_dev->dev);
- if (!buffer)
- return -ENOMEM;
-
- iio_device_attach_buffer(indio_dev, buffer);
- indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
-
- return 0;
-}
-
static inline
int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state)
{
@@ -1479,7 +1465,9 @@ static int sca3000_probe(struct spi_device *spi)
}
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = sca3000_configure_ring(indio_dev);
+ ret = devm_iio_kfifo_buffer_setup(&spi->dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &sca3000_ring_setup_ops);
if (ret)
return ret;
@@ -1493,7 +1481,6 @@ static int sca3000_probe(struct spi_device *spi)
if (ret)
return ret;
}
- indio_dev->setup_ops = &sca3000_ring_setup_ops;
ret = sca3000_clean_setup(st);
if (ret)
goto error_free_irq;
diff --git a/drivers/iio/accel/ssp_accel_sensor.c b/drivers/iio/accel/ssp_accel_sensor.c
index 474477e91b5e..04dcb2b657ee 100644
--- a/drivers/iio/accel/ssp_accel_sensor.c
+++ b/drivers/iio/accel/ssp_accel_sensor.c
@@ -96,7 +96,6 @@ static int ssp_accel_probe(struct platform_device *pdev)
int ret;
struct iio_dev *indio_dev;
struct ssp_sensor_data *spd;
- struct iio_buffer *buffer;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*spd));
if (!indio_dev)
@@ -109,18 +108,15 @@ static int ssp_accel_probe(struct platform_device *pdev)
indio_dev->name = ssp_accel_device_name;
indio_dev->info = &ssp_accel_iio_info;
- indio_dev->modes = INDIO_BUFFER_SOFTWARE;
indio_dev->channels = ssp_acc_channels;
indio_dev->num_channels = ARRAY_SIZE(ssp_acc_channels);
indio_dev->available_scan_masks = ssp_accel_scan_mask;
- buffer = devm_iio_kfifo_allocate(&pdev->dev);
- if (!buffer)
- return -ENOMEM;
-
- iio_device_attach_buffer(indio_dev, buffer);
-
- indio_dev->setup_ops = &ssp_accel_buffer_ops;
+ ret = devm_iio_kfifo_buffer_setup(&pdev->dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &ssp_accel_buffer_ops);
+ if (ret)
+ return ret;
platform_set_drvdata(pdev, indio_dev);
diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index 3b59887a8581..157d8faefb9e 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* Sensortek STK8312 3-Axis Accelerometer
*
* Copyright (c) 2015, Intel Corporation.
@@ -558,7 +558,6 @@ static int stk8312_probe(struct i2c_client *client,
goto err_power_off;
}
- data->dready_trig->dev.parent = &client->dev;
data->dready_trig->ops = &stk8312_trigger_ops;
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
ret = iio_trigger_register(data->dready_trig);
diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c
index 3ead378b02c9..7cf9cb7e8666 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* Sensortek STK8BA50 3-Axis Accelerometer
*
* Copyright (c) 2015, Intel Corporation.
@@ -454,7 +454,6 @@ static int stk8ba50_probe(struct i2c_client *client,
goto err_power_off;
}
- data->dready_trig->dev.parent = &client->dev;
data->dready_trig->ops = &stk8ba50_trigger_ops;
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
ret = iio_trigger_register(data->dready_trig);
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index e0667c4b3c08..d20a3b574af9 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -1154,6 +1154,18 @@ config TI_ADS124S08
This driver can also be built as a module. If so, the module will be
called ti-ads124s08.
+config TI_ADS131E08
+ tristate "Texas Instruments ADS131E08"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to get support for Texas Instruments ADS131E04, ADS131E06
+ and ADS131E08 chips.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads131e08.
+
config TI_AM335X_ADC
tristate "TI's AM335X ADC driver"
depends on MFD_TI_AM335X_TSCADC && HAS_DMA
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 5fca90ada0ec..a226657d19c0 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -103,6 +103,7 @@ obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
+obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index 766c73333604..9d3952b4674f 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -5,12 +5,14 @@
* Copyright 2018 Analog Devices Inc.
*/
#include <linux/bitfield.h>
+#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
+#include <linux/kfifo.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
@@ -86,6 +88,10 @@
#define AD7124_SINC3_FILTER 2
#define AD7124_SINC4_FILTER 0
+#define AD7124_CONF_ADDR_OFFSET 20
+#define AD7124_MAX_CONFIGS 8
+#define AD7124_MAX_CHANNELS 16
+
enum ad7124_ids {
ID_AD7124_4,
ID_AD7124_8,
@@ -136,25 +142,37 @@ struct ad7124_chip_info {
};
struct ad7124_channel_config {
+ bool live;
+ unsigned int cfg_slot;
enum ad7124_ref_sel refsel;
bool bipolar;
bool buf_positive;
bool buf_negative;
- unsigned int ain;
unsigned int vref_mv;
unsigned int pga_bits;
unsigned int odr;
+ unsigned int odr_sel_bits;
unsigned int filter_type;
};
+struct ad7124_channel {
+ unsigned int nr;
+ struct ad7124_channel_config cfg;
+ unsigned int ain;
+ unsigned int slot;
+};
+
struct ad7124_state {
const struct ad7124_chip_info *chip_info;
struct ad_sigma_delta sd;
- struct ad7124_channel_config *channel_config;
+ struct ad7124_channel *channels;
struct regulator *vref[4];
struct clk *mclk;
unsigned int adc_control;
unsigned int num_channels;
+ struct mutex cfgs_lock; /* lock for configs access */
+ unsigned long cfg_slots_status; /* bitmap with slot status (1 means it is used) */
+ DECLARE_KFIFO(live_cfgs_fifo, struct ad7124_channel_config *, AD7124_MAX_CONFIGS);
};
static const struct iio_chan_spec ad7124_channel_template = {
@@ -238,33 +256,9 @@ static int ad7124_set_mode(struct ad_sigma_delta *sd,
return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control);
}
-static int ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
-{
- struct ad7124_state *st = container_of(sd, struct ad7124_state, sd);
- unsigned int val;
-
- val = st->channel_config[channel].ain | AD7124_CHANNEL_EN(1) |
- AD7124_CHANNEL_SETUP(channel);
-
- return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(channel), 2, val);
-}
-
-static const struct ad_sigma_delta_info ad7124_sigma_delta_info = {
- .set_channel = ad7124_set_channel,
- .set_mode = ad7124_set_mode,
- .has_registers = true,
- .addr_shift = 0,
- .read_mask = BIT(6),
- .data_reg = AD7124_DATA,
- .irq_flags = IRQF_TRIGGER_FALLING,
-};
-
-static int ad7124_set_channel_odr(struct ad7124_state *st,
- unsigned int channel,
- unsigned int odr)
+static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel, unsigned int odr)
{
unsigned int fclk, odr_sel_bits;
- int ret;
fclk = clk_get_rate(st->mclk);
/*
@@ -280,36 +274,12 @@ static int ad7124_set_channel_odr(struct ad7124_state *st,
else if (odr_sel_bits > 2047)
odr_sel_bits = 2047;
- ret = ad7124_spi_write_mask(st, AD7124_FILTER(channel),
- AD7124_FILTER_FS_MSK,
- AD7124_FILTER_FS(odr_sel_bits), 3);
- if (ret < 0)
- return ret;
- /* fADC = fCLK / (FS[10:0] x 32) */
- st->channel_config[channel].odr =
- DIV_ROUND_CLOSEST(fclk, odr_sel_bits * 32);
-
- return 0;
-}
-
-static int ad7124_set_channel_gain(struct ad7124_state *st,
- unsigned int channel,
- unsigned int gain)
-{
- unsigned int res;
- int ret;
+ if (odr_sel_bits != st->channels[channel].cfg.odr_sel_bits)
+ st->channels[channel].cfg.live = false;
- res = ad7124_find_closest_match(ad7124_gain,
- ARRAY_SIZE(ad7124_gain), gain);
- ret = ad7124_spi_write_mask(st, AD7124_CONFIG(channel),
- AD7124_CONFIG_PGA_MSK,
- AD7124_CONFIG_PGA(res), 2);
- if (ret < 0)
- return ret;
-
- st->channel_config[channel].pga_bits = res;
-
- return 0;
+ /* fADC = fCLK / (FS[10:0] x 32) */
+ st->channels[channel].cfg.odr = DIV_ROUND_CLOSEST(fclk, odr_sel_bits * 32);
+ st->channels[channel].cfg.odr_sel_bits = odr_sel_bits;
}
static int ad7124_get_3db_filter_freq(struct ad7124_state *st,
@@ -317,9 +287,9 @@ static int ad7124_get_3db_filter_freq(struct ad7124_state *st,
{
unsigned int fadc;
- fadc = st->channel_config[channel].odr;
+ fadc = st->channels[channel].cfg.odr;
- switch (st->channel_config[channel].filter_type) {
+ switch (st->channels[channel].cfg.filter_type) {
case AD7124_SINC3_FILTER:
return DIV_ROUND_CLOSEST(fadc * 230, 1000);
case AD7124_SINC4_FILTER:
@@ -329,9 +299,8 @@ static int ad7124_get_3db_filter_freq(struct ad7124_state *st,
}
}
-static int ad7124_set_3db_filter_freq(struct ad7124_state *st,
- unsigned int channel,
- unsigned int freq)
+static void ad7124_set_3db_filter_freq(struct ad7124_state *st, unsigned int channel,
+ unsigned int freq)
{
unsigned int sinc4_3db_odr;
unsigned int sinc3_3db_odr;
@@ -349,21 +318,211 @@ static int ad7124_set_3db_filter_freq(struct ad7124_state *st,
new_odr = sinc3_3db_odr;
}
- if (st->channel_config[channel].filter_type != new_filter) {
- int ret;
+ if (new_odr != st->channels[channel].cfg.odr)
+ st->channels[channel].cfg.live = false;
- st->channel_config[channel].filter_type = new_filter;
- ret = ad7124_spi_write_mask(st, AD7124_FILTER(channel),
- AD7124_FILTER_TYPE_MSK,
- AD7124_FILTER_TYPE_SEL(new_filter),
- 3);
- if (ret < 0)
- return ret;
+ st->channels[channel].cfg.filter_type = new_filter;
+ st->channels[channel].cfg.odr = new_odr;
+}
+
+static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_state *st,
+ struct ad7124_channel_config *cfg)
+{
+ struct ad7124_channel_config *cfg_aux;
+ ptrdiff_t cmp_size;
+ int i;
+
+ cmp_size = (u8 *)&cfg->live - (u8 *)cfg;
+ for (i = 0; i < st->num_channels; i++) {
+ cfg_aux = &st->channels[i].cfg;
+
+ if (cfg_aux->live && !memcmp(cfg, cfg_aux, cmp_size))
+ return cfg_aux;
+ }
+
+ return NULL;
+}
+
+static int ad7124_find_free_config_slot(struct ad7124_state *st)
+{
+ unsigned int free_cfg_slot;
+
+ free_cfg_slot = find_next_zero_bit(&st->cfg_slots_status, AD7124_MAX_CONFIGS, 0);
+ if (free_cfg_slot == AD7124_MAX_CONFIGS)
+ return -1;
+
+ return free_cfg_slot;
+}
+
+static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channel_config *cfg)
+{
+ unsigned int refsel = cfg->refsel;
+
+ switch (refsel) {
+ case AD7124_REFIN1:
+ case AD7124_REFIN2:
+ case AD7124_AVDD_REF:
+ if (IS_ERR(st->vref[refsel])) {
+ dev_err(&st->sd.spi->dev,
+ "Error, trying to use external voltage reference without a %s regulator.\n",
+ ad7124_ref_names[refsel]);
+ return PTR_ERR(st->vref[refsel]);
+ }
+ cfg->vref_mv = regulator_get_voltage(st->vref[refsel]);
+ /* Conversion from uV to mV */
+ cfg->vref_mv /= 1000;
+ return 0;
+ case AD7124_INT_REF:
+ cfg->vref_mv = 2500;
+ st->adc_control &= ~AD7124_ADC_CTRL_REF_EN_MSK;
+ st->adc_control |= AD7124_ADC_CTRL_REF_EN(1);
+ return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL,
+ 2, st->adc_control);
+ default:
+ dev_err(&st->sd.spi->dev, "Invalid reference %d\n", refsel);
+ return -EINVAL;
+ }
+}
+
+static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_config *cfg,
+ unsigned int cfg_slot)
+{
+ unsigned int tmp;
+ unsigned int val;
+ int ret;
+
+ cfg->cfg_slot = cfg_slot;
+
+ tmp = (cfg->buf_positive << 1) + cfg->buf_negative;
+ val = AD7124_CONFIG_BIPOLAR(cfg->bipolar) | AD7124_CONFIG_REF_SEL(cfg->refsel) |
+ AD7124_CONFIG_IN_BUFF(tmp);
+ ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(cfg->cfg_slot), 2, val);
+ if (ret < 0)
+ return ret;
+
+ tmp = AD7124_FILTER_TYPE_SEL(cfg->filter_type);
+ ret = ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot), AD7124_FILTER_TYPE_MSK,
+ tmp, 3);
+ if (ret < 0)
+ return ret;
+
+ ret = ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot), AD7124_FILTER_FS_MSK,
+ AD7124_FILTER_FS(cfg->odr_sel_bits), 3);
+ if (ret < 0)
+ return ret;
+
+ return ad7124_spi_write_mask(st, AD7124_CONFIG(cfg->cfg_slot), AD7124_CONFIG_PGA_MSK,
+ AD7124_CONFIG_PGA(cfg->pga_bits), 2);
+}
+
+static struct ad7124_channel_config *ad7124_pop_config(struct ad7124_state *st)
+{
+ struct ad7124_channel_config *lru_cfg;
+ struct ad7124_channel_config *cfg;
+ int ret;
+ int i;
+
+ /*
+ * Pop least recently used config from the fifo
+ * in order to make room for the new one
+ */
+ ret = kfifo_get(&st->live_cfgs_fifo, &lru_cfg);
+ if (ret <= 0)
+ return NULL;
+
+ lru_cfg->live = false;
+
+ /* mark slot as free */
+ assign_bit(lru_cfg->cfg_slot, &st->cfg_slots_status, 0);
+
+ /* invalidate all other configs that pointed to this one */
+ for (i = 0; i < st->num_channels; i++) {
+ cfg = &st->channels[i].cfg;
+
+ if (cfg->cfg_slot == lru_cfg->cfg_slot)
+ cfg->live = false;
+ }
+
+ return lru_cfg;
+}
+
+static int ad7124_push_config(struct ad7124_state *st, struct ad7124_channel_config *cfg)
+{
+ struct ad7124_channel_config *lru_cfg;
+ int free_cfg_slot;
+
+ free_cfg_slot = ad7124_find_free_config_slot(st);
+ if (free_cfg_slot >= 0) {
+ /* push the new config in configs queue */
+ kfifo_put(&st->live_cfgs_fifo, cfg);
+ } else {
+ /* pop one config to make room for the new one */
+ lru_cfg = ad7124_pop_config(st);
+ if (!lru_cfg)
+ return -EINVAL;
+
+ /* push the new config in configs queue */
+ free_cfg_slot = lru_cfg->cfg_slot;
+ kfifo_put(&st->live_cfgs_fifo, cfg);
+ }
+
+ /* mark slot as used */
+ assign_bit(free_cfg_slot, &st->cfg_slots_status, 1);
+
+ return ad7124_write_config(st, cfg, free_cfg_slot);
+}
+
+static int ad7124_enable_channel(struct ad7124_state *st, struct ad7124_channel *ch)
+{
+ ch->cfg.live = true;
+ return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(ch->nr), 2, ch->ain |
+ AD7124_CHANNEL_SETUP(ch->cfg.cfg_slot) | AD7124_CHANNEL_EN(1));
+}
+
+static int ad7124_prepare_read(struct ad7124_state *st, int address)
+{
+ struct ad7124_channel_config *cfg = &st->channels[address].cfg;
+ struct ad7124_channel_config *live_cfg;
+
+ /*
+ * Before doing any reads assign the channel a configuration.
+ * Check if channel's config is on the device
+ */
+ if (!cfg->live) {
+ /* check if config matches another one */
+ live_cfg = ad7124_find_similar_live_cfg(st, cfg);
+ if (!live_cfg)
+ ad7124_push_config(st, cfg);
+ else
+ cfg->cfg_slot = live_cfg->cfg_slot;
}
- return ad7124_set_channel_odr(st, channel, new_odr);
+ /* point channel to the config slot and enable */
+ return ad7124_enable_channel(st, &st->channels[address]);
}
+static int ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
+{
+ struct ad7124_state *st = container_of(sd, struct ad7124_state, sd);
+ int ret;
+
+ mutex_lock(&st->cfgs_lock);
+ ret = ad7124_prepare_read(st, channel);
+ mutex_unlock(&st->cfgs_lock);
+
+ return ret;
+}
+
+static const struct ad_sigma_delta_info ad7124_sigma_delta_info = {
+ .set_channel = ad7124_set_channel,
+ .set_mode = ad7124_set_mode,
+ .has_registers = true,
+ .addr_shift = 0,
+ .read_mask = BIT(6),
+ .data_reg = AD7124_DATA,
+ .irq_flags = IRQF_TRIGGER_FALLING
+};
+
static int ad7124_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long info)
@@ -378,36 +537,44 @@ static int ad7124_read_raw(struct iio_dev *indio_dev,
return ret;
/* After the conversion is performed, disable the channel */
- ret = ad_sd_write_reg(&st->sd,
- AD7124_CHANNEL(chan->address), 2,
- st->channel_config[chan->address].ain |
- AD7124_CHANNEL_EN(0));
+ ret = ad_sd_write_reg(&st->sd, AD7124_CHANNEL(chan->address), 2,
+ st->channels[chan->address].ain | AD7124_CHANNEL_EN(0));
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- idx = st->channel_config[chan->address].pga_bits;
- *val = st->channel_config[chan->address].vref_mv;
- if (st->channel_config[chan->address].bipolar)
+ mutex_lock(&st->cfgs_lock);
+
+ idx = st->channels[chan->address].cfg.pga_bits;
+ *val = st->channels[chan->address].cfg.vref_mv;
+ if (st->channels[chan->address].cfg.bipolar)
*val2 = chan->scan_type.realbits - 1 + idx;
else
*val2 = chan->scan_type.realbits + idx;
+ mutex_unlock(&st->cfgs_lock);
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
- if (st->channel_config[chan->address].bipolar)
+ mutex_lock(&st->cfgs_lock);
+ if (st->channels[chan->address].cfg.bipolar)
*val = -(1 << (chan->scan_type.realbits - 1));
else
*val = 0;
+ mutex_unlock(&st->cfgs_lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
- *val = st->channel_config[chan->address].odr;
+ mutex_lock(&st->cfgs_lock);
+ *val = st->channels[chan->address].cfg.odr;
+ mutex_unlock(&st->cfgs_lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ mutex_lock(&st->cfgs_lock);
*val = ad7124_get_3db_filter_freq(st, chan->scan_index);
+ mutex_unlock(&st->cfgs_lock);
+
return IIO_VAL_INT;
default:
return -EINVAL;
@@ -420,35 +587,54 @@ static int ad7124_write_raw(struct iio_dev *indio_dev,
{
struct ad7124_state *st = iio_priv(indio_dev);
unsigned int res, gain, full_scale, vref;
+ int ret = 0;
+
+ mutex_lock(&st->cfgs_lock);
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
- if (val2 != 0)
- return -EINVAL;
+ if (val2 != 0) {
+ ret = -EINVAL;
+ break;
+ }
- return ad7124_set_channel_odr(st, chan->address, val);
+ ad7124_set_channel_odr(st, chan->address, val);
+ break;
case IIO_CHAN_INFO_SCALE:
- if (val != 0)
- return -EINVAL;
+ if (val != 0) {
+ ret = -EINVAL;
+ break;
+ }
- if (st->channel_config[chan->address].bipolar)
+ if (st->channels[chan->address].cfg.bipolar)
full_scale = 1 << (chan->scan_type.realbits - 1);
else
full_scale = 1 << chan->scan_type.realbits;
- vref = st->channel_config[chan->address].vref_mv * 1000000LL;
+ vref = st->channels[chan->address].cfg.vref_mv * 1000000LL;
res = DIV_ROUND_CLOSEST(vref, full_scale);
gain = DIV_ROUND_CLOSEST(res, val2);
+ res = ad7124_find_closest_match(ad7124_gain, ARRAY_SIZE(ad7124_gain), gain);
+
+ if (st->channels[chan->address].cfg.pga_bits != res)
+ st->channels[chan->address].cfg.live = false;
- return ad7124_set_channel_gain(st, chan->address, gain);
+ st->channels[chan->address].cfg.pga_bits = res;
+ break;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- if (val2 != 0)
- return -EINVAL;
+ if (val2 != 0) {
+ ret = -EINVAL;
+ break;
+ }
- return ad7124_set_3db_filter_freq(st, chan->address, val);
+ ad7124_set_3db_filter_freq(st, chan->address, val);
+ break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
+
+ mutex_unlock(&st->cfgs_lock);
+ return ret;
}
static int ad7124_reg_access(struct iio_dev *indio_dev,
@@ -547,47 +733,14 @@ static int ad7124_check_chip_id(struct ad7124_state *st)
return 0;
}
-static int ad7124_init_channel_vref(struct ad7124_state *st,
- unsigned int channel_number)
-{
- unsigned int refsel = st->channel_config[channel_number].refsel;
-
- switch (refsel) {
- case AD7124_REFIN1:
- case AD7124_REFIN2:
- case AD7124_AVDD_REF:
- if (IS_ERR(st->vref[refsel])) {
- dev_err(&st->sd.spi->dev,
- "Error, trying to use external voltage reference without a %s regulator.\n",
- ad7124_ref_names[refsel]);
- return PTR_ERR(st->vref[refsel]);
- }
- st->channel_config[channel_number].vref_mv =
- regulator_get_voltage(st->vref[refsel]);
- /* Conversion from uV to mV */
- st->channel_config[channel_number].vref_mv /= 1000;
- break;
- case AD7124_INT_REF:
- st->channel_config[channel_number].vref_mv = 2500;
- st->adc_control &= ~AD7124_ADC_CTRL_REF_EN_MSK;
- st->adc_control |= AD7124_ADC_CTRL_REF_EN(1);
- return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL,
- 2, st->adc_control);
- default:
- dev_err(&st->sd.spi->dev, "Invalid reference %d\n", refsel);
- return -EINVAL;
- }
-
- return 0;
-}
-
static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
struct device_node *np)
{
struct ad7124_state *st = iio_priv(indio_dev);
+ struct ad7124_channel_config *cfg;
+ struct ad7124_channel *channels;
struct device_node *child;
struct iio_chan_spec *chan;
- struct ad7124_channel_config *chan_config;
unsigned int ain[2], channel = 0, tmp;
int ret;
@@ -602,16 +755,18 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
if (!chan)
return -ENOMEM;
- chan_config = devm_kcalloc(indio_dev->dev.parent, st->num_channels,
- sizeof(*chan_config), GFP_KERNEL);
- if (!chan_config)
+ channels = devm_kcalloc(indio_dev->dev.parent, st->num_channels, sizeof(*channels),
+ GFP_KERNEL);
+ if (!channels)
return -ENOMEM;
indio_dev->channels = chan;
indio_dev->num_channels = st->num_channels;
- st->channel_config = chan_config;
+ st->channels = channels;
for_each_available_child_of_node(np, child) {
+ cfg = &st->channels[channel].cfg;
+
ret = of_property_read_u32(child, "reg", &channel);
if (ret)
goto err;
@@ -621,21 +776,20 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
if (ret)
goto err;
- st->channel_config[channel].ain = AD7124_CHANNEL_AINP(ain[0]) |
+ st->channels[channel].nr = channel;
+ st->channels[channel].ain = AD7124_CHANNEL_AINP(ain[0]) |
AD7124_CHANNEL_AINM(ain[1]);
- st->channel_config[channel].bipolar =
- of_property_read_bool(child, "bipolar");
+
+ cfg->bipolar = of_property_read_bool(child, "bipolar");
ret = of_property_read_u32(child, "adi,reference-select", &tmp);
if (ret)
- st->channel_config[channel].refsel = AD7124_INT_REF;
+ cfg->refsel = AD7124_INT_REF;
else
- st->channel_config[channel].refsel = tmp;
+ cfg->refsel = tmp;
- st->channel_config[channel].buf_positive =
- of_property_read_bool(child, "adi,buffered-positive");
- st->channel_config[channel].buf_negative =
- of_property_read_bool(child, "adi,buffered-negative");
+ cfg->buf_positive = of_property_read_bool(child, "adi,buffered-positive");
+ cfg->buf_negative = of_property_read_bool(child, "adi,buffered-negative");
chan[channel] = ad7124_channel_template;
chan[channel].address = channel;
@@ -653,8 +807,8 @@ err:
static int ad7124_setup(struct ad7124_state *st)
{
- unsigned int val, fclk, power_mode;
- int i, ret, tmp;
+ unsigned int fclk, power_mode;
+ int i, ret;
fclk = clk_get_rate(st->mclk);
if (!fclk)
@@ -677,31 +831,20 @@ static int ad7124_setup(struct ad7124_state *st)
if (ret < 0)
return ret;
+ mutex_init(&st->cfgs_lock);
+ INIT_KFIFO(st->live_cfgs_fifo);
for (i = 0; i < st->num_channels; i++) {
- val = st->channel_config[i].ain | AD7124_CHANNEL_SETUP(i);
- ret = ad_sd_write_reg(&st->sd, AD7124_CHANNEL(i), 2, val);
- if (ret < 0)
- return ret;
- ret = ad7124_init_channel_vref(st, i);
+ ret = ad7124_init_config_vref(st, &st->channels[i].cfg);
if (ret < 0)
return ret;
- tmp = (st->channel_config[i].buf_positive << 1) +
- st->channel_config[i].buf_negative;
-
- val = AD7124_CONFIG_BIPOLAR(st->channel_config[i].bipolar) |
- AD7124_CONFIG_REF_SEL(st->channel_config[i].refsel) |
- AD7124_CONFIG_IN_BUFF(tmp);
- ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(i), 2, val);
- if (ret < 0)
- return ret;
/*
* 9.38 SPS is the minimum output data rate supported
* regardless of the selected power mode. Round it up to 10 and
- * set all the enabled channels to this default value.
+ * set all channels to this default value.
*/
- ret = ad7124_set_channel_odr(st, i, 10);
+ ad7124_set_channel_odr(st, i, 10);
}
return ret;
diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c
index 70e33dd1c9f7..3271a31afde1 100644
--- a/drivers/iio/adc/ad7292.c
+++ b/drivers/iio/adc/ad7292.c
@@ -260,7 +260,7 @@ static int ad7292_probe(struct spi_device *spi)
struct ad7292_state *st;
struct iio_dev *indio_dev;
struct device_node *child;
- bool diff_channels = 0;
+ bool diff_channels = false;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index ee7b108688b3..0af0bb4d5a7f 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -668,7 +668,6 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
return -ENOMEM;
st->trig->ops = &ad7606_trigger_ops;
- st->trig->dev.parent = dev;
iio_trigger_set_drvdata(st->trig, indio_dev);
ret = devm_iio_trigger_register(dev, st->trig);
if (ret)
diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c
index b6b6765be7b4..829a3426f235 100644
--- a/drivers/iio/adc/ad7766.c
+++ b/drivers/iio/adc/ad7766.c
@@ -253,7 +253,6 @@ static int ad7766_probe(struct spi_device *spi)
return -ENOMEM;
ad7766->trig->ops = &ad7766_trigger_ops;
- ad7766->trig->dev.parent = &spi->dev;
iio_trigger_set_drvdata(ad7766->trig, ad7766);
ret = devm_request_irq(&spi->dev, spi->irq, ad7766_irq,
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index 5c0cbee03230..c945f1349623 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -631,7 +631,6 @@ static int ad7768_probe(struct spi_device *spi)
return -ENOMEM;
st->trig->ops = &ad7768_trigger_ops;
- st->trig->dev.parent = &spi->dev;
iio_trigger_set_drvdata(st->trig, indio_dev);
ret = devm_iio_trigger_register(&spi->dev, st->trig);
if (ret)
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 3a6f239d4acc..9289812c0a94 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -475,8 +475,9 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev)
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
int ret;
- sigma_delta->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
- indio_dev->id);
+ sigma_delta->trig = iio_trigger_alloc(&sigma_delta->spi->dev,
+ "%s-dev%d", indio_dev->name,
+ indio_dev->id);
if (sigma_delta->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -496,7 +497,6 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev)
sigma_delta->irq_dis = true;
disable_irq_nosync(sigma_delta->spi->irq);
}
- sigma_delta->trig->dev.parent = &sigma_delta->spi->dev;
iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
ret = iio_trigger_register(sigma_delta->trig);
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index 9109da2d2e15..d5f6ffc5b5bc 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -23,7 +23,7 @@
#include <linux/fpga/adi-axi-common.h>
#include <linux/iio/adc/adi-axi-adc.h>
-/**
+/*
* Register definitions:
* https://wiki.analog.com/resources/fpga/docs/axi_adc_ip#register_map
*/
@@ -104,7 +104,6 @@ static unsigned int adi_axi_adc_read(struct adi_axi_adc_state *st,
static int adi_axi_adc_config_dma_buffer(struct device *dev,
struct iio_dev *indio_dev)
{
- struct iio_buffer *buffer;
const char *dma_name;
if (!device_property_present(dev, "dmas"))
@@ -113,15 +112,8 @@ static int adi_axi_adc_config_dma_buffer(struct device *dev,
if (device_property_read_string(dev, "dma-names", &dma_name))
dma_name = "rx";
- buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent,
- dma_name);
- if (IS_ERR(buffer))
- return PTR_ERR(buffer);
-
- indio_dev->modes |= INDIO_BUFFER_HARDWARE;
- iio_device_attach_buffer(indio_dev, buffer);
-
- return 0;
+ return devm_iio_dmaengine_buffer_setup(indio_dev->dev.parent,
+ indio_dev, dma_name);
}
static int adi_axi_adc_read_raw(struct iio_dev *indio_dev,
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 70750abb5dea..0b5f0c91d0d7 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -625,12 +625,11 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
struct iio_trigger *trig;
int ret;
- trig = iio_trigger_alloc("%s-dev%d-%s", idev->name,
+ trig = iio_trigger_alloc(idev->dev.parent, "%s-dev%d-%s", idev->name,
idev->id, trigger->name);
if (trig == NULL)
return NULL;
- trig->dev.parent = idev->dev.parent;
iio_trigger_set_drvdata(trig, idev);
trig->ops = &at91_adc_trigger_ops;
diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c
index f19c9aa93f17..40e59f4c95bc 100644
--- a/drivers/iio/adc/cpcap-adc.c
+++ b/drivers/iio/adc/cpcap-adc.c
@@ -100,7 +100,7 @@ struct cpcap_adc_ato {
};
/**
- * struct cpcap-adc - cpcap adc device driver data
+ * struct cpcap_adc - cpcap adc device driver data
* @reg: cpcap regmap
* @dev: struct device
* @vendor: cpcap vendor
diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c
index b573ec60a8b8..2ae54258b221 100644
--- a/drivers/iio/adc/ina2xx-adc.c
+++ b/drivers/iio/adc/ina2xx-adc.c
@@ -953,7 +953,6 @@ static int ina2xx_probe(struct i2c_client *client,
{
struct ina2xx_chip_info *chip;
struct iio_dev *indio_dev;
- struct iio_buffer *buffer;
unsigned int val;
enum ina2xx_ids type;
int ret;
@@ -1017,7 +1016,7 @@ static int ina2xx_probe(struct i2c_client *client,
return ret;
}
- indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+ indio_dev->modes = INDIO_DIRECT_MODE;
if (id->driver_data == ina226) {
indio_dev->channels = ina226_channels;
indio_dev->num_channels = ARRAY_SIZE(ina226_channels);
@@ -1028,13 +1027,12 @@ static int ina2xx_probe(struct i2c_client *client,
indio_dev->info = &ina219_info;
}
indio_dev->name = id->name;
- indio_dev->setup_ops = &ina2xx_setup_ops;
- buffer = devm_iio_kfifo_allocate(&indio_dev->dev);
- if (!buffer)
- return -ENOMEM;
-
- iio_device_attach_buffer(indio_dev, buffer);
+ ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &ina2xx_setup_ops);
+ if (ret)
+ return ret;
return iio_device_register(indio_dev);
}
diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c
index ca1dff3924ff..e3c8ec107722 100644
--- a/drivers/iio/adc/max1027.c
+++ b/drivers/iio/adc/max1027.c
@@ -473,7 +473,6 @@ static int max1027_probe(struct spi_device *spi)
}
st->trig->ops = &max1027_trigger_ops;
- st->trig->dev.parent = &spi->dev;
iio_trigger_set_drvdata(st->trig, indio_dev);
ret = devm_iio_trigger_register(&indio_dev->dev,
st->trig);
diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c
index f57db3056fbe..6b39a139ce28 100644
--- a/drivers/iio/adc/mt6360-adc.c
+++ b/drivers/iio/adc/mt6360-adc.c
@@ -9,13 +9,14 @@
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
-#include <linux/unaligned/be_byteshift.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
+#include <asm/unaligned.h>
+
#define MT6360_REG_PMUCHGCTRL3 0x313
#define MT6360_REG_PMUADCCFG 0x356
#define MT6360_REG_PMUADCIDLET 0x358
diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c
index d9d105920001..f7bc0bb7f112 100644
--- a/drivers/iio/adc/npcm_adc.c
+++ b/drivers/iio/adc/npcm_adc.c
@@ -25,6 +25,15 @@ struct npcm_adc {
wait_queue_head_t wq;
struct regulator *vref;
struct reset_control *reset;
+ /*
+ * Lock to protect the device state during a potential concurrent
+ * 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
+ * has finished.
+ */
+ struct mutex lock;
};
/* ADC registers */
@@ -135,9 +144,9 @@ static int npcm_adc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&info->lock);
ret = npcm_adc_read(info, val, chan->channel);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&info->lock);
if (ret) {
dev_err(info->dev, "NPCM ADC read failed\n");
return ret;
@@ -187,6 +196,8 @@ static int npcm_adc_probe(struct platform_device *pdev)
return -ENOMEM;
info = iio_priv(indio_dev);
+ mutex_init(&info->lock);
+
info->dev = &pdev->dev;
info->regs = devm_platform_ioremap_resource(pdev, 0);
diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c
index 889b88768b63..6ef09609be9f 100644
--- a/drivers/iio/adc/palmas_gpadc.c
+++ b/drivers/iio/adc/palmas_gpadc.c
@@ -90,6 +90,12 @@ static struct palmas_gpadc_info palmas_gpadc_info[] = {
* 3: 800 uA
* @extended_delay: enable the gpadc extended delay mode
* @auto_conversion_period: define the auto_conversion_period
+ * @lock: Lock to protect the device state during a potential concurrent
+ * read access from userspace. Reading a raw value requires a sequence
+ * 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.
*
* This is the palmas_gpadc structure to store run-time information
* and pointers for this driver instance.
@@ -110,6 +116,7 @@ struct palmas_gpadc {
bool wakeup1_enable;
bool wakeup2_enable;
int auto_conversion_period;
+ struct mutex lock;
};
/*
@@ -388,7 +395,7 @@ static int palmas_gpadc_read_raw(struct iio_dev *indio_dev,
if (adc_chan > PALMAS_ADC_CH_MAX)
return -EINVAL;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -414,12 +421,12 @@ static int palmas_gpadc_read_raw(struct iio_dev *indio_dev,
goto out;
}
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&adc->lock);
return ret;
out:
palmas_gpadc_read_done(adc, adc_chan);
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&adc->lock);
return ret;
}
@@ -516,8 +523,11 @@ static int palmas_gpadc_probe(struct platform_device *pdev)
adc->dev = &pdev->dev;
adc->palmas = dev_get_drvdata(pdev->dev.parent);
adc->adc_info = palmas_gpadc_info;
+
+ mutex_init(&adc->lock);
+
init_completion(&adc->conv_completion);
- dev_set_drvdata(&pdev->dev, indio_dev);
+ platform_set_drvdata(pdev, indio_dev);
adc->auto_conversion_period = gpadc_pdata->auto_conversion_period_ms;
adc->irq = palmas_irq_get_virq(adc->palmas, PALMAS_GPADC_EOC_SW_IRQ);
diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c
index 1bc986a7009d..d93e580b3dc5 100644
--- a/drivers/iio/adc/spear_adc.c
+++ b/drivers/iio/adc/spear_adc.c
@@ -75,6 +75,15 @@ struct spear_adc_state {
struct adc_regs_spear6xx __iomem *adc_base_spear6xx;
struct clk *clk;
struct completion completion;
+ /*
+ * Lock to protect the device state during a potential concurrent
+ * read access from userspace. Reading a raw value requires a sequence
+ * 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.
+ */
+ struct mutex lock;
u32 current_clk;
u32 sampling_freq;
u32 avg_samples;
@@ -146,7 +155,7 @@ static int spear_adc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) |
SPEAR_ADC_STATUS_AVG_SAMPLE(st->avg_samples) |
@@ -159,7 +168,7 @@ static int spear_adc_read_raw(struct iio_dev *indio_dev,
wait_for_completion(&st->completion); /* set by ISR */
*val = st->value;
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return IIO_VAL_INT;
@@ -187,7 +196,7 @@ static int spear_adc_write_raw(struct iio_dev *indio_dev,
if (mask != IIO_CHAN_INFO_SAMP_FREQ)
return -EINVAL;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
if ((val < SPEAR_ADC_CLK_MIN) ||
(val > SPEAR_ADC_CLK_MAX) ||
@@ -199,7 +208,7 @@ static int spear_adc_write_raw(struct iio_dev *indio_dev,
spear_adc_set_clk(st, val);
out:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
}
@@ -271,6 +280,9 @@ static int spear_adc_probe(struct platform_device *pdev)
}
st = iio_priv(indio_dev);
+
+ mutex_init(&st->lock);
+
st->np = np;
/*
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index f7c53cea509a..b25386b19373 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -177,7 +177,7 @@ struct stm32_adc_cfg {
* @offset: ADC instance register offset in ADC block
* @cfg: compatible configuration data
* @completion: end of single conversion completion
- * @buffer: data buffer
+ * @buffer: data buffer + 8 bytes for timestamp if enabled
* @clk: clock for this adc instance
* @irq: interrupt for this adc instance
* @lock: spinlock
@@ -200,7 +200,7 @@ struct stm32_adc {
u32 offset;
const struct stm32_adc_cfg *cfg;
struct completion completion;
- u16 buffer[STM32_ADC_MAX_SQ];
+ u16 buffer[STM32_ADC_MAX_SQ + 4] __aligned(8);
struct clk *clk;
int irq;
spinlock_t lock; /* interrupt lock */
@@ -1714,7 +1714,7 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
}
}
-static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
+static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping)
{
struct device_node *node = indio_dev->dev.of_node;
struct stm32_adc *adc = iio_priv(indio_dev);
@@ -1762,6 +1762,9 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
return -EINVAL;
}
+ if (timestamping)
+ num_channels++;
+
channels = devm_kcalloc(&indio_dev->dev, num_channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
if (!channels)
@@ -1812,6 +1815,19 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
stm32_adc_smpr_init(adc, channels[i].channel, smp);
}
+ 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;
+
+ scan_index++;
+ }
+
indio_dev->num_channels = scan_index;
indio_dev->channels = channels;
@@ -1871,6 +1887,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
irqreturn_t (*handler)(int irq, void *p) = NULL;
struct stm32_adc *adc;
+ bool timestamping = false;
int ret;
if (!pdev->dev.of_node)
@@ -1927,16 +1944,22 @@ static int stm32_adc_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- ret = stm32_adc_chan_of_init(indio_dev);
- if (ret < 0)
- return ret;
-
ret = stm32_adc_dma_request(dev, indio_dev);
if (ret < 0)
return ret;
- if (!adc->dma_chan)
+ if (!adc->dma_chan) {
+ /* For PIO mode only, iio_pollfunc_store_time stores a timestamp
+ * in the primary trigger IRQ handler and stm32_adc_trigger_handler
+ * runs in the IRQ thread to push out buffer along with timestamp.
+ */
handler = &stm32_adc_trigger_handler;
+ timestamping = true;
+ }
+
+ ret = stm32_adc_chan_of_init(indio_dev, timestamping);
+ if (ret < 0)
+ goto err_dma_disable;
ret = iio_triggered_buffer_setup(indio_dev,
&iio_pollfunc_store_time, handler,
diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c
index fb14b92fa6e7..33aea961d850 100644
--- a/drivers/iio/adc/ti-adc084s021.c
+++ b/drivers/iio/adc/ti-adc084s021.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* Copyright (C) 2017 Axis Communications AB
*
* Driver for Texas Instruments' ADC084S021 ADC chip.
@@ -65,7 +65,7 @@ static const struct iio_chan_spec adc084s021_channels[] = {
};
/**
- * Read an ADC channel and return its value.
+ * adc084s021_adc_conversion() - Read an ADC channel and return its value.
*
* @adc: The ADC SPI data.
* @data: Buffer for converted data.
@@ -136,7 +136,7 @@ static int adc084s021_read_raw(struct iio_dev *indio_dev,
}
/**
- * Read enabled ADC channels and push data to the buffer.
+ * adc084s021_buffer_trigger_handler() - Read ADC channels and push to buffer.
*
* @irq: The interrupt number (not used).
* @pollfunc: Pointer to the poll func.
diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c
new file mode 100644
index 000000000000..0060d5f0abb0
--- /dev/null
+++ b/drivers/iio/adc/ti-ads131e08.c
@@ -0,0 +1,948 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments ADS131E0x 4-, 6- and 8-Channel ADCs
+ *
+ * Copyright (c) 2020 AVL DiTEST GmbH
+ * Tomislav Denis <tomislav.denis@avl.com>
+ *
+ * Datasheet: https://www.ti.com/lit/ds/symlink/ads131e08.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.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 <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <asm/unaligned.h>
+
+/* Commands */
+#define ADS131E08_CMD_RESET 0x06
+#define ADS131E08_CMD_START 0x08
+#define ADS131E08_CMD_STOP 0x0A
+#define ADS131E08_CMD_OFFSETCAL 0x1A
+#define ADS131E08_CMD_SDATAC 0x11
+#define ADS131E08_CMD_RDATA 0x12
+#define ADS131E08_CMD_RREG(r) (BIT(5) | (r & GENMASK(4, 0)))
+#define ADS131E08_CMD_WREG(r) (BIT(6) | (r & GENMASK(4, 0)))
+
+/* Registers */
+#define ADS131E08_ADR_CFG1R 0x01
+#define ADS131E08_ADR_CFG3R 0x03
+#define ADS131E08_ADR_CH0R 0x05
+
+/* Configuration register 1 */
+#define ADS131E08_CFG1R_DR_MASK GENMASK(2, 0)
+
+/* Configuration register 3 */
+#define ADS131E08_CFG3R_PDB_REFBUF_MASK BIT(7)
+#define ADS131E08_CFG3R_VREF_4V_MASK BIT(5)
+
+/* Channel settings register */
+#define ADS131E08_CHR_GAIN_MASK GENMASK(6, 4)
+#define ADS131E08_CHR_MUX_MASK GENMASK(2, 0)
+#define ADS131E08_CHR_PWD_MASK BIT(7)
+
+/* ADC misc */
+#define ADS131E08_DEFAULT_DATA_RATE 1
+#define ADS131E08_DEFAULT_PGA_GAIN 1
+#define ADS131E08_DEFAULT_MUX 0
+
+#define ADS131E08_VREF_2V4_mV 2400
+#define ADS131E08_VREF_4V_mV 4000
+
+#define ADS131E08_WAIT_RESET_CYCLES 18
+#define ADS131E08_WAIT_SDECODE_CYCLES 4
+#define ADS131E08_WAIT_OFFSETCAL_MS 153
+#define ADS131E08_MAX_SETTLING_TIME_MS 6
+
+#define ADS131E08_NUM_STATUS_BYTES 3
+#define ADS131E08_NUM_DATA_BYTES_MAX 24
+#define ADS131E08_NUM_DATA_BYTES(dr) (((dr) >= 32) ? 2 : 3)
+#define ADS131E08_NUM_DATA_BITS(dr) (ADS131E08_NUM_DATA_BYTES(dr) * 8)
+#define ADS131E08_NUM_STORAGE_BYTES 4
+
+enum ads131e08_ids {
+ ads131e04,
+ ads131e06,
+ ads131e08,
+};
+
+struct ads131e08_info {
+ unsigned int max_channels;
+ const char *name;
+};
+
+struct ads131e08_channel_config {
+ unsigned int pga_gain;
+ unsigned int mux;
+};
+
+struct ads131e08_state {
+ const struct ads131e08_info *info;
+ struct spi_device *spi;
+ struct iio_trigger *trig;
+ struct clk *adc_clk;
+ struct regulator *vref_reg;
+ struct ads131e08_channel_config *channel_config;
+ unsigned int data_rate;
+ unsigned int vref_mv;
+ unsigned int sdecode_delay_us;
+ unsigned int reset_delay_us;
+ unsigned int readback_len;
+ struct completion completion;
+ struct {
+ u8 data[ADS131E08_NUM_DATA_BYTES_MAX];
+ s64 ts __aligned(8);
+ } tmp_buf;
+
+ u8 tx_buf[3] ____cacheline_aligned;
+ /*
+ * Add extra one padding byte to be able to access the last channel
+ * value using u32 pointer
+ */
+ u8 rx_buf[ADS131E08_NUM_STATUS_BYTES +
+ ADS131E08_NUM_DATA_BYTES_MAX + 1];
+};
+
+static const struct ads131e08_info ads131e08_info_tbl[] = {
+ [ads131e04] = {
+ .max_channels = 4,
+ .name = "ads131e04",
+ },
+ [ads131e06] = {
+ .max_channels = 6,
+ .name = "ads131e06",
+ },
+ [ads131e08] = {
+ .max_channels = 8,
+ .name = "ads131e08",
+ },
+};
+
+struct ads131e08_data_rate_desc {
+ unsigned int rate; /* data rate in kSPS */
+ u8 reg; /* reg value */
+};
+
+static const struct ads131e08_data_rate_desc ads131e08_data_rate_tbl[] = {
+ { .rate = 64, .reg = 0x00 },
+ { .rate = 32, .reg = 0x01 },
+ { .rate = 16, .reg = 0x02 },
+ { .rate = 8, .reg = 0x03 },
+ { .rate = 4, .reg = 0x04 },
+ { .rate = 2, .reg = 0x05 },
+ { .rate = 1, .reg = 0x06 },
+};
+
+struct ads131e08_pga_gain_desc {
+ unsigned int gain; /* PGA gain value */
+ u8 reg; /* field value */
+};
+
+static const struct ads131e08_pga_gain_desc ads131e08_pga_gain_tbl[] = {
+ { .gain = 1, .reg = 0x01 },
+ { .gain = 2, .reg = 0x02 },
+ { .gain = 4, .reg = 0x04 },
+ { .gain = 8, .reg = 0x05 },
+ { .gain = 12, .reg = 0x06 },
+};
+
+static const u8 ads131e08_valid_channel_mux_values[] = { 0, 1, 3, 4 };
+
+static int ads131e08_exec_cmd(struct ads131e08_state *st, u8 cmd)
+{
+ int ret;
+
+ ret = spi_write_then_read(st->spi, &cmd, 1, NULL, 0);
+ if (ret)
+ dev_err(&st->spi->dev, "Exec cmd(%02x) failed\n", cmd);
+
+ return ret;
+}
+
+static int ads131e08_read_reg(struct ads131e08_state *st, u8 reg)
+{
+ int ret;
+ struct spi_transfer transfer[] = {
+ {
+ .tx_buf = &st->tx_buf,
+ .len = 2,
+ .delay_usecs = st->sdecode_delay_us,
+ }, {
+ .rx_buf = &st->rx_buf,
+ .len = 1,
+ },
+ };
+
+ st->tx_buf[0] = ADS131E08_CMD_RREG(reg);
+ st->tx_buf[1] = 0;
+
+ ret = spi_sync_transfer(st->spi, transfer, ARRAY_SIZE(transfer));
+ if (ret) {
+ dev_err(&st->spi->dev, "Read register failed\n");
+ return ret;
+ }
+
+ return st->rx_buf[0];
+}
+
+static int ads131e08_write_reg(struct ads131e08_state *st, u8 reg, u8 value)
+{
+ int ret;
+ struct spi_transfer transfer[] = {
+ {
+ .tx_buf = &st->tx_buf,
+ .len = 3,
+ .delay_usecs = st->sdecode_delay_us,
+ }
+ };
+
+ st->tx_buf[0] = ADS131E08_CMD_WREG(reg);
+ st->tx_buf[1] = 0;
+ st->tx_buf[2] = value;
+
+ ret = spi_sync_transfer(st->spi, transfer, ARRAY_SIZE(transfer));
+ if (ret)
+ dev_err(&st->spi->dev, "Write register failed\n");
+
+ return ret;
+}
+
+static int ads131e08_read_data(struct ads131e08_state *st, int rx_len)
+{
+ int ret;
+ struct spi_transfer transfer[] = {
+ {
+ .tx_buf = &st->tx_buf,
+ .len = 1,
+ }, {
+ .rx_buf = &st->rx_buf,
+ .len = rx_len,
+ },
+ };
+
+ st->tx_buf[0] = ADS131E08_CMD_RDATA;
+
+ ret = spi_sync_transfer(st->spi, transfer, ARRAY_SIZE(transfer));
+ if (ret)
+ dev_err(&st->spi->dev, "Read data failed\n");
+
+ return ret;
+}
+
+static int ads131e08_set_data_rate(struct ads131e08_state *st, int data_rate)
+{
+ int i, reg, ret;
+
+ for (i = 0; i < ARRAY_SIZE(ads131e08_data_rate_tbl); i++) {
+ if (ads131e08_data_rate_tbl[i].rate == data_rate)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(ads131e08_data_rate_tbl)) {
+ dev_err(&st->spi->dev, "invalid data rate value\n");
+ return -EINVAL;
+ }
+
+ reg = ads131e08_read_reg(st, ADS131E08_ADR_CFG1R);
+ if (reg < 0)
+ return reg;
+
+ reg &= ~ADS131E08_CFG1R_DR_MASK;
+ reg |= FIELD_PREP(ADS131E08_CFG1R_DR_MASK,
+ ads131e08_data_rate_tbl[i].reg);
+
+ ret = ads131e08_write_reg(st, ADS131E08_ADR_CFG1R, reg);
+ if (ret)
+ return ret;
+
+ st->data_rate = data_rate;
+ st->readback_len = ADS131E08_NUM_STATUS_BYTES +
+ ADS131E08_NUM_DATA_BYTES(st->data_rate) *
+ st->info->max_channels;
+
+ return 0;
+}
+
+static int ads131e08_pga_gain_to_field_value(struct ads131e08_state *st,
+ unsigned int pga_gain)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ads131e08_pga_gain_tbl); i++) {
+ if (ads131e08_pga_gain_tbl[i].gain == pga_gain)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(ads131e08_pga_gain_tbl)) {
+ dev_err(&st->spi->dev, "invalid PGA gain value\n");
+ return -EINVAL;
+ }
+
+ return ads131e08_pga_gain_tbl[i].reg;
+}
+
+static int ads131e08_set_pga_gain(struct ads131e08_state *st,
+ unsigned int channel, unsigned int pga_gain)
+{
+ int field_value, reg;
+
+ field_value = ads131e08_pga_gain_to_field_value(st, pga_gain);
+ if (field_value < 0)
+ return field_value;
+
+ reg = ads131e08_read_reg(st, ADS131E08_ADR_CH0R + channel);
+ if (reg < 0)
+ return reg;
+
+ reg &= ~ADS131E08_CHR_GAIN_MASK;
+ reg |= FIELD_PREP(ADS131E08_CHR_GAIN_MASK, field_value);
+
+ return ads131e08_write_reg(st, ADS131E08_ADR_CH0R + channel, reg);
+}
+
+static int ads131e08_validate_channel_mux(struct ads131e08_state *st,
+ unsigned int mux)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ads131e08_valid_channel_mux_values); i++) {
+ if (ads131e08_valid_channel_mux_values[i] == mux)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(ads131e08_valid_channel_mux_values)) {
+ dev_err(&st->spi->dev, "invalid channel mux value\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ads131e08_set_channel_mux(struct ads131e08_state *st,
+ unsigned int channel, unsigned int mux)
+{
+ int reg;
+
+ reg = ads131e08_read_reg(st, ADS131E08_ADR_CH0R + channel);
+ if (reg < 0)
+ return reg;
+
+ reg &= ~ADS131E08_CHR_MUX_MASK;
+ reg |= FIELD_PREP(ADS131E08_CHR_MUX_MASK, mux);
+
+ return ads131e08_write_reg(st, ADS131E08_ADR_CH0R + channel, reg);
+}
+
+static int ads131e08_power_down_channel(struct ads131e08_state *st,
+ unsigned int channel, bool value)
+{
+ int reg;
+
+ reg = ads131e08_read_reg(st, ADS131E08_ADR_CH0R + channel);
+ if (reg < 0)
+ return reg;
+
+ reg &= ~ADS131E08_CHR_PWD_MASK;
+ reg |= FIELD_PREP(ADS131E08_CHR_PWD_MASK, value);
+
+ return ads131e08_write_reg(st, ADS131E08_ADR_CH0R + channel, reg);
+}
+
+static int ads131e08_config_reference_voltage(struct ads131e08_state *st)
+{
+ int reg;
+
+ reg = ads131e08_read_reg(st, ADS131E08_ADR_CFG3R);
+ if (reg < 0)
+ return reg;
+
+ reg &= ~ADS131E08_CFG3R_PDB_REFBUF_MASK;
+ if (!st->vref_reg) {
+ reg |= FIELD_PREP(ADS131E08_CFG3R_PDB_REFBUF_MASK, 1);
+ reg &= ~ADS131E08_CFG3R_VREF_4V_MASK;
+ reg |= FIELD_PREP(ADS131E08_CFG3R_VREF_4V_MASK,
+ st->vref_mv == ADS131E08_VREF_4V_mV);
+ }
+
+ return ads131e08_write_reg(st, ADS131E08_ADR_CFG3R, reg);
+}
+
+static int ads131e08_initial_config(struct iio_dev *indio_dev)
+{
+ const struct iio_chan_spec *channel = indio_dev->channels;
+ struct ads131e08_state *st = iio_priv(indio_dev);
+ unsigned long active_channels = 0;
+ int ret, i;
+
+ ret = ads131e08_exec_cmd(st, ADS131E08_CMD_RESET);
+ if (ret)
+ return ret;
+
+ udelay(st->reset_delay_us);
+
+ /* Disable read data in continuous mode (enabled by default) */
+ ret = ads131e08_exec_cmd(st, ADS131E08_CMD_SDATAC);
+ if (ret)
+ return ret;
+
+ ret = ads131e08_set_data_rate(st, ADS131E08_DEFAULT_DATA_RATE);
+ if (ret)
+ return ret;
+
+ ret = ads131e08_config_reference_voltage(st);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ ret = ads131e08_set_pga_gain(st, channel->channel,
+ st->channel_config[i].pga_gain);
+ if (ret)
+ return ret;
+
+ ret = ads131e08_set_channel_mux(st, channel->channel,
+ st->channel_config[i].mux);
+ if (ret)
+ return ret;
+
+ active_channels |= BIT(channel->channel);
+ channel++;
+ }
+
+ /* Power down unused channels */
+ for_each_clear_bit(i, &active_channels, st->info->max_channels) {
+ ret = ads131e08_power_down_channel(st, i, true);
+ if (ret)
+ return ret;
+ }
+
+ /* Request channel offset calibration */
+ ret = ads131e08_exec_cmd(st, ADS131E08_CMD_OFFSETCAL);
+ if (ret)
+ return ret;
+
+ /*
+ * Channel offset calibration is triggered with the first START
+ * command. Since calibration takes more time than settling operation,
+ * this causes timeout error when command START is sent first
+ * time (e.g. first call of the ads131e08_read_direct method).
+ * To avoid this problem offset calibration is triggered here.
+ */
+ ret = ads131e08_exec_cmd(st, ADS131E08_CMD_START);
+ if (ret)
+ return ret;
+
+ msleep(ADS131E08_WAIT_OFFSETCAL_MS);
+
+ return ads131e08_exec_cmd(st, ADS131E08_CMD_STOP);
+}
+
+static int ads131e08_pool_data(struct ads131e08_state *st)
+{
+ unsigned long timeout;
+ int ret;
+
+ reinit_completion(&st->completion);
+
+ ret = ads131e08_exec_cmd(st, ADS131E08_CMD_START);
+ if (ret)
+ return ret;
+
+ timeout = msecs_to_jiffies(ADS131E08_MAX_SETTLING_TIME_MS);
+ ret = wait_for_completion_timeout(&st->completion, timeout);
+ if (!ret)
+ return -ETIMEDOUT;
+
+ ret = ads131e08_read_data(st, st->readback_len);
+ if (ret)
+ return ret;
+
+ return ads131e08_exec_cmd(st, ADS131E08_CMD_STOP);
+}
+
+static int ads131e08_read_direct(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *value)
+{
+ struct ads131e08_state *st = iio_priv(indio_dev);
+ u8 num_bits, *src;
+ int ret;
+
+ ret = ads131e08_pool_data(st);
+ if (ret)
+ return ret;
+
+ src = st->rx_buf + ADS131E08_NUM_STATUS_BYTES +
+ channel->channel * ADS131E08_NUM_DATA_BYTES(st->data_rate);
+
+ num_bits = ADS131E08_NUM_DATA_BITS(st->data_rate);
+ *value = sign_extend32(get_unaligned_be32(src) >> (32 - num_bits), num_bits - 1);
+
+ return 0;
+}
+
+static int ads131e08_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *value,
+ int *value2, long mask)
+{
+ struct ads131e08_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ads131e08_read_direct(indio_dev, channel, value);
+ iio_device_release_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ if (st->vref_reg) {
+ ret = regulator_get_voltage(st->vref_reg);
+ if (ret < 0)
+ return ret;
+
+ *value = ret / 1000;
+ } else {
+ *value = st->vref_mv;
+ }
+
+ *value /= st->channel_config[channel->address].pga_gain;
+ *value2 = ADS131E08_NUM_DATA_BITS(st->data_rate) - 1;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *value = st->data_rate;
+
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ads131e08_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int value,
+ int value2, long mask)
+{
+ struct ads131e08_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ads131e08_set_data_rate(st, value);
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1 2 4 8 16 32 64");
+
+static struct attribute *ads131e08_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ads131e08_attribute_group = {
+ .attrs = ads131e08_attributes,
+};
+
+static int ads131e08_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval, unsigned int *readval)
+{
+ struct ads131e08_state *st = iio_priv(indio_dev);
+
+ if (readval) {
+ int ret = ads131e08_read_reg(st, reg);
+ *readval = ret;
+ return ret;
+ }
+
+ return ads131e08_write_reg(st, reg, writeval);
+}
+
+static const struct iio_info ads131e08_iio_info = {
+ .read_raw = ads131e08_read_raw,
+ .write_raw = ads131e08_write_raw,
+ .attrs = &ads131e08_attribute_group,
+ .debugfs_reg_access = &ads131e08_debugfs_reg_access,
+};
+
+static int ads131e08_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct ads131e08_state *st = iio_priv(indio_dev);
+ u8 cmd = state ? ADS131E08_CMD_START : ADS131E08_CMD_STOP;
+
+ return ads131e08_exec_cmd(st, cmd);
+}
+
+static const struct iio_trigger_ops ads131e08_trigger_ops = {
+ .set_trigger_state = &ads131e08_set_trigger_state,
+ .validate_device = &iio_trigger_validate_own_device,
+};
+
+static irqreturn_t ads131e08_trigger_handler(int irq, void *private)
+{
+ struct iio_poll_func *pf = private;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ads131e08_state *st = iio_priv(indio_dev);
+ unsigned int chn, i = 0;
+ u8 *src, *dest;
+ int ret;
+
+ /*
+ * The number of data bits per channel depends on the data rate.
+ * For 32 and 64 ksps data rates, number of data bits per channel
+ * is 16. This case is not compliant with used (fixed) scan element
+ * type (be:s24/32>>8). So we use a little tweak to pack properly
+ * 16 bits of data into the buffer.
+ */
+ unsigned int num_bytes = ADS131E08_NUM_DATA_BYTES(st->data_rate);
+ u8 tweek_offset = num_bytes == 2 ? 1 : 0;
+
+ if (iio_trigger_using_own(indio_dev))
+ ret = ads131e08_read_data(st, st->readback_len);
+ else
+ ret = ads131e08_pool_data(st);
+
+ if (ret)
+ goto out;
+
+ for_each_set_bit(chn, indio_dev->active_scan_mask, indio_dev->masklength) {
+ src = st->rx_buf + ADS131E08_NUM_STATUS_BYTES + chn * num_bytes;
+ dest = st->tmp_buf.data + i * ADS131E08_NUM_STORAGE_BYTES;
+
+ /*
+ * Tweek offset is 0:
+ * +---+---+---+---+
+ * |D0 |D1 |D2 | X | (3 data bytes)
+ * +---+---+---+---+
+ * a+0 a+1 a+2 a+3
+ *
+ * Tweek offset is 1:
+ * +---+---+---+---+
+ * |P0 |D0 |D1 | X | (one padding byte and 2 data bytes)
+ * +---+---+---+---+
+ * a+0 a+1 a+2 a+3
+ */
+ memcpy(dest + tweek_offset, src, num_bytes);
+
+ /*
+ * Data conversion from 16 bits of data to 24 bits of data
+ * is done by sign extension (properly filling padding byte).
+ */
+ if (tweek_offset)
+ *dest = *src & BIT(7) ? 0xff : 0x00;
+
+ i++;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, st->tmp_buf.data,
+ iio_get_time_ns(indio_dev));
+
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ads131e08_interrupt(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct ads131e08_state *st = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev))
+ iio_trigger_poll(st->trig);
+ else
+ complete(&st->completion);
+
+ return IRQ_HANDLED;
+}
+
+static int ads131e08_alloc_channels(struct iio_dev *indio_dev)
+{
+ struct ads131e08_state *st = iio_priv(indio_dev);
+ struct ads131e08_channel_config *channel_config;
+ struct device *dev = &st->spi->dev;
+ struct iio_chan_spec *channels;
+ struct fwnode_handle *node;
+ unsigned int channel, tmp;
+ int num_channels, i, ret;
+
+ ret = device_property_read_u32(dev, "ti,vref-internal", &tmp);
+ if (ret)
+ tmp = 0;
+
+ switch (tmp) {
+ case 0:
+ st->vref_mv = ADS131E08_VREF_2V4_mV;
+ break;
+ case 1:
+ st->vref_mv = ADS131E08_VREF_4V_mV;
+ break;
+ default:
+ dev_err(&st->spi->dev, "invalid internal voltage reference\n");
+ return -EINVAL;
+ }
+
+ num_channels = device_get_child_node_count(dev);
+ if (num_channels == 0) {
+ dev_err(&st->spi->dev, "no channel children\n");
+ return -ENODEV;
+ }
+
+ if (num_channels > st->info->max_channels) {
+ dev_err(&st->spi->dev, "num of channel children out of range\n");
+ return -EINVAL;
+ }
+
+ channels = devm_kcalloc(&st->spi->dev, num_channels,
+ sizeof(*channels), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ channel_config = devm_kcalloc(&st->spi->dev, num_channels,
+ sizeof(*channel_config), GFP_KERNEL);
+ if (!channel_config)
+ return -ENOMEM;
+
+ i = 0;
+ device_for_each_child_node(dev, node) {
+ ret = fwnode_property_read_u32(node, "reg", &channel);
+ if (ret)
+ return ret;
+
+ ret = fwnode_property_read_u32(node, "ti,gain", &tmp);
+ if (ret) {
+ channel_config[i].pga_gain = ADS131E08_DEFAULT_PGA_GAIN;
+ } else {
+ ret = ads131e08_pga_gain_to_field_value(st, tmp);
+ if (ret < 0)
+ return ret;
+
+ channel_config[i].pga_gain = tmp;
+ }
+
+ ret = fwnode_property_read_u32(node, "ti,mux", &tmp);
+ if (ret) {
+ channel_config[i].mux = ADS131E08_DEFAULT_MUX;
+ } else {
+ ret = ads131e08_validate_channel_mux(st, tmp);
+ if (ret)
+ return ret;
+
+ channel_config[i].mux = tmp;
+ }
+
+ channels[i].type = IIO_VOLTAGE;
+ channels[i].indexed = 1;
+ channels[i].channel = channel;
+ channels[i].address = i;
+ channels[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE);
+ channels[i].info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ);
+ channels[i].scan_index = channel;
+ channels[i].scan_type.sign = 's';
+ channels[i].scan_type.realbits = 24;
+ channels[i].scan_type.storagebits = 32;
+ channels[i].scan_type.shift = 8;
+ channels[i].scan_type.endianness = IIO_BE;
+ i++;
+ }
+
+ indio_dev->channels = channels;
+ indio_dev->num_channels = num_channels;
+ st->channel_config = channel_config;
+
+ return 0;
+}
+
+static void ads131e08_regulator_disable(void *data)
+{
+ struct ads131e08_state *st = data;
+
+ regulator_disable(st->vref_reg);
+}
+
+static void ads131e08_clk_disable(void *data)
+{
+ struct ads131e08_state *st = data;
+
+ clk_disable_unprepare(st->adc_clk);
+}
+
+static int ads131e08_probe(struct spi_device *spi)
+{
+ const struct ads131e08_info *info;
+ struct ads131e08_state *st;
+ struct iio_dev *indio_dev;
+ unsigned long adc_clk_hz;
+ unsigned long adc_clk_ns;
+ int ret;
+
+ info = device_get_match_data(&spi->dev);
+ if (!info) {
+ dev_err(&spi->dev, "failed to get match data\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev) {
+ dev_err(&spi->dev, "failed to allocate IIO device\n");
+ return -ENOMEM;
+ }
+
+ st = iio_priv(indio_dev);
+ st->info = info;
+ st->spi = spi;
+
+ ret = ads131e08_alloc_channels(indio_dev);
+ if (ret)
+ return ret;
+
+ indio_dev->name = st->info->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->info = &ads131e08_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ init_completion(&st->completion);
+
+ if (spi->irq) {
+ ret = devm_request_irq(&spi->dev, spi->irq,
+ ads131e08_interrupt,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ spi->dev.driver->name, indio_dev);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "request irq failed\n");
+ } else {
+ dev_err(&spi->dev, "data ready IRQ missing\n");
+ return -ENODEV;
+ }
+
+ st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
+ indio_dev->name, indio_dev->id);
+ if (!st->trig) {
+ dev_err(&spi->dev, "failed to allocate IIO trigger\n");
+ return -ENOMEM;
+ }
+
+ st->trig->ops = &ads131e08_trigger_ops;
+ st->trig->dev.parent = &spi->dev;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
+ ret = devm_iio_trigger_register(&spi->dev, st->trig);
+ if (ret) {
+ dev_err(&spi->dev, "failed to register IIO trigger\n");
+ return -ENOMEM;
+ }
+
+ indio_dev->trig = iio_trigger_get(st->trig);
+
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ NULL, &ads131e08_trigger_handler, NULL);
+ if (ret) {
+ dev_err(&spi->dev, "failed to setup IIO buffer\n");
+ return ret;
+ }
+
+ st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref");
+ if (!IS_ERR(st->vref_reg)) {
+ ret = regulator_enable(st->vref_reg);
+ if (ret) {
+ dev_err(&spi->dev,
+ "failed to enable external vref supply\n");
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(&spi->dev, ads131e08_regulator_disable, st);
+ if (ret)
+ return ret;
+ } else {
+ if (PTR_ERR(st->vref_reg) != -ENODEV)
+ return PTR_ERR(st->vref_reg);
+
+ st->vref_reg = NULL;
+ }
+
+ st->adc_clk = devm_clk_get(&spi->dev, "adc-clk");
+ if (IS_ERR(st->adc_clk))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->adc_clk),
+ "failed to get the ADC clock\n");
+
+ ret = clk_prepare_enable(st->adc_clk);
+ if (ret) {
+ dev_err(&spi->dev, "failed to prepare/enable the ADC clock\n");
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(&spi->dev, ads131e08_clk_disable, st);
+ if (ret)
+ return ret;
+
+ adc_clk_hz = clk_get_rate(st->adc_clk);
+ if (!adc_clk_hz) {
+ dev_err(&spi->dev, "failed to get the ADC clock rate\n");
+ return -EINVAL;
+ }
+
+ adc_clk_ns = NSEC_PER_SEC / adc_clk_hz;
+ st->sdecode_delay_us = DIV_ROUND_UP(
+ ADS131E08_WAIT_SDECODE_CYCLES * adc_clk_ns, NSEC_PER_USEC);
+ st->reset_delay_us = DIV_ROUND_UP(
+ ADS131E08_WAIT_RESET_CYCLES * adc_clk_ns, NSEC_PER_USEC);
+
+ ret = ads131e08_initial_config(indio_dev);
+ if (ret) {
+ dev_err(&spi->dev, "initial configuration failed\n");
+ return ret;
+ }
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct of_device_id ads131e08_of_match[] = {
+ { .compatible = "ti,ads131e04",
+ .data = &ads131e08_info_tbl[ads131e04], },
+ { .compatible = "ti,ads131e06",
+ .data = &ads131e08_info_tbl[ads131e06], },
+ { .compatible = "ti,ads131e08",
+ .data = &ads131e08_info_tbl[ads131e08], },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ads131e08_of_match);
+
+static struct spi_driver ads131e08_driver = {
+ .driver = {
+ .name = "ads131e08",
+ .of_match_table = ads131e08_of_match,
+ },
+ .probe = ads131e08_probe,
+};
+module_spi_driver(ads131e08_driver);
+
+MODULE_AUTHOR("Tomislav Denis <tomislav.denis@avl.com>");
+MODULE_DESCRIPTION("Driver for ADS131E0x ADC family");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index e946903b0993..855cc2d64ac8 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -385,24 +385,16 @@ static int tiadc_iio_buffered_hardware_setup(struct device *dev,
unsigned long flags,
const struct iio_buffer_setup_ops *setup_ops)
{
- struct iio_buffer *buffer;
int ret;
- buffer = devm_iio_kfifo_allocate(dev);
- if (!buffer)
- return -ENOMEM;
-
- iio_device_attach_buffer(indio_dev, buffer);
-
- ret = devm_request_threaded_irq(dev, irq, pollfunc_th, pollfunc_bh,
- flags, indio_dev->name, indio_dev);
+ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ setup_ops);
if (ret)
return ret;
- indio_dev->setup_ops = setup_ops;
- indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
-
- return 0;
+ return devm_request_threaded_irq(dev, irq, pollfunc_th, pollfunc_bh,
+ flags, indio_dev->name, indio_dev);
}
static const char * const chan_name_ain[] = {
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c
index 34800dccbf69..6914c1900ed0 100644
--- a/drivers/iio/adc/xilinx-xadc-core.c
+++ b/drivers/iio/adc/xilinx-xadc-core.c
@@ -747,7 +747,6 @@ static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev,
if (trig == NULL)
return ERR_PTR(-ENOMEM);
- trig->dev.parent = indio_dev->dev.parent;
trig->ops = &xadc_trigger_ops;
iio_trigger_set_drvdata(trig, iio_priv(indio_dev));
diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
index b0cb9a35f5cd..d76179878ff9 100644
--- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c
+++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
@@ -132,9 +132,9 @@ static const struct iio_dma_buffer_ops iio_dmaengine_default_ops = {
static ssize_t iio_dmaengine_buffer_get_length_align(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
struct dmaengine_buffer *dmaengine_buffer =
- iio_buffer_to_dmaengine_buffer(indio_dev->buffer);
+ iio_buffer_to_dmaengine_buffer(buffer);
return sprintf(buf, "%zu\n", dmaengine_buffer->align);
}
@@ -244,7 +244,7 @@ static void __devm_iio_dmaengine_buffer_free(struct device *dev, void *res)
*
* The buffer will be automatically de-allocated once the device gets destroyed.
*/
-struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev,
+static struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev,
const char *channel)
{
struct iio_buffer **bufferp, *buffer;
@@ -265,7 +265,34 @@ struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev,
return buffer;
}
-EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_alloc);
+
+/**
+ * devm_iio_dmaengine_buffer_setup() - Setup a DMA buffer for an IIO device
+ * @dev: Parent device for the buffer
+ * @indio_dev: IIO device to which to attach this buffer.
+ * @channel: DMA channel name, typically "rx".
+ *
+ * This allocates a new IIO buffer with devm_iio_dmaengine_buffer_alloc()
+ * and attaches it to an IIO device with iio_device_attach_buffer().
+ * It also appends the INDIO_BUFFER_HARDWARE mode to the supported modes of the
+ * IIO device.
+ */
+int devm_iio_dmaengine_buffer_setup(struct device *dev,
+ struct iio_dev *indio_dev,
+ const char *channel)
+{
+ struct iio_buffer *buffer;
+
+ buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent,
+ channel);
+ if (IS_ERR(buffer))
+ return PTR_ERR(buffer);
+
+ indio_dev->modes |= INDIO_BUFFER_HARDWARE;
+
+ return iio_device_attach_buffer(indio_dev, buffer);
+}
+EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_setup);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("DMA buffer for the IIO framework");
diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c
index 92b8aea3e063..b2b1b7d27af4 100644
--- a/drivers/iio/buffer/industrialio-triggered-buffer.c
+++ b/drivers/iio/buffer/industrialio-triggered-buffer.c
@@ -50,8 +50,6 @@ int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev,
goto error_ret;
}
- iio_device_attach_buffer(indio_dev, buffer);
-
indio_dev->pollfunc = iio_alloc_pollfunc(h,
thread,
IRQF_ONESHOT,
@@ -72,10 +70,16 @@ int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev,
buffer->attrs = buffer_attrs;
+ ret = iio_device_attach_buffer(indio_dev, buffer);
+ if (ret < 0)
+ goto error_dealloc_pollfunc;
+
return 0;
+error_dealloc_pollfunc:
+ iio_dealloc_pollfunc(indio_dev->pollfunc);
error_kfifo_free:
- iio_kfifo_free(indio_dev->buffer);
+ iio_kfifo_free(buffer);
error_ret:
return ret;
}
diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c
index 1359abed3b31..516eb3465de1 100644
--- a/drivers/iio/buffer/kfifo_buf.c
+++ b/drivers/iio/buffer/kfifo_buf.c
@@ -180,13 +180,13 @@ static void devm_iio_kfifo_release(struct device *dev, void *res)
}
/**
- * devm_iio_fifo_allocate - Resource-managed iio_kfifo_allocate()
+ * 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.
*/
-struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
+static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
{
struct iio_buffer **ptr, *r;
@@ -204,6 +204,45 @@ struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
return r;
}
-EXPORT_SYMBOL(devm_iio_kfifo_allocate);
+
+/**
+ * devm_iio_kfifo_buffer_setup_ext - Allocate a kfifo buffer & attach it to an IIO device
+ * @dev: Device object to which to attach the life-time of this kfifo buffer
+ * @indio_dev: The device the buffer should be attached to
+ * @mode_flags: The mode flags for this buffer (INDIO_BUFFER_SOFTWARE and/or
+ * INDIO_BUFFER_TRIGGERED).
+ * @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
+ * 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.
+ */
+int devm_iio_kfifo_buffer_setup_ext(struct device *dev,
+ struct iio_dev *indio_dev,
+ int mode_flags,
+ const struct iio_buffer_setup_ops *setup_ops,
+ const struct attribute **buffer_attrs)
+{
+ struct iio_buffer *buffer;
+
+ if (!mode_flags)
+ return -EINVAL;
+
+ buffer = devm_iio_kfifo_allocate(dev);
+ if (!buffer)
+ return -ENOMEM;
+
+ mode_flags &= kfifo_access_funcs.modes;
+
+ indio_dev->modes |= mode_flags;
+ indio_dev->setup_ops = setup_ops;
+
+ buffer->attrs = buffer_attrs;
+
+ return iio_device_attach_buffer(indio_dev, buffer);
+}
+EXPORT_SYMBOL_GPL(devm_iio_kfifo_buffer_setup_ext);
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c
index cdab9d04dedd..56ba6c82b501 100644
--- a/drivers/iio/chemical/atlas-sensor.c
+++ b/drivers/iio/chemical/atlas-sensor.c
@@ -649,7 +649,6 @@ static int atlas_probe(struct i2c_client *client,
data->client = client;
data->trig = trig;
data->chip = chip;
- trig->dev.parent = indio_dev->dev.parent;
trig->ops = &atlas_interrupt_trigger_ops;
iio_trigger_set_drvdata(trig, indio_dev);
diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c
index de9c9e3d23ea..29c0dfa4702b 100644
--- a/drivers/iio/chemical/bme680_i2c.c
+++ b/drivers/iio/chemical/bme680_i2c.c
@@ -26,8 +26,7 @@ static int bme680_i2c_probe(struct i2c_client *client,
regmap = devm_regmap_init_i2c(client, &bme680_regmap_config);
if (IS_ERR(regmap)) {
- dev_err(&client->dev, "Failed to register i2c regmap %d\n",
- (int)PTR_ERR(regmap));
+ dev_err(&client->dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap));
return PTR_ERR(regmap);
}
diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c
index 3b838068a7e4..6f56ad48cc40 100644
--- a/drivers/iio/chemical/bme680_spi.c
+++ b/drivers/iio/chemical/bme680_spi.c
@@ -132,8 +132,7 @@ 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 %d\n",
- (int)PTR_ERR(regmap));
+ dev_err(&spi->dev, "Failed to register spi regmap %ld\n", PTR_ERR(regmap));
return PTR_ERR(regmap);
}
diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c
index 60dd87e96f5f..886e96496dbf 100644
--- a/drivers/iio/chemical/ccs811.c
+++ b/drivers/iio/chemical/ccs811.c
@@ -497,7 +497,6 @@ static int ccs811_probe(struct i2c_client *client,
goto err_poweroff;
}
- data->drdy_trig->dev.parent = &client->dev;
data->drdy_trig->ops = &ccs811_trigger_ops;
iio_trigger_set_drvdata(data->drdy_trig, indio_dev);
indio_dev->trig = data->drdy_trig;
diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c
index 4d0d798c7cd3..261c277ac4a5 100644
--- a/drivers/iio/chemical/scd30_core.c
+++ b/drivers/iio/chemical/scd30_core.c
@@ -646,7 +646,6 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev)
return -ENOMEM;
}
- trig->dev.parent = dev;
trig->ops = &scd30_trigger_ops;
iio_trigger_set_drvdata(trig, indio_dev);
diff --git a/drivers/iio/chemical/scd30_serial.c b/drivers/iio/chemical/scd30_serial.c
index 06f85eb1a4dd..568b34486c44 100644
--- a/drivers/iio/chemical/scd30_serial.c
+++ b/drivers/iio/chemical/scd30_serial.c
@@ -177,7 +177,7 @@ static int scd30_serdev_command(struct scd30_state *state, enum scd30_cmd cmd, u
static int scd30_serdev_receive_buf(struct serdev_device *serdev,
const unsigned char *buf, size_t size)
{
- struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
+ struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
struct scd30_serdev_priv *priv;
struct scd30_state *state;
int num;
diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
index 2b9ee9161abd..0334b4954773 100644
--- a/drivers/iio/common/Kconfig
+++ b/drivers/iio/common/Kconfig
@@ -6,5 +6,6 @@
source "drivers/iio/common/cros_ec_sensors/Kconfig"
source "drivers/iio/common/hid-sensors/Kconfig"
source "drivers/iio/common/ms_sensors/Kconfig"
+source "drivers/iio/common/scmi_sensors/Kconfig"
source "drivers/iio/common/ssp_sensors/Kconfig"
source "drivers/iio/common/st_sensors/Kconfig"
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
index 4bc30bb548e2..fad40e1e1718 100644
--- a/drivers/iio/common/Makefile
+++ b/drivers/iio/common/Makefile
@@ -11,5 +11,6 @@
obj-y += cros_ec_sensors/
obj-y += hid-sensors/
obj-y += ms_sensors/
+obj-y += scmi_sensors/
obj-y += ssp_sensors/
obj-y += st_sensors/
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 752f59037715..af801e203623 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
@@ -97,8 +97,7 @@ static int cros_ec_lid_angle_probe(struct platform_device *pdev)
if (!indio_dev)
return -ENOMEM;
- ret = cros_ec_sensors_core_init(pdev, indio_dev, false, NULL,
- NULL, false);
+ ret = cros_ec_sensors_core_init(pdev, indio_dev, false, NULL, NULL);
if (ret)
return ret;
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 dee1191de752..376a5b30010a 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
@@ -236,8 +236,7 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
cros_ec_sensors_capture,
- cros_ec_sensors_push_data,
- true);
+ cros_ec_sensors_push_data);
if (ret)
return ret;
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
index c833ec0ef214..28bde13003b7 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
@@ -12,6 +12,7 @@
#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>
#include <linux/kernel.h>
@@ -240,7 +241,6 @@ static void cros_ec_sensors_core_clean(void *arg)
* for backward compatibility.
* @push_data: function to call when cros_ec_sensorhub receives
* a sample for that sensor.
- * @has_hw_fifo: Set true if this device has/uses a HW FIFO
*
* Return: 0 on success, -errno on failure.
*/
@@ -248,8 +248,7 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
struct iio_dev *indio_dev,
bool physical_device,
cros_ec_sensors_capture_t trigger_capture,
- cros_ec_sensorhub_push_data_cb_t push_data,
- bool has_hw_fifo)
+ cros_ec_sensorhub_push_data_cb_t push_data)
{
struct device *dev = &pdev->dev;
struct cros_ec_sensors_core_state *state = iio_priv(indio_dev);
@@ -334,14 +333,11 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
* We can not use trigger here, as events are generated
* as soon as sample_frequency is set.
*/
- struct iio_buffer *buffer;
-
- buffer = devm_iio_kfifo_allocate(dev);
- if (!buffer)
- return -ENOMEM;
-
- iio_device_attach_buffer(indio_dev, buffer);
- indio_dev->modes = INDIO_BUFFER_SOFTWARE;
+ ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE, NULL,
+ cros_ec_sensor_fifo_attributes);
+ if (ret)
+ return ret;
ret = cros_ec_sensorhub_register_push_data(
sensor_hub, sensor_platform->sensor_num,
@@ -358,21 +354,14 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
ret = iio_device_set_clock(indio_dev, CLOCK_BOOTTIME);
if (ret)
return ret;
- } else {
- const struct attribute **fifo_attrs;
-
- if (has_hw_fifo)
- fifo_attrs = cros_ec_sensor_fifo_attributes;
- else
- fifo_attrs = NULL;
+ } else {
/*
* The only way to get samples in buffer is to set a
* software trigger (systrig, hrtimer).
*/
- ret = devm_iio_triggered_buffer_setup_ext(
- dev, indio_dev, NULL, trigger_capture,
- NULL, fifo_attrs);
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ NULL, trigger_capture, NULL);
if (ret)
return ret;
}
@@ -562,7 +551,7 @@ static int cros_ec_sensors_read_until_not_busy(
}
/**
- * read_ec_sensors_data_unsafe() - read acceleration data from EC shared memory
+ * cros_ec_sensors_read_data_unsafe() - read acceleration data from EC shared memory
* @indio_dev: pointer to IIO device
* @scan_mask: bitmap of the sensor indices to scan
* @data: location to store data
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
index 5b822a4298a0..cb52b4fd6bf7 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
@@ -263,6 +263,29 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
}
EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value);
+int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1,
+ int *val2)
+{
+ s32 value;
+ int ret;
+
+ ret = sensor_hub_get_feature(st->hsdev,
+ st->sensitivity_rel.report_id,
+ st->sensitivity_rel.index, sizeof(value),
+ &value);
+ if (ret < 0 || value < 0) {
+ *val1 = *val2 = 0;
+ return -EINVAL;
+ }
+
+ convert_from_vtf_format(value, st->sensitivity_rel.size,
+ st->sensitivity_rel.unit_expo, val1, val2);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+EXPORT_SYMBOL(hid_sensor_read_raw_hyst_rel_value);
+
+
int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
int val1, int val2)
{
@@ -294,6 +317,37 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
}
EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
+int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st,
+ int val1, int val2)
+{
+ s32 value;
+ int ret;
+
+ if (val1 < 0 || val2 < 0)
+ return -EINVAL;
+
+ value = convert_to_vtf_format(st->sensitivity_rel.size,
+ 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);
+ if (ret < 0 || value < 0)
+ return -EINVAL;
+
+ ret = sensor_hub_get_feature(st->hsdev,
+ st->sensitivity_rel.report_id,
+ st->sensitivity_rel.index, sizeof(value),
+ &value);
+ if (ret < 0 || value < 0)
+ return -EINVAL;
+
+ st->raw_hystersis = value;
+
+ return 0;
+}
+EXPORT_SYMBOL(hid_sensor_write_raw_hyst_rel_value);
+
/*
* This fuction applies the unit exponent to the scale.
* For example:
@@ -448,12 +502,15 @@ EXPORT_SYMBOL(hid_sensor_batch_mode_supported);
int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
- struct hid_sensor_common *st)
+ struct hid_sensor_common *st,
+ const u32 *sensitivity_addresses,
+ u32 sensitivity_addresses_len)
{
struct hid_sensor_hub_attribute_info timestamp;
s32 value;
int ret;
+ int i;
hid_sensor_get_reporting_interval(hsdev, usage_id, st);
@@ -475,6 +532,30 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS,
&st->sensitivity);
+ sensor_hub_input_get_attribute_info(hsdev,
+ HID_FEATURE_REPORT, usage_id,
+ HID_USAGE_SENSOR_PROP_SENSITIVITY_REL_PCT,
+ &st->sensitivity_rel);
+ /*
+ * Set Sensitivity field ids, when there is no individual modifier, will
+ * check absolute sensitivity and relative sensitivity of data field
+ */
+ for (i = 0; i < sensitivity_addresses_len; i++) {
+ if (st->sensitivity.index < 0)
+ sensor_hub_input_get_attribute_info(
+ hsdev, HID_FEATURE_REPORT, usage_id,
+ HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
+ sensitivity_addresses[i],
+ &st->sensitivity);
+
+ if (st->sensitivity_rel.index < 0)
+ sensor_hub_input_get_attribute_info(
+ hsdev, HID_FEATURE_REPORT, usage_id,
+ HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_REL_PCT |
+ sensitivity_addresses[i],
+ &st->sensitivity_rel);
+ }
+
st->raw_hystersis = -1;
sensor_hub_input_get_attribute_info(hsdev,
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 064c32bec9c7..95ddccb44f1c 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -255,14 +255,14 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
return ret;
}
- trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id);
+ trig = iio_trigger_alloc(indio_dev->dev.parent,
+ "%s-dev%d", name, indio_dev->id);
if (trig == NULL) {
dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
ret = -ENOMEM;
goto error_triggered_buffer_cleanup;
}
- trig->dev.parent = indio_dev->dev.parent;
iio_trigger_set_drvdata(trig, attrb);
trig->ops = &hid_sensor_trigger_ops;
ret = iio_trigger_register(trig);
diff --git a/drivers/iio/common/scmi_sensors/Kconfig b/drivers/iio/common/scmi_sensors/Kconfig
new file mode 100644
index 000000000000..67e084cbb1ab
--- /dev/null
+++ b/drivers/iio/common/scmi_sensors/Kconfig
@@ -0,0 +1,18 @@
+#
+# IIO over SCMI
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "IIO SCMI Sensors"
+
+config IIO_SCMI
+ tristate "IIO SCMI"
+ depends on ARM_SCMI_PROTOCOL
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ help
+ Say yes here to build support for IIO SCMI Driver.
+ This provides ARM SCMI Protocol based IIO device.
+ This driver provides support for accelerometer and gyroscope
+ sensors available on SCMI based platforms.
+endmenu
diff --git a/drivers/iio/common/scmi_sensors/Makefile b/drivers/iio/common/scmi_sensors/Makefile
new file mode 100644
index 000000000000..f13140a2575a
--- /dev/null
+++ b/drivers/iio/common/scmi_sensors/Makefile
@@ -0,0 +1,5 @@
+# SPDX - License - Identifier : GPL - 2.0 - only
+#
+# Makefile for the IIO over SCMI
+#
+obj-$(CONFIG_IIO_SCMI) += scmi_iio.o
diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c
new file mode 100644
index 000000000000..63e4cec9de5e
--- /dev/null
+++ b/drivers/iio/common/scmi_sensors/scmi_iio.c
@@ -0,0 +1,672 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * System Control and Management Interface(SCMI) based IIO sensor driver
+ *
+ * Copyright (C) 2021 Google LLC
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/scmi_protocol.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#define SCMI_IIO_NUM_OF_AXIS 3
+
+struct scmi_iio_priv {
+ struct scmi_handle *handle;
+ const struct scmi_sensor_info *sensor_info;
+ struct iio_dev *indio_dev;
+ /* adding one additional channel for timestamp */
+ s64 iio_buf[SCMI_IIO_NUM_OF_AXIS + 1];
+ struct notifier_block sensor_update_nb;
+ u32 *freq_avail;
+};
+
+static int scmi_iio_sensor_update_cb(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct scmi_sensor_update_report *sensor_update = data;
+ struct iio_dev *scmi_iio_dev;
+ struct scmi_iio_priv *sensor;
+ s8 tstamp_scale;
+ u64 time, time_ns;
+ int i;
+
+ if (sensor_update->readings_count == 0)
+ return NOTIFY_DONE;
+
+ sensor = container_of(nb, struct scmi_iio_priv, sensor_update_nb);
+
+ for (i = 0; i < sensor_update->readings_count; i++)
+ sensor->iio_buf[i] = sensor_update->readings[i].value;
+
+ if (!sensor->sensor_info->timestamped) {
+ time_ns = ktime_to_ns(sensor_update->timestamp);
+ } else {
+ /*
+ * All the axes are supposed to have the same value for timestamp.
+ * We are just using the values from the Axis 0 here.
+ */
+ time = sensor_update->readings[0].timestamp;
+
+ /*
+ * Timestamp returned by SCMI is in seconds and is equal to
+ * time * power-of-10 multiplier(tstamp_scale) seconds.
+ * Converting the timestamp to nanoseconds below.
+ */
+ tstamp_scale = sensor->sensor_info->tstamp_scale +
+ const_ilog2(NSEC_PER_SEC) / const_ilog2(10);
+ if (tstamp_scale < 0) {
+ do_div(time, int_pow(10, abs(tstamp_scale)));
+ time_ns = time;
+ } else {
+ time_ns = time * int_pow(10, tstamp_scale);
+ }
+ }
+
+ scmi_iio_dev = sensor->indio_dev;
+ iio_push_to_buffers_with_timestamp(scmi_iio_dev, sensor->iio_buf,
+ time_ns);
+ return NOTIFY_OK;
+}
+
+static int scmi_iio_buffer_preenable(struct iio_dev *iio_dev)
+{
+ struct scmi_iio_priv *sensor = iio_priv(iio_dev);
+ u32 sensor_id = sensor->sensor_info->id;
+ u32 sensor_config = 0;
+ int err;
+
+ if (sensor->sensor_info->timestamped)
+ sensor_config |= FIELD_PREP(SCMI_SENS_CFG_TSTAMP_ENABLED_MASK,
+ SCMI_SENS_CFG_TSTAMP_ENABLE);
+
+ sensor_config |= FIELD_PREP(SCMI_SENS_CFG_SENSOR_ENABLED_MASK,
+ SCMI_SENS_CFG_SENSOR_ENABLE);
+
+ err = sensor->handle->notify_ops->register_event_notifier(sensor->handle,
+ SCMI_PROTOCOL_SENSOR, SCMI_EVENT_SENSOR_UPDATE,
+ &sensor_id, &sensor->sensor_update_nb);
+ if (err) {
+ dev_err(&iio_dev->dev,
+ "Error in registering sensor update notifier for sensor %s err %d",
+ sensor->sensor_info->name, err);
+ return err;
+ }
+
+ err = sensor->handle->sensor_ops->config_set(sensor->handle,
+ sensor->sensor_info->id, sensor_config);
+ if (err) {
+ sensor->handle->notify_ops->unregister_event_notifier(sensor->handle,
+ SCMI_PROTOCOL_SENSOR,
+ SCMI_EVENT_SENSOR_UPDATE, &sensor_id,
+ &sensor->sensor_update_nb);
+ dev_err(&iio_dev->dev, "Error in enabling sensor %s err %d",
+ sensor->sensor_info->name, err);
+ }
+
+ return err;
+}
+
+static int scmi_iio_buffer_postdisable(struct iio_dev *iio_dev)
+{
+ struct scmi_iio_priv *sensor = iio_priv(iio_dev);
+ u32 sensor_id = sensor->sensor_info->id;
+ u32 sensor_config = 0;
+ int err;
+
+ sensor_config |= FIELD_PREP(SCMI_SENS_CFG_SENSOR_ENABLED_MASK,
+ SCMI_SENS_CFG_SENSOR_DISABLE);
+
+ err = sensor->handle->notify_ops->unregister_event_notifier(sensor->handle,
+ SCMI_PROTOCOL_SENSOR, SCMI_EVENT_SENSOR_UPDATE,
+ &sensor_id, &sensor->sensor_update_nb);
+ if (err) {
+ dev_err(&iio_dev->dev,
+ "Error in unregistering sensor update notifier for sensor %s err %d",
+ sensor->sensor_info->name, err);
+ return err;
+ }
+
+ err = sensor->handle->sensor_ops->config_set(sensor->handle, sensor_id,
+ sensor_config);
+ if (err) {
+ dev_err(&iio_dev->dev,
+ "Error in disabling sensor %s with err %d",
+ sensor->sensor_info->name, err);
+ }
+
+ return err;
+}
+
+static const struct iio_buffer_setup_ops scmi_iio_buffer_ops = {
+ .preenable = scmi_iio_buffer_preenable,
+ .postdisable = scmi_iio_buffer_postdisable,
+};
+
+static int scmi_iio_set_odr_val(struct iio_dev *iio_dev, int val, int val2)
+{
+ struct scmi_iio_priv *sensor = iio_priv(iio_dev);
+ const unsigned long UHZ_PER_HZ = 1000000UL;
+ u64 sec, mult, uHz, sf;
+ u32 sensor_config;
+ char buf[32];
+
+ int err = sensor->handle->sensor_ops->config_get(sensor->handle,
+ sensor->sensor_info->id, &sensor_config);
+ if (err) {
+ dev_err(&iio_dev->dev,
+ "Error in getting sensor config for sensor %s err %d",
+ sensor->sensor_info->name, err);
+ return err;
+ }
+
+ uHz = val * UHZ_PER_HZ + val2;
+
+ /*
+ * The seconds field in the sensor interval in SCMI is 16 bits long
+ * Therefore seconds = 1/Hz <= 0xFFFF. As floating point calculations are
+ * discouraged in the kernel driver code, to calculate the scale factor (sf)
+ * (1* 1000000 * sf)/uHz <= 0xFFFF. Therefore, sf <= (uHz * 0xFFFF)/1000000
+ * To calculate the multiplier,we convert the sf into char string and
+ * count the number of characters
+ */
+ sf = (u64)uHz * 0xFFFF;
+ do_div(sf, UHZ_PER_HZ);
+ mult = scnprintf(buf, sizeof(buf), "%llu", sf) - 1;
+
+ sec = int_pow(10, mult) * UHZ_PER_HZ;
+ do_div(sec, uHz);
+ if (sec == 0) {
+ dev_err(&iio_dev->dev,
+ "Trying to set invalid sensor update value for sensor %s",
+ sensor->sensor_info->name);
+ return -EINVAL;
+ }
+
+ sensor_config &= ~SCMI_SENS_CFG_UPDATE_SECS_MASK;
+ sensor_config |= FIELD_PREP(SCMI_SENS_CFG_UPDATE_SECS_MASK, sec);
+ sensor_config &= ~SCMI_SENS_CFG_UPDATE_EXP_MASK;
+ sensor_config |= FIELD_PREP(SCMI_SENS_CFG_UPDATE_EXP_MASK, -mult);
+
+ if (sensor->sensor_info->timestamped) {
+ sensor_config &= ~SCMI_SENS_CFG_TSTAMP_ENABLED_MASK;
+ sensor_config |= FIELD_PREP(SCMI_SENS_CFG_TSTAMP_ENABLED_MASK,
+ SCMI_SENS_CFG_TSTAMP_ENABLE);
+ }
+
+ sensor_config &= ~SCMI_SENS_CFG_ROUND_MASK;
+ sensor_config |=
+ FIELD_PREP(SCMI_SENS_CFG_ROUND_MASK, SCMI_SENS_CFG_ROUND_AUTO);
+
+ err = sensor->handle->sensor_ops->config_set(sensor->handle,
+ sensor->sensor_info->id, sensor_config);
+ if (err)
+ dev_err(&iio_dev->dev,
+ "Error in setting sensor update interval for sensor %s value %u err %d",
+ sensor->sensor_info->name, sensor_config, err);
+
+ return err;
+}
+
+static int scmi_iio_write_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ int err;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ mutex_lock(&iio_dev->mlock);
+ err = scmi_iio_set_odr_val(iio_dev, val, val2);
+ mutex_unlock(&iio_dev->mlock);
+ return err;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int scmi_iio_read_avail(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct scmi_iio_priv *sensor = iio_priv(iio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = sensor->freq_avail;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *length = sensor->sensor_info->intervals.count * 2;
+ if (sensor->sensor_info->intervals.segmented)
+ return IIO_AVAIL_RANGE;
+ else
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void convert_ns_to_freq(u64 interval_ns, u64 *hz, u64 *uhz)
+{
+ u64 rem, freq;
+
+ freq = NSEC_PER_SEC;
+ rem = do_div(freq, interval_ns);
+ *hz = freq;
+ *uhz = rem * 1000000UL;
+ do_div(*uhz, interval_ns);
+}
+
+static int scmi_iio_get_odr_val(struct iio_dev *iio_dev, int *val, int *val2)
+{
+ u64 sensor_update_interval, sensor_interval_mult, hz, uhz;
+ struct scmi_iio_priv *sensor = iio_priv(iio_dev);
+ u32 sensor_config;
+ int mult;
+
+ int err = sensor->handle->sensor_ops->config_get(sensor->handle,
+ sensor->sensor_info->id, &sensor_config);
+ if (err) {
+ dev_err(&iio_dev->dev,
+ "Error in getting sensor config for sensor %s err %d",
+ sensor->sensor_info->name, err);
+ return err;
+ }
+
+ sensor_update_interval =
+ SCMI_SENS_CFG_GET_UPDATE_SECS(sensor_config) * NSEC_PER_SEC;
+
+ mult = SCMI_SENS_CFG_GET_UPDATE_EXP(sensor_config);
+ if (mult < 0) {
+ sensor_interval_mult = int_pow(10, abs(mult));
+ do_div(sensor_update_interval, sensor_interval_mult);
+ } else {
+ sensor_interval_mult = int_pow(10, mult);
+ sensor_update_interval =
+ sensor_update_interval * sensor_interval_mult;
+ }
+
+ convert_ns_to_freq(sensor_update_interval, &hz, &uhz);
+ *val = hz;
+ *val2 = uhz;
+ return 0;
+}
+
+static int scmi_iio_read_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *ch, int *val,
+ int *val2, long mask)
+{
+ struct scmi_iio_priv *sensor = iio_priv(iio_dev);
+ s8 scale;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ scale = sensor->sensor_info->axis[ch->scan_index].scale;
+ if (scale < 0) {
+ *val = 1;
+ *val2 = int_pow(10, abs(scale));
+ return IIO_VAL_FRACTIONAL;
+ }
+ *val = int_pow(10, scale);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = scmi_iio_get_odr_val(iio_dev, val, val2);
+ return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info scmi_iio_info = {
+ .read_raw = scmi_iio_read_raw,
+ .read_avail = scmi_iio_read_avail,
+ .write_raw = scmi_iio_write_raw,
+};
+
+static ssize_t scmi_iio_get_raw_available(struct iio_dev *iio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ char *buf)
+{
+ struct scmi_iio_priv *sensor = iio_priv(iio_dev);
+ u64 resolution, rem;
+ s64 min_range, max_range;
+ s8 exponent, scale;
+ int len = 0;
+
+ /*
+ * All the axes are supposed to have the same value for range and resolution.
+ * We are just using the values from the Axis 0 here.
+ */
+ if (sensor->sensor_info->axis[0].extended_attrs) {
+ min_range = sensor->sensor_info->axis[0].attrs.min_range;
+ max_range = sensor->sensor_info->axis[0].attrs.max_range;
+ resolution = sensor->sensor_info->axis[0].resolution;
+ exponent = sensor->sensor_info->axis[0].exponent;
+ scale = sensor->sensor_info->axis[0].scale;
+
+ /*
+ * To provide the raw value for the resolution to the userspace,
+ * need to divide the resolution exponent by the sensor scale
+ */
+ exponent = exponent - scale;
+ if (exponent < 0) {
+ rem = do_div(resolution,
+ int_pow(10, abs(exponent))
+ );
+ len = scnprintf(buf, PAGE_SIZE,
+ "[%lld %llu.%llu %lld]\n", min_range,
+ resolution, rem, max_range);
+ } else {
+ resolution = resolution * int_pow(10, exponent);
+ len = scnprintf(buf, PAGE_SIZE, "[%lld %llu %lld]\n",
+ min_range, resolution, max_range);
+ }
+ }
+ return len;
+}
+
+static const struct iio_chan_spec_ext_info scmi_iio_ext_info[] = {
+ {
+ .name = "raw_available",
+ .read = scmi_iio_get_raw_available,
+ .shared = IIO_SHARED_BY_TYPE,
+ },
+ {},
+};
+
+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)
+{
+ iio_chan->type = type;
+ iio_chan->modified = 1;
+ iio_chan->channel2 = mod;
+ iio_chan->info_mask_separate = BIT(IIO_CHAN_INFO_SCALE);
+ iio_chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ);
+ iio_chan->info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_SAMP_FREQ);
+ iio_chan->scan_index = scan_index;
+ iio_chan->scan_type.sign = 's';
+ iio_chan->scan_type.realbits = 64;
+ iio_chan->scan_type.storagebits = 64;
+ iio_chan->scan_type.endianness = IIO_LE;
+ iio_chan->ext_info = scmi_iio_ext_info;
+}
+
+static int scmi_iio_get_chan_modifier(const char *name,
+ enum iio_modifier *modifier)
+{
+ char *pch, mod;
+
+ if (!name)
+ return -EINVAL;
+
+ pch = strrchr(name, '_');
+ if (!pch)
+ return -EINVAL;
+
+ mod = *(pch + 1);
+ switch (mod) {
+ case 'X':
+ *modifier = IIO_MOD_X;
+ return 0;
+ case 'Y':
+ *modifier = IIO_MOD_Y;
+ return 0;
+ case 'Z':
+ *modifier = IIO_MOD_Z;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int scmi_iio_get_chan_type(u8 scmi_type, enum iio_chan_type *iio_type)
+{
+ switch (scmi_type) {
+ case METERS_SEC_SQUARED:
+ *iio_type = IIO_ACCEL;
+ return 0;
+ case RADIANS_SEC:
+ *iio_type = IIO_ANGL_VEL;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static u64 scmi_iio_convert_interval_to_ns(u32 val)
+{
+ u64 sensor_update_interval =
+ SCMI_SENS_INTVL_GET_SECS(val) * NSEC_PER_SEC;
+ u64 sensor_interval_mult;
+ int mult;
+
+ mult = SCMI_SENS_INTVL_GET_EXP(val);
+ if (mult < 0) {
+ sensor_interval_mult = int_pow(10, abs(mult));
+ do_div(sensor_update_interval, sensor_interval_mult);
+ } else {
+ sensor_interval_mult = int_pow(10, mult);
+ sensor_update_interval =
+ sensor_update_interval * sensor_interval_mult;
+ }
+ return sensor_update_interval;
+}
+
+static int scmi_iio_set_sampling_freq_avail(struct iio_dev *iio_dev)
+{
+ u64 cur_interval_ns, low_interval_ns, high_interval_ns, step_size_ns,
+ hz, uhz;
+ unsigned int cur_interval, low_interval, high_interval, step_size;
+ struct scmi_iio_priv *sensor = iio_priv(iio_dev);
+ int i;
+
+ sensor->freq_avail =
+ devm_kzalloc(&iio_dev->dev,
+ sizeof(*sensor->freq_avail) *
+ (sensor->sensor_info->intervals.count * 2),
+ GFP_KERNEL);
+ if (!sensor->freq_avail)
+ return -ENOMEM;
+
+ if (sensor->sensor_info->intervals.segmented) {
+ low_interval = sensor->sensor_info->intervals
+ .desc[SCMI_SENS_INTVL_SEGMENT_LOW];
+ low_interval_ns = scmi_iio_convert_interval_to_ns(low_interval);
+ convert_ns_to_freq(low_interval_ns, &hz, &uhz);
+ sensor->freq_avail[0] = hz;
+ sensor->freq_avail[1] = uhz;
+
+ step_size = sensor->sensor_info->intervals
+ .desc[SCMI_SENS_INTVL_SEGMENT_STEP];
+ step_size_ns = scmi_iio_convert_interval_to_ns(step_size);
+ convert_ns_to_freq(step_size_ns, &hz, &uhz);
+ sensor->freq_avail[2] = hz;
+ sensor->freq_avail[3] = uhz;
+
+ high_interval = sensor->sensor_info->intervals
+ .desc[SCMI_SENS_INTVL_SEGMENT_HIGH];
+ high_interval_ns =
+ scmi_iio_convert_interval_to_ns(high_interval);
+ convert_ns_to_freq(high_interval_ns, &hz, &uhz);
+ sensor->freq_avail[4] = hz;
+ sensor->freq_avail[5] = uhz;
+ } else {
+ for (i = 0; i < sensor->sensor_info->intervals.count; i++) {
+ cur_interval = sensor->sensor_info->intervals.desc[i];
+ cur_interval_ns =
+ scmi_iio_convert_interval_to_ns(cur_interval);
+ convert_ns_to_freq(cur_interval_ns, &hz, &uhz);
+ sensor->freq_avail[i * 2] = hz;
+ sensor->freq_avail[i * 2 + 1] = uhz;
+ }
+ }
+ return 0;
+}
+
+static struct iio_dev *scmi_alloc_iiodev(struct device *dev,
+ struct scmi_handle *handle,
+ const struct scmi_sensor_info *sensor_info)
+{
+ struct iio_chan_spec *iio_channels;
+ struct scmi_iio_priv *sensor;
+ enum iio_modifier modifier;
+ enum iio_chan_type type;
+ struct iio_dev *iiodev;
+ int i, ret;
+
+ iiodev = devm_iio_device_alloc(dev, sizeof(*sensor));
+ if (!iiodev)
+ return ERR_PTR(-ENOMEM);
+
+ iiodev->modes = INDIO_DIRECT_MODE;
+ iiodev->dev.parent = dev;
+ sensor = iio_priv(iiodev);
+ sensor->handle = handle;
+ sensor->sensor_info = sensor_info;
+ sensor->sensor_update_nb.notifier_call = scmi_iio_sensor_update_cb;
+ sensor->indio_dev = iiodev;
+
+ /* adding one additional channel for timestamp */
+ iiodev->num_channels = sensor_info->num_axis + 1;
+ iiodev->name = sensor_info->name;
+ iiodev->info = &scmi_iio_info;
+
+ iio_channels =
+ devm_kzalloc(dev,
+ sizeof(*iio_channels) * (iiodev->num_channels),
+ GFP_KERNEL);
+ if (!iio_channels)
+ return ERR_PTR(-ENOMEM);
+
+ ret = scmi_iio_set_sampling_freq_avail(iiodev);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ for (i = 0; i < sensor_info->num_axis; i++) {
+ ret = scmi_iio_get_chan_type(sensor_info->axis[i].type, &type);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ ret = scmi_iio_get_chan_modifier(sensor_info->axis[i].name,
+ &modifier);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ scmi_iio_set_data_channel(&iio_channels[i], type, modifier,
+ sensor_info->axis[i].id);
+ }
+
+ scmi_iio_set_timestamp_channel(&iio_channels[i], i);
+ iiodev->channels = iio_channels;
+ return iiodev;
+}
+
+static int scmi_iio_dev_probe(struct scmi_device *sdev)
+{
+ const struct scmi_sensor_info *sensor_info;
+ struct scmi_handle *handle = sdev->handle;
+ struct device *dev = &sdev->dev;
+ struct iio_dev *scmi_iio_dev;
+ u16 nr_sensors;
+ int err = -ENODEV, i;
+
+ if (!handle || !handle->sensor_ops) {
+ dev_err(dev, "SCMI device has no sensor interface\n");
+ return -EINVAL;
+ }
+
+ nr_sensors = handle->sensor_ops->count_get(handle);
+ if (!nr_sensors) {
+ dev_dbg(dev, "0 sensors found via SCMI bus\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < nr_sensors; i++) {
+ sensor_info = handle->sensor_ops->info_get(handle, i);
+ if (!sensor_info) {
+ dev_err(dev, "SCMI sensor %d has missing info\n", i);
+ return -EINVAL;
+ }
+
+ /* This driver only supports 3-axis accel and gyro, skipping other sensors */
+ if (sensor_info->num_axis != SCMI_IIO_NUM_OF_AXIS)
+ continue;
+
+ /* This driver only supports 3-axis accel and gyro, skipping other sensors */
+ if (sensor_info->axis[0].type != METERS_SEC_SQUARED &&
+ sensor_info->axis[0].type != RADIANS_SEC)
+ continue;
+
+ scmi_iio_dev = scmi_alloc_iiodev(dev, handle, sensor_info);
+ if (IS_ERR(scmi_iio_dev)) {
+ dev_err(dev,
+ "failed to allocate IIO device for sensor %s: %ld\n",
+ sensor_info->name, PTR_ERR(scmi_iio_dev));
+ return PTR_ERR(scmi_iio_dev);
+ }
+
+ err = devm_iio_kfifo_buffer_setup(&scmi_iio_dev->dev,
+ scmi_iio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &scmi_iio_buffer_ops);
+ if (err < 0) {
+ dev_err(dev,
+ "IIO buffer setup error at sensor %s: %d\n",
+ sensor_info->name, err);
+ return err;
+ }
+
+ err = devm_iio_device_register(dev, scmi_iio_dev);
+ if (err) {
+ dev_err(dev,
+ "IIO device registration failed at sensor %s: %d\n",
+ sensor_info->name, err);
+ return err;
+ }
+ }
+ return err;
+}
+
+static const struct scmi_device_id scmi_id_table[] = {
+ { SCMI_PROTOCOL_SENSOR, "iiodev" },
+ {},
+};
+
+MODULE_DEVICE_TABLE(scmi, scmi_id_table);
+
+static struct scmi_driver scmi_iiodev_driver = {
+ .name = "scmi-sensor-iiodev",
+ .probe = scmi_iio_dev_probe,
+ .id_table = scmi_id_table,
+};
+
+module_scmi_driver(scmi_iiodev_driver);
+
+MODULE_AUTHOR("Jyoti Bhayana <jbhayana@google.com>");
+MODULE_DESCRIPTION("SCMI IIO Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c
index eee30130ae23..802f9ae04cf4 100644
--- a/drivers/iio/common/st_sensors/st_sensors_buffer.c
+++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c
@@ -57,7 +57,7 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p)
s64 timestamp;
/*
- * If we do timetamping here, do it before reading the values, because
+ * If we do timestamping here, do it before reading the values, because
* once we've read the values, new interrupts can occur (when using
* the hardware trigger) and the hw_timestamp may get updated.
* By storing it in a local variable first, we are safe.
diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c
index 2dbd2646e44e..0b511665dee5 100644
--- a/drivers/iio/common/st_sensors/st_sensors_trigger.c
+++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
@@ -123,7 +123,8 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
unsigned long irq_trig;
int err;
- sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
+ sdata->trig = iio_trigger_alloc(sdata->dev, "%s-trigger",
+ indio_dev->name);
if (sdata->trig == NULL) {
dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
return -ENOMEM;
@@ -131,7 +132,6 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
iio_trigger_set_drvdata(sdata->trig, indio_dev);
sdata->trig->ops = trigger_ops;
- sdata->trig->dev.parent = sdata->dev;
irq_trig = irqd_get_trigger_type(irq_get_irq_data(sdata->irq));
/*
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index cea07b4cced1..75e1f2b48638 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -142,8 +142,9 @@ config AD5696_I2C
select AD5686
help
Say yes here to build support for Analog Devices AD5311R, AD5338R,
- AD5671R, AD5675R, AD5691R, AD5692R, AD5693, AD5693R, AD5694, AD5694R,
- AD5695R, AD5696, and AD5696R Digital to Analog converters.
+ AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693, AD5693R,
+ AD5694, AD5694R, AD5695R, AD5696, and AD5696R Digital to Analog
+ converters.
To compile this driver as a module, choose M here: the module will be
called ad5696.
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index e9297c25d4ef..f383bdcdc121 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -39,7 +39,7 @@
#define AD5504_DAC_PWRDN_3STATE 1
/**
- * struct ad5446_state - driver instance specific data
+ * struct ad5504_state - driver instance specific data
* @spi: spi_device
* @reg: supply regulator
* @vref_mv: actual reference voltage used
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 7d6792ac1020..99a95282ac57 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -301,6 +301,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
.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,
@@ -324,6 +330,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
.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,
diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h
index d9c8ba413fe9..f89a6f92b427 100644
--- a/drivers/iio/dac/ad5686.h
+++ b/drivers/iio/dac/ad5686.h
@@ -55,10 +55,12 @@ enum ad5686_supported_device_ids {
ID_AD5338R,
ID_AD5671R,
ID_AD5672R,
+ ID_AD5673R,
ID_AD5674R,
ID_AD5675R,
ID_AD5676,
ID_AD5676R,
+ ID_AD5677R,
ID_AD5679R,
ID_AD5681R,
ID_AD5682R,
diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c
index a39eda7c02d2..24a6a4a5a2e0 100644
--- a/drivers/iio/dac/ad5696-i2c.c
+++ b/drivers/iio/dac/ad5696-i2c.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * AD5671R, AD5675R, AD5691R, AD5692R, AD5693, AD5693R,
- * AD5694, AD5694R, AD5695R, AD5696, AD5696R
+ * AD5338R, AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693,
+ * AD5693R, AD5694, AD5694R, AD5695R, AD5696, AD5696R
* Digital to analog converters driver
*
* Copyright 2018 Analog Devices Inc.
@@ -74,7 +74,9 @@ static const struct i2c_device_id ad5686_i2c_id[] = {
{"ad5311r", ID_AD5311R},
{"ad5338r", ID_AD5338R},
{"ad5671r", ID_AD5671R},
+ {"ad5673r", ID_AD5673R},
{"ad5675r", ID_AD5675R},
+ {"ad5677r", ID_AD5677R},
{"ad5691r", ID_AD5691R},
{"ad5692r", ID_AD5692R},
{"ad5693", ID_AD5693},
diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c
index 84dcf149261f..4e7a8ed83cc1 100644
--- a/drivers/iio/dac/ad5770r.c
+++ b/drivers/iio/dac/ad5770r.c
@@ -118,7 +118,7 @@ struct ad5770r_out_range {
};
/**
- * struct ad5770R_state - driver instance specific data
+ * struct ad5770r_state - driver instance specific data
* @spi: spi_device
* @regmap: regmap
* @vref_reg: fixed regulator for reference configuration
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
index e3ffa4b9f84c..615d72cd59bc 100644
--- a/drivers/iio/dac/ad5791.c
+++ b/drivers/iio/dac/ad5791.c
@@ -76,7 +76,7 @@ struct ad5791_chip_info {
* @chip_info: chip model specific constants
* @vref_mv: actual reference voltage used
* @vref_neg_mv: voltage of the negative supply
- * @ctrl: control regster cache
+ * @ctrl: control register cache
* @pwr_down_mode: current power down mode
* @pwr_down: true if device is powered down
* @data: spi transfer buffers
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
index daa60386bf0c..a6ef555153f4 100644
--- a/drivers/iio/dac/max517.c
+++ b/drivers/iio/dac/max517.c
@@ -153,7 +153,6 @@ static int max517_probe(struct i2c_client *client,
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
- i2c_set_clientdata(client, indio_dev);
data->client = client;
switch (id->driver_data) {
@@ -186,13 +185,7 @@ static int max517_probe(struct i2c_client *client,
data->vref_mv[chan] = platform_data->vref_mv[chan];
}
- return iio_device_register(indio_dev);
-}
-
-static int max517_remove(struct i2c_client *client)
-{
- iio_device_unregister(i2c_get_clientdata(client));
- return 0;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id max517_id[] = {
@@ -211,7 +204,6 @@ static struct i2c_driver max517_driver = {
.pm = &max517_pm_ops,
},
.probe = max517_probe,
- .remove = max517_remove,
.id_table = max517_id,
};
module_i2c_driver(max517_driver);
diff --git a/drivers/iio/dummy/iio_simple_dummy_buffer.c b/drivers/iio/dummy/iio_simple_dummy_buffer.c
index 5512d5edc707..59aa60d4ca37 100644
--- a/drivers/iio/dummy/iio_simple_dummy_buffer.c
+++ b/drivers/iio/dummy/iio_simple_dummy_buffer.c
@@ -16,9 +16,9 @@
#include <linux/bitmap.h>
#include <linux/iio/iio.h>
-#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
#include "iio_simple_dummy.h"
@@ -103,64 +103,9 @@ static const struct iio_buffer_setup_ops iio_simple_dummy_buffer_setup_ops = {
int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
{
- int ret;
- struct iio_buffer *buffer;
-
- /* Allocate a buffer to use - here a kfifo */
- buffer = iio_kfifo_allocate();
- if (!buffer) {
- ret = -ENOMEM;
- goto error_ret;
- }
-
- iio_device_attach_buffer(indio_dev, buffer);
-
- /*
- * Tell the core what device type specific functions should
- * be run on either side of buffer capture enable / disable.
- */
- indio_dev->setup_ops = &iio_simple_dummy_buffer_setup_ops;
-
- /*
- * Configure a polling function.
- * When a trigger event with this polling function connected
- * occurs, this function is run. Typically this grabs data
- * from the device.
- *
- * NULL for the bottom half. This is normally implemented only if we
- * either want to ping a capture now pin (no sleeping) or grab
- * a timestamp as close as possible to a data ready trigger firing.
- *
- * IRQF_ONESHOT ensures irqs are masked such that only one instance
- * of the handler can run at a time.
- *
- * "iio_simple_dummy_consumer%d" formatting string for the irq 'name'
- * as seen under /proc/interrupts. Remaining parameters as per printk.
- */
- indio_dev->pollfunc = iio_alloc_pollfunc(NULL,
- &iio_simple_dummy_trigger_h,
- IRQF_ONESHOT,
- indio_dev,
- "iio_simple_dummy_consumer%d",
- indio_dev->id);
-
- if (!indio_dev->pollfunc) {
- ret = -ENOMEM;
- goto error_free_buffer;
- }
-
- /*
- * Notify the core that this device is capable of buffered capture
- * driven by a trigger.
- */
- indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
-
- return 0;
-
-error_free_buffer:
- iio_kfifo_free(indio_dev->buffer);
-error_ret:
- return ret;
+ return iio_triggered_buffer_setup(indio_dev, NULL,
+ iio_simple_dummy_trigger_h,
+ &iio_simple_dummy_buffer_setup_ops);
}
/**
@@ -169,6 +114,5 @@ error_ret:
*/
void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
{
- iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_kfifo_free(indio_dev->buffer);
+ iio_triggered_buffer_cleanup(indio_dev);
}
diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c
index c45d8226cc2b..cec5e1f17c22 100644
--- a/drivers/iio/gyro/adxrs290.c
+++ b/drivers/iio/gyro/adxrs290.c
@@ -593,7 +593,6 @@ static int adxrs290_probe_trigger(struct iio_dev *indio_dev)
if (!st->dready_trig)
return -ENOMEM;
- st->dready_trig->dev.parent = &st->spi->dev;
st->dready_trig->ops = &adxrs290_trigger_ops;
iio_trigger_set_drvdata(st->dready_trig, indio_dev);
diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
index 029ef4c34604..b11ebd9bb7a4 100644
--- a/drivers/iio/gyro/bmg160_core.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -1148,14 +1148,12 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
if (!data->motion_trig)
return -ENOMEM;
- data->dready_trig->dev.parent = dev;
data->dready_trig->ops = &bmg160_trigger_ops;
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
ret = iio_trigger_register(data->dready_trig);
if (ret)
return ret;
- data->motion_trig->dev.parent = dev;
data->motion_trig->ops = &bmg160_trigger_ops;
iio_trigger_set_drvdata(data->motion_trig, indio_dev);
ret = iio_trigger_register(data->motion_trig);
diff --git a/drivers/iio/gyro/fxas21002c_core.c b/drivers/iio/gyro/fxas21002c_core.c
index 129eead8febc..1a20c6b88e7d 100644
--- a/drivers/iio/gyro/fxas21002c_core.c
+++ b/drivers/iio/gyro/fxas21002c_core.c
@@ -875,7 +875,6 @@ static int fxas21002c_trigger_probe(struct fxas21002c_data *data)
if (ret < 0)
return ret;
- data->dready_trig->dev.parent = dev;
data->dready_trig->ops = &fxas21002c_trigger_ops;
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index fb0d678ece1a..dad26ee4fd1f 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -45,6 +45,10 @@ static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = {
HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS
};
+static const u32 gryo_3d_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_DATA_ANGL_VELOCITY,
+};
+
/* Channel definitions */
static const struct iio_chan_spec gyro_3d_channels[] = {
{
@@ -271,17 +275,6 @@ static int gyro_3d_parse_report(struct platform_device *pdev,
&st->gyro[CHANNEL_SCAN_INDEX_X],
&st->scale_pre_decml, &st->scale_post_decml);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->common_attributes.sensitivity.index < 0) {
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_DATA_ANGL_VELOCITY,
- &st->common_attributes.sensitivity);
- dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
- st->common_attributes.sensitivity.index,
- st->common_attributes.sensitivity.report_id);
- }
return ret;
}
@@ -305,7 +298,9 @@ 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);
+ &gyro_state->common_attributes,
+ gryo_3d_sensitivity_addresses,
+ ARRAY_SIZE(gryo_3d_sensitivity_addresses));
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c
index 1c3c1bd53374..af0aaa146f0c 100644
--- a/drivers/iio/gyro/itg3200_buffer.c
+++ b/drivers/iio/gyro/itg3200_buffer.c
@@ -113,7 +113,7 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct itg3200 *st = iio_priv(indio_dev);
- st->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
+ st->trig = iio_trigger_alloc(&st->i2c->dev, "%s-dev%d", indio_dev->name,
indio_dev->id);
if (!st->trig)
return -ENOMEM;
@@ -127,7 +127,6 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev)
goto error_free_trig;
- st->trig->dev.parent = &st->i2c->dev;
st->trig->ops = &itg3200_trigger_ops;
iio_trigger_set_drvdata(st->trig, indio_dev);
ret = iio_trigger_register(st->trig);
diff --git a/drivers/iio/gyro/ssp_gyro_sensor.c b/drivers/iio/gyro/ssp_gyro_sensor.c
index ac7c170a20de..46ed12771d2f 100644
--- a/drivers/iio/gyro/ssp_gyro_sensor.c
+++ b/drivers/iio/gyro/ssp_gyro_sensor.c
@@ -96,7 +96,6 @@ static int ssp_gyro_probe(struct platform_device *pdev)
int ret;
struct iio_dev *indio_dev;
struct ssp_sensor_data *spd;
- struct iio_buffer *buffer;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*spd));
if (!indio_dev)
@@ -109,18 +108,15 @@ static int ssp_gyro_probe(struct platform_device *pdev)
indio_dev->name = ssp_gyro_name;
indio_dev->info = &ssp_gyro_iio_info;
- indio_dev->modes = INDIO_BUFFER_SOFTWARE;
indio_dev->channels = ssp_gyro_channels;
indio_dev->num_channels = ARRAY_SIZE(ssp_gyro_channels);
indio_dev->available_scan_masks = ssp_gyro_scan_mask;
- buffer = devm_iio_kfifo_allocate(&pdev->dev);
- if (!buffer)
- return -ENOMEM;
-
- iio_device_attach_buffer(indio_dev, buffer);
-
- indio_dev->setup_ops = &ssp_gyro_buffer_ops;
+ ret = devm_iio_kfifo_buffer_setup(&pdev->dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &ssp_gyro_buffer_ops);
+ if (ret)
+ return ret;
platform_set_drvdata(pdev, indio_dev);
diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c
index 38734e4ce360..1fa8d51d5080 100644
--- a/drivers/iio/health/afe4403.c
+++ b/drivers/iio/health/afe4403.c
@@ -531,7 +531,6 @@ static int afe4403_probe(struct spi_device *spi)
iio_trigger_set_drvdata(afe->trig, indio_dev);
afe->trig->ops = &afe4403_trigger_ops;
- afe->trig->dev.parent = afe->dev;
ret = iio_trigger_register(afe->trig);
if (ret) {
diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c
index 61fe4932d81d..e1476bf79fe2 100644
--- a/drivers/iio/health/afe4404.c
+++ b/drivers/iio/health/afe4404.c
@@ -538,7 +538,6 @@ static int afe4404_probe(struct i2c_client *client,
iio_trigger_set_drvdata(afe->trig, indio_dev);
afe->trig->ops = &afe4404_trigger_ops;
- afe->trig->dev.parent = afe->dev;
ret = iio_trigger_register(afe->trig);
if (ret) {
diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c
index 38aa2030f3c6..36ba7611d9ce 100644
--- a/drivers/iio/health/max30100.c
+++ b/drivers/iio/health/max30100.c
@@ -418,7 +418,6 @@ static int max30100_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max30100_data *data;
- struct iio_buffer *buffer;
struct iio_dev *indio_dev;
int ret;
@@ -426,19 +425,18 @@ static int max30100_probe(struct i2c_client *client,
if (!indio_dev)
return -ENOMEM;
- buffer = devm_iio_kfifo_allocate(&client->dev);
- if (!buffer)
- return -ENOMEM;
-
- iio_device_attach_buffer(indio_dev, buffer);
-
indio_dev->name = MAX30100_DRV_NAME;
indio_dev->channels = max30100_channels;
indio_dev->info = &max30100_info;
indio_dev->num_channels = ARRAY_SIZE(max30100_channels);
indio_dev->available_scan_masks = max30100_scan_masks;
- indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
- indio_dev->setup_ops = &max30100_buffer_setup_ops;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &max30100_buffer_setup_ops);
+ if (ret)
+ return ret;
data = iio_priv(indio_dev);
data->indio_dev = indio_dev;
diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index b35557a54ee2..2292876c55e2 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -506,7 +506,6 @@ static int max30102_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max30102_data *data;
- struct iio_buffer *buffer;
struct iio_dev *indio_dev;
int ret;
unsigned int reg;
@@ -515,16 +514,9 @@ static int max30102_probe(struct i2c_client *client,
if (!indio_dev)
return -ENOMEM;
- buffer = devm_iio_kfifo_allocate(&client->dev);
- if (!buffer)
- return -ENOMEM;
-
- iio_device_attach_buffer(indio_dev, buffer);
-
indio_dev->name = MAX30102_DRV_NAME;
indio_dev->info = &max30102_info;
- indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
- indio_dev->setup_ops = &max30102_buffer_setup_ops;
+ indio_dev->modes = INDIO_DIRECT_MODE;
data = iio_priv(indio_dev);
data->indio_dev = indio_dev;
@@ -549,6 +541,12 @@ static int max30102_probe(struct i2c_client *client,
return -ENODEV;
}
+ ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &max30102_buffer_setup_ops);
+ if (ret)
+ return ret;
+
data->regmap = devm_regmap_init_i2c(client, &max30102_regmap_config);
if (IS_ERR(data->regmap)) {
dev_err(&client->dev, "regmap initialization failed\n");
diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c
index 02ad1767c845..23bc9c784ef4 100644
--- a/drivers/iio/humidity/am2315.c
+++ b/drivers/iio/humidity/am2315.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* Aosong AM2315 relative humidity and temperature
*
* Copyright (c) 2016, Intel Corporation.
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index d62705448ae2..74383abc0d44 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -25,6 +25,10 @@ struct hid_humidity_state {
int value_offset;
};
+static const u32 humidity_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
+};
+
/* Channel definitions */
static const struct iio_chan_spec humidity_channels[] = {
{
@@ -176,14 +180,6 @@ static int humidity_parse_report(struct platform_device *pdev,
&st->scale_pre_decml,
&st->scale_post_decml);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->common_attributes.sensitivity.index < 0)
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
- &st->common_attributes.sensitivity);
-
return ret;
}
@@ -212,7 +208,9 @@ static int hid_humidity_probe(struct platform_device *pdev)
ret = hid_sensor_parse_common_attributes(hsdev,
HID_USAGE_SENSOR_HUMIDITY,
- &humid_st->common_attributes);
+ &humid_st->common_attributes,
+ humidity_sensitivity_addresses,
+ ARRAY_SIZE(humidity_sensitivity_addresses));
if (ret)
return ret;
diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c
index 95e56917677f..f29692b9d2db 100644
--- a/drivers/iio/humidity/hts221_buffer.c
+++ b/drivers/iio/humidity/hts221_buffer.c
@@ -135,7 +135,6 @@ int hts221_allocate_trigger(struct iio_dev *iio_dev)
iio_trigger_set_drvdata(hw->trig, iio_dev);
hw->trig->ops = &hts221_trigger_ops;
- hw->trig->dev.parent = hw->dev;
iio_dev->trig = iio_trigger_get(hw->trig);
return devm_iio_trigger_register(hw->dev, hw->trig);
diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index fced02cadcc3..8f4a9b264962 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -12,11 +12,17 @@
#include <linux/kernel.h>
#include <linux/device.h>
+struct iio_buffer;
struct iio_chan_spec;
struct iio_dev;
extern struct device_type iio_device_type;
+struct iio_dev_buffer_pair {
+ struct iio_dev *indio_dev;
+ struct iio_buffer *buffer;
+};
+
#define IIO_IOCTL_UNHANDLED 1
struct iio_ioctl_handler {
struct list_head entry;
@@ -43,9 +49,13 @@ int __iio_add_chan_devattr(const char *postfix,
u64 mask,
enum iio_shared_by shared_by,
struct device *dev,
+ struct iio_buffer *buffer,
struct list_head *attr_list);
void iio_free_chan_devattr_list(struct list_head *attr_list);
+int iio_device_register_sysfs_group(struct iio_dev *indio_dev,
+ const struct attribute_group *group);
+
ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals);
/* Event interface flags */
@@ -54,34 +64,36 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals);
#ifdef CONFIG_IIO_BUFFER
struct poll_table_struct;
-__poll_t iio_buffer_poll(struct file *filp,
- struct poll_table_struct *wait);
-ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf,
- size_t n, loff_t *f_ps);
+__poll_t iio_buffer_poll_wrapper(struct file *filp,
+ struct poll_table_struct *wait);
+ssize_t iio_buffer_read_wrapper(struct file *filp, char __user *buf,
+ size_t n, loff_t *f_ps);
-int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev);
-void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev);
+int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev);
+void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev);
-#define iio_buffer_poll_addr (&iio_buffer_poll)
-#define iio_buffer_read_outer_addr (&iio_buffer_read_outer)
+#define iio_buffer_poll_addr (&iio_buffer_poll_wrapper)
+#define iio_buffer_read_outer_addr (&iio_buffer_read_wrapper)
void iio_disable_all_buffers(struct iio_dev *indio_dev);
void iio_buffer_wakeup_poll(struct iio_dev *indio_dev);
+void iio_device_detach_buffers(struct iio_dev *indio_dev);
#else
#define iio_buffer_poll_addr NULL
#define iio_buffer_read_outer_addr NULL
-static inline int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
+static inline int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
{
return 0;
}
-static inline void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) {}
+static inline void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev) {}
static inline void iio_disable_all_buffers(struct iio_dev *indio_dev) {}
static inline void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) {}
+static inline void iio_device_detach_buffers(struct iio_dev *indio_dev) {}
#endif
diff --git a/drivers/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h
index 374816bc3e73..e1a56824e07f 100644
--- a/drivers/iio/iio_core_trigger.h
+++ b/drivers/iio/iio_core_trigger.h
@@ -9,8 +9,10 @@
/**
* iio_device_register_trigger_consumer() - set up an iio_dev to use triggers
* @indio_dev: iio_dev associated with the device that will consume the trigger
+ *
+ * Return 0 if successful, negative otherwise
**/
-void iio_device_register_trigger_consumer(struct iio_dev *indio_dev);
+int iio_device_register_trigger_consumer(struct iio_dev *indio_dev);
/**
* iio_device_unregister_trigger_consumer() - reverse the registration process
diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c
index 785a4ce606d8..768aa493a1a6 100644
--- a/drivers/iio/imu/adis16400.c
+++ b/drivers/iio/imu/adis16400.c
@@ -504,7 +504,6 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long info)
{
struct adis16400_state *st = iio_priv(indio_dev);
- struct mutex *slock = &st->adis.state_lock;
int ret, sps;
switch (info) {
@@ -517,18 +516,18 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
* Need to cache values so we can update if the frequency
* changes.
*/
- mutex_lock(slock);
+ adis_dev_lock(&st->adis);
st->filt_int = val;
/* Work out update to current value */
sps = st->variant->get_freq(st);
if (sps < 0) {
- mutex_unlock(slock);
+ adis_dev_unlock(&st->adis);
return sps;
}
ret = __adis16400_set_filter(indio_dev, sps,
val * 1000 + val2 / 1000);
- mutex_unlock(slock);
+ adis_dev_unlock(&st->adis);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
sps = val * 1000 + val2 / 1000;
@@ -536,9 +535,9 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
if (sps <= 0)
return -EINVAL;
- mutex_lock(slock);
+ adis_dev_lock(&st->adis);
ret = st->variant->set_freq(st, sps);
- mutex_unlock(slock);
+ adis_dev_unlock(&st->adis);
return ret;
default:
return -EINVAL;
@@ -549,7 +548,6 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long info)
{
struct adis16400_state *st = iio_priv(indio_dev);
- struct mutex *slock = &st->adis.state_lock;
int16_t val16;
int ret;
@@ -605,17 +603,17 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
*val = st->variant->temp_offset;
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- mutex_lock(slock);
+ adis_dev_lock(&st->adis);
/* Need both the number of taps and the sampling frequency */
ret = __adis_read_reg_16(&st->adis,
ADIS16400_SENS_AVG,
&val16);
if (ret) {
- mutex_unlock(slock);
+ adis_dev_unlock(&st->adis);
return ret;
}
ret = st->variant->get_freq(st);
- mutex_unlock(slock);
+ adis_dev_unlock(&st->adis);
if (ret)
return ret;
ret /= adis16400_3db_divisors[val16 & 0x07];
@@ -623,9 +621,9 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
*val2 = (ret % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
- mutex_lock(slock);
+ adis_dev_lock(&st->adis);
ret = st->variant->get_freq(st);
- mutex_unlock(slock);
+ adis_dev_unlock(&st->adis);
if (ret)
return ret;
*val = ret / 1000;
diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
index 197d48240991..8f6bea4b6608 100644
--- a/drivers/iio/imu/adis16475.c
+++ b/drivers/iio/imu/adis16475.c
@@ -17,6 +17,8 @@
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/irq.h>
+#include <linux/lcm.h>
+#include <linux/math.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
@@ -101,6 +103,7 @@ struct adis16475 {
u32 clk_freq;
bool burst32;
unsigned long lsb_flag;
+ u16 sync_mode;
/* Alignment needed for the timestamp */
__be16 data[ADIS16475_MAX_SCAN_DATA] __aligned(8);
};
@@ -117,6 +120,11 @@ enum {
ADIS16475_SCAN_CRC_FAILURE,
};
+static bool low_rate_allow;
+module_param(low_rate_allow, bool, 0444);
+MODULE_PARM_DESC(low_rate_allow,
+ "Allow IMU rates below the minimum advisable when external clk is used in SCALED mode (default: N)");
+
#ifdef CONFIG_DEBUG_FS
static ssize_t adis16475_show_firmware_revision(struct file *file,
char __user *userbuf,
@@ -253,25 +261,92 @@ static int adis16475_get_freq(struct adis16475 *st, u32 *freq)
{
int ret;
u16 dec;
+ u32 sample_rate = st->clk_freq;
+
+ adis_dev_lock(&st->adis);
+
+ if (st->sync_mode == ADIS16475_SYNC_SCALED) {
+ u16 sync_scale;
+
+ ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, &sync_scale);
+ if (ret)
+ goto error;
+
+ sample_rate = st->clk_freq * sync_scale;
+ }
- ret = adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, &dec);
+ ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, &dec);
if (ret)
- return -EINVAL;
+ goto error;
- *freq = DIV_ROUND_CLOSEST(st->clk_freq, dec + 1);
+ adis_dev_unlock(&st->adis);
+
+ *freq = DIV_ROUND_CLOSEST(sample_rate, dec + 1);
return 0;
+error:
+ adis_dev_unlock(&st->adis);
+ return ret;
}
static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
{
u16 dec;
int ret;
+ u32 sample_rate = st->clk_freq;
if (!freq)
return -EINVAL;
- dec = DIV_ROUND_CLOSEST(st->clk_freq, freq);
+ adis_dev_lock(&st->adis);
+ /*
+ * When using sync scaled mode, the input clock needs to be scaled so that we have
+ * an IMU sample rate between (optimally) 1900 and 2100. After this, we can use the
+ * decimation filter to lower the sampling rate in order to get what the user wants.
+ * Optimally, the user sample rate is a multiple of both the IMU sample rate and
+ * the input clock. Hence, calculating the sync_scale dynamically gives us better
+ * chances of achieving a perfect/integer value for DEC_RATE. The math here is:
+ * 1. lcm of the input clock and the desired output rate.
+ * 2. get the highest multiple of the previous result lower than the adis max rate.
+ * 3. The last result becomes the IMU sample rate. Use that to calculate SYNC_SCALE
+ * and DEC_RATE (to get the user output rate)
+ */
+ if (st->sync_mode == ADIS16475_SYNC_SCALED) {
+ unsigned long scaled_rate = lcm(st->clk_freq, freq);
+ int sync_scale;
+
+ /*
+ * If lcm is bigger than the IMU maximum sampling rate there's no perfect
+ * solution. In this case, we get the highest multiple of the input clock
+ * lower than the IMU max sample rate.
+ */
+ if (scaled_rate > 2100000)
+ scaled_rate = 2100000 / st->clk_freq * st->clk_freq;
+ else
+ scaled_rate = 2100000 / scaled_rate * scaled_rate;
+
+ /*
+ * This is not an hard requirement but it's not advised to run the IMU
+ * with a sample rate lower than 4000Hz due to possible undersampling
+ * issues. However, there are users that might really want to take the risk.
+ * Hence, we provide a module parameter for them. If set, we allow sample
+ * rates lower than 4KHz. By default, we won't allow this and we just roundup
+ * the rate to the next multiple of the input clock bigger than 4KHz. This
+ * is done like this as in some cases (when DEC_RATE is 0) might give
+ * us the closest value to the one desired by the user...
+ */
+ if (scaled_rate < 1900000 && !low_rate_allow)
+ scaled_rate = roundup(1900000, st->clk_freq);
+
+ sync_scale = scaled_rate / st->clk_freq;
+ ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, sync_scale);
+ if (ret)
+ goto error;
+
+ sample_rate = scaled_rate;
+ }
+
+ dec = DIV_ROUND_CLOSEST(sample_rate, freq);
if (dec)
dec--;
@@ -281,7 +356,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
ret = adis_write_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, dec);
if (ret)
- return ret;
+ goto error;
/*
* If decimation is used, then gyro and accel data will have meaningful
@@ -290,6 +365,9 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
assign_bit(ADIS16475_LSB_DEC_MASK, &st->lsb_flag, dec);
return 0;
+error:
+ adis_dev_unlock(&st->adis);
+ return ret;
}
/* The values are approximated. */
@@ -1085,6 +1163,7 @@ static int adis16475_config_sync_mode(struct adis16475 *st)
}
sync = &st->info->sync[sync_mode];
+ st->sync_mode = sync->sync_mode;
/* All the other modes require external input signal */
if (sync->sync_mode != ADIS16475_SYNC_OUTPUT) {
@@ -1112,37 +1191,20 @@ static int adis16475_config_sync_mode(struct adis16475 *st)
if (sync->sync_mode == ADIS16475_SYNC_SCALED) {
u16 up_scale;
- u32 scaled_out_freq = 0;
+
/*
- * If we are in scaled mode, we must have an up_scale.
- * In scaled mode the allowable input clock range is
- * 1 Hz to 128 Hz, and the allowable output range is
- * 1900 to 2100 Hz. Hence, a scale must be given to
- * get the allowable output.
+ * In sync scaled mode, the IMU sample rate is the clk_freq * sync_scale.
+ * Hence, default the IMU sample rate to the highest multiple of the input
+ * clock lower than the IMU max sample rate. The optimal range is
+ * 1900-2100 sps...
*/
- ret = device_property_read_u32(dev,
- "adi,scaled-output-hz",
- &scaled_out_freq);
- if (ret) {
- dev_err(dev, "adi,scaled-output-hz must be given when in scaled sync mode");
- return -EINVAL;
- } else if (scaled_out_freq < 1900 ||
- scaled_out_freq > 2100) {
- dev_err(dev, "Invalid value: %u for adi,scaled-output-hz",
- scaled_out_freq);
- return -EINVAL;
- }
-
- up_scale = DIV_ROUND_CLOSEST(scaled_out_freq,
- st->clk_freq);
+ up_scale = 2100 / st->clk_freq;
ret = __adis_write_reg_16(&st->adis,
ADIS16475_REG_UP_SCALE,
up_scale);
if (ret)
return ret;
-
- st->clk_freq = scaled_out_freq;
}
st->clk_freq *= 1000;
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index dfe86c589325..f81b86690b76 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -10,6 +10,7 @@
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/math.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
@@ -17,6 +18,7 @@
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/module.h>
+#include <linux/lcm.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -170,6 +172,11 @@ static const char * const adis16480_int_pin_names[4] = {
[ADIS16480_PIN_DIO4] = "DIO4",
};
+static bool low_rate_allow;
+module_param(low_rate_allow, bool, 0444);
+MODULE_PARM_DESC(low_rate_allow,
+ "Allow IMU rates below the minimum advisable when external clk is used in PPS mode (default: N)");
+
#ifdef CONFIG_DEBUG_FS
static ssize_t adis16480_show_firmware_revision(struct file *file,
@@ -312,7 +319,8 @@ static int adis16480_debugfs_init(struct iio_dev *indio_dev)
static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
{
struct adis16480 *st = iio_priv(indio_dev);
- unsigned int t, reg;
+ unsigned int t, sample_rate = st->clk_freq;
+ int ret;
if (val < 0 || val2 < 0)
return -EINVAL;
@@ -321,28 +329,65 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
if (t == 0)
return -EINVAL;
+ adis_dev_lock(&st->adis);
/*
- * When using PPS mode, the rate of data collection is equal to the
- * product of the external clock frequency and the scale factor in the
- * SYNC_SCALE register.
- * When using sync mode, or internal clock, the output data rate is
- * equal with the clock frequency divided by DEC_RATE + 1.
+ * When using PPS mode, the input clock needs to be scaled so that we have an IMU
+ * sample rate between (optimally) 4000 and 4250. After this, we can use the
+ * decimation filter to lower the sampling rate in order to get what the user wants.
+ * Optimally, the user sample rate is a multiple of both the IMU sample rate and
+ * the input clock. Hence, calculating the sync_scale dynamically gives us better
+ * chances of achieving a perfect/integer value for DEC_RATE. The math here is:
+ * 1. lcm of the input clock and the desired output rate.
+ * 2. get the highest multiple of the previous result lower than the adis max rate.
+ * 3. The last result becomes the IMU sample rate. Use that to calculate SYNC_SCALE
+ * and DEC_RATE (to get the user output rate)
*/
if (st->clk_mode == ADIS16480_CLK_PPS) {
- t = t / st->clk_freq;
- reg = ADIS16495_REG_SYNC_SCALE;
- } else {
- t = st->clk_freq / t;
- reg = ADIS16480_REG_DEC_RATE;
+ unsigned long scaled_rate = lcm(st->clk_freq, t);
+ int sync_scale;
+
+ /*
+ * If lcm is bigger than the IMU maximum sampling rate there's no perfect
+ * solution. In this case, we get the highest multiple of the input clock
+ * lower than the IMU max sample rate.
+ */
+ if (scaled_rate > st->chip_info->int_clk)
+ scaled_rate = st->chip_info->int_clk / st->clk_freq * st->clk_freq;
+ else
+ scaled_rate = st->chip_info->int_clk / scaled_rate * scaled_rate;
+
+ /*
+ * This is not an hard requirement but it's not advised to run the IMU
+ * with a sample rate lower than 4000Hz due to possible undersampling
+ * issues. However, there are users that might really want to take the risk.
+ * Hence, we provide a module parameter for them. If set, we allow sample
+ * rates lower than 4KHz. By default, we won't allow this and we just roundup
+ * the rate to the next multiple of the input clock bigger than 4KHz. This
+ * is done like this as in some cases (when DEC_RATE is 0) might give
+ * us the closest value to the one desired by the user...
+ */
+ if (scaled_rate < 4000000 && !low_rate_allow)
+ scaled_rate = roundup(4000000, st->clk_freq);
+
+ sync_scale = scaled_rate / st->clk_freq;
+ ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale);
+ if (ret)
+ goto error;
+
+ sample_rate = scaled_rate;
}
+ t = DIV_ROUND_CLOSEST(sample_rate, t);
+ if (t)
+ t--;
+
if (t > st->chip_info->max_dec_rate)
t = st->chip_info->max_dec_rate;
- if ((t != 0) && (st->clk_mode != ADIS16480_CLK_PPS))
- t--;
-
- return adis_write_reg_16(&st->adis, reg, t);
+ ret = __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
+error:
+ adis_dev_unlock(&st->adis);
+ return ret;
}
static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
@@ -350,34 +395,35 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
struct adis16480 *st = iio_priv(indio_dev);
uint16_t t;
int ret;
- unsigned int freq;
- unsigned int reg;
+ unsigned int freq, sample_rate = st->clk_freq;
- if (st->clk_mode == ADIS16480_CLK_PPS)
- reg = ADIS16495_REG_SYNC_SCALE;
- else
- reg = ADIS16480_REG_DEC_RATE;
+ adis_dev_lock(&st->adis);
+
+ if (st->clk_mode == ADIS16480_CLK_PPS) {
+ u16 sync_scale;
+
+ ret = __adis_read_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, &sync_scale);
+ if (ret)
+ goto error;
- ret = adis_read_reg_16(&st->adis, reg, &t);
+ sample_rate = st->clk_freq * sync_scale;
+ }
+
+ ret = __adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
if (ret)
- return ret;
+ goto error;
- /*
- * When using PPS mode, the rate of data collection is equal to the
- * product of the external clock frequency and the scale factor in the
- * SYNC_SCALE register.
- * When using sync mode, or internal clock, the output data rate is
- * equal with the clock frequency divided by DEC_RATE + 1.
- */
- if (st->clk_mode == ADIS16480_CLK_PPS)
- freq = st->clk_freq * t;
- else
- freq = st->clk_freq / (t + 1);
+ adis_dev_unlock(&st->adis);
+
+ freq = DIV_ROUND_CLOSEST(sample_rate, (t + 1));
*val = freq / 1000;
*val2 = (freq % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
+error:
+ adis_dev_unlock(&st->adis);
+ return ret;
}
enum {
@@ -552,7 +598,6 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int freq)
{
struct adis16480 *st = iio_priv(indio_dev);
- struct mutex *slock = &st->adis.state_lock;
unsigned int enable_mask, offset, reg;
unsigned int diff, best_diff;
unsigned int i, best_freq;
@@ -563,7 +608,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
offset = ad16480_filter_data[chan->scan_index][1];
enable_mask = BIT(offset + 2);
- mutex_lock(slock);
+ adis_dev_lock(&st->adis);
ret = __adis_read_reg_16(&st->adis, reg, &val);
if (ret)
@@ -591,7 +636,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
ret = __adis_write_reg_16(&st->adis, reg, val);
out_unlock:
- mutex_unlock(slock);
+ adis_dev_unlock(&st->adis);
return ret;
}
@@ -1278,6 +1323,20 @@ static int adis16480_probe(struct spi_device *spi)
st->clk_freq = clk_get_rate(st->ext_clk);
st->clk_freq *= 1000; /* micro */
+ if (st->clk_mode == ADIS16480_CLK_PPS) {
+ u16 sync_scale;
+
+ /*
+ * In PPS mode, the IMU sample rate is the clk_freq * sync_scale. Hence,
+ * default the IMU sample rate to the highest multiple of the input clock
+ * lower than the IMU max sample rate. The internal sample rate is the
+ * max...
+ */
+ sync_scale = st->chip_info->int_clk / st->clk_freq;
+ ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale);
+ if (ret)
+ return ret;
+ }
} else {
st->clk_freq = st->chip_info->int_clk;
}
diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c
index 64e0ba51cb18..0f29e56200af 100644
--- a/drivers/iio/imu/adis_trigger.c
+++ b/drivers/iio/imu/adis_trigger.c
@@ -27,13 +27,6 @@ static const struct iio_trigger_ops adis_trigger_ops = {
.set_trigger_state = &adis_data_rdy_trigger_set_state,
};
-static void adis_trigger_setup(struct adis *adis)
-{
- adis->trig->dev.parent = &adis->spi->dev;
- adis->trig->ops = &adis_trigger_ops;
- iio_trigger_set_drvdata(adis->trig, adis);
-}
-
static int adis_validate_irq_flag(struct adis *adis)
{
/*
@@ -72,7 +65,8 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
if (!adis->trig)
return -ENOMEM;
- adis_trigger_setup(adis);
+ adis->trig->ops = &adis_trigger_ops;
+ iio_trigger_set_drvdata(adis->trig, adis);
ret = adis_validate_irq_flag(adis);
if (ret)
diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c
index 3ceb76366313..40a570325b0a 100644
--- a/drivers/iio/imu/fxos8700_i2c.c
+++ b/drivers/iio/imu/fxos8700_i2c.c
@@ -26,8 +26,7 @@ static int fxos8700_i2c_probe(struct i2c_client *client,
regmap = devm_regmap_init_i2c(client, &fxos8700_regmap_config);
if (IS_ERR(regmap)) {
- dev_err(&client->dev, "Failed to register i2c regmap %d\n",
- (int)PTR_ERR(regmap));
+ dev_err(&client->dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap));
return PTR_ERR(regmap);
}
diff --git a/drivers/iio/imu/fxos8700_spi.c b/drivers/iio/imu/fxos8700_spi.c
index 57e7bb6444e7..27e694cce173 100644
--- a/drivers/iio/imu/fxos8700_spi.c
+++ b/drivers/iio/imu/fxos8700_spi.c
@@ -17,8 +17,7 @@ static int fxos8700_spi_probe(struct spi_device *spi)
regmap = devm_regmap_init_spi(spi, &fxos8700_regmap_config);
if (IS_ERR(regmap)) {
- dev_err(&spi->dev, "Failed to register spi regmap %d\n",
- (int)PTR_ERR(regmap));
+ dev_err(&spi->dev, "Failed to register spi regmap %ld\n", PTR_ERR(regmap));
return PTR_ERR(regmap);
}
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index 3441b0d61c5d..383cc3250342 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -709,7 +709,6 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
const char *name;
struct inv_icm42600_timestamp *ts;
struct iio_dev *indio_dev;
- struct iio_buffer *buffer;
int ret;
name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->name);
@@ -720,23 +719,22 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
if (!indio_dev)
return ERR_PTR(-ENOMEM);
- buffer = devm_iio_kfifo_allocate(dev);
- if (!buffer)
- return ERR_PTR(-ENOMEM);
-
ts = iio_priv(indio_dev);
inv_icm42600_timestamp_init(ts, inv_icm42600_odr_to_period(st->conf.accel.odr));
iio_device_set_drvdata(indio_dev, st);
indio_dev->name = name;
indio_dev->info = &inv_icm42600_accel_info;
- indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+ indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = inv_icm42600_accel_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_accel_channels);
indio_dev->available_scan_masks = inv_icm42600_accel_scan_masks;
- indio_dev->setup_ops = &inv_icm42600_buffer_ops;
- iio_device_attach_buffer(indio_dev, buffer);
+ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &inv_icm42600_buffer_ops);
+ if (ret)
+ return ERR_PTR(ret);
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
index aee7b9ff4bf4..cec1dd0e0464 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
@@ -720,7 +720,6 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
const char *name;
struct inv_icm42600_timestamp *ts;
struct iio_dev *indio_dev;
- struct iio_buffer *buffer;
int ret;
name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->name);
@@ -731,23 +730,23 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
if (!indio_dev)
return ERR_PTR(-ENOMEM);
- buffer = devm_iio_kfifo_allocate(dev);
- if (!buffer)
- return ERR_PTR(-ENOMEM);
-
ts = iio_priv(indio_dev);
inv_icm42600_timestamp_init(ts, inv_icm42600_odr_to_period(st->conf.gyro.odr));
iio_device_set_drvdata(indio_dev, st);
indio_dev->name = name;
indio_dev->info = &inv_icm42600_gyro_info;
- indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+ indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = inv_icm42600_gyro_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_gyro_channels);
indio_dev->available_scan_masks = inv_icm42600_gyro_scan_masks;
indio_dev->setup_ops = &inv_icm42600_buffer_ops;
- iio_device_attach_buffer(indio_dev, buffer);
+ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &inv_icm42600_buffer_ops);
+ if (ret)
+ return ERR_PTR(ret);
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index 4377047d503a..fc5a60fcfec0 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -1268,7 +1268,6 @@ static struct iio_trigger *kmx61_trigger_setup(struct kmx61_data *data,
if (!trig)
return ERR_PTR(-ENOMEM);
- trig->dev.parent = &data->client->dev;
trig->ops = &kmx61_trigger_ops;
iio_trigger_set_drvdata(trig, indio_dev);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
index f1103ecedd64..16730a780964 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -739,20 +739,17 @@ static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = {
int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
{
- struct iio_buffer *buffer;
- int i;
+ int i, ret;
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
if (!hw->iio_devs[i])
continue;
- buffer = devm_iio_kfifo_allocate(hw->dev);
- if (!buffer)
- return -ENOMEM;
-
- iio_device_attach_buffer(hw->iio_devs[i], buffer);
- hw->iio_devs[i]->modes |= INDIO_BUFFER_SOFTWARE;
- hw->iio_devs[i]->setup_ops = &st_lsm6dsx_buffer_ops;
+ ret = devm_iio_kfifo_buffer_setup(hw->dev, hw->iio_devs[i],
+ INDIO_BUFFER_SOFTWARE,
+ &st_lsm6dsx_buffer_ops);
+ if (ret)
+ return ret;
}
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 ec8d4351390a..8b4fc2c15622 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
@@ -29,8 +29,7 @@ static int st_lsm6dsx_i2c_probe(struct i2c_client *client,
regmap = devm_regmap_init_i2c(client, &st_lsm6dsx_i2c_regmap_config);
if (IS_ERR(regmap)) {
- dev_err(&client->dev, "Failed to register i2c regmap %d\n",
- (int)PTR_ERR(regmap));
+ dev_err(&client->dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap));
return PTR_ERR(regmap);
}
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c
index 57e633121bdc..8d4201b86e87 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c
@@ -34,8 +34,7 @@ static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev)
regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config);
if (IS_ERR(regmap)) {
- dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n",
- (int)PTR_ERR(regmap));
+ dev_err(&i3cdev->dev, "Failed to register i3c regmap %ld\n", PTR_ERR(regmap));
return PTR_ERR(regmap);
}
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
index 349ec9c1890d..e80110b6b280 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
@@ -29,8 +29,7 @@ static int st_lsm6dsx_spi_probe(struct spi_device *spi)
regmap = devm_regmap_init_spi(spi, &st_lsm6dsx_spi_regmap_config);
if (IS_ERR(regmap)) {
- dev_err(&spi->dev, "Failed to register spi regmap %d\n",
- (int)PTR_ERR(regmap));
+ dev_err(&spi->dev, "Failed to register spi regmap %ld\n", PTR_ERR(regmap));
return PTR_ERR(regmap);
}
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 2f7426a2f47c..ee5aab9d4a23 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -9,9 +9,11 @@
* - Better memory allocation techniques?
* - Alternative access techniques?
*/
+#include <linux/anon_inodes.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/device.h>
+#include <linux/file.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
@@ -89,7 +91,7 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
}
/**
- * iio_buffer_read_outer() - chrdev read for buffer access
+ * iio_buffer_read() - chrdev read for buffer access
* @filp: File structure pointer for the char device
* @buf: Destination buffer for iio buffer read
* @n: First n bytes to read
@@ -101,11 +103,12 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
* Return: negative values corresponding to error codes or ret != 0
* for ending the reading activity
**/
-ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf,
- size_t n, loff_t *f_ps)
+static ssize_t iio_buffer_read(struct file *filp, char __user *buf,
+ size_t n, loff_t *f_ps)
{
- struct iio_dev *indio_dev = filp->private_data;
- struct iio_buffer *rb = indio_dev->buffer;
+ struct iio_dev_buffer_pair *ib = filp->private_data;
+ struct iio_buffer *rb = ib->buffer;
+ struct iio_dev *indio_dev = ib->indio_dev;
DEFINE_WAIT_FUNC(wait, woken_wake_function);
size_t datum_size;
size_t to_wait;
@@ -167,11 +170,12 @@ ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf,
* Return: (EPOLLIN | EPOLLRDNORM) if data is available for reading
* or 0 for other cases
*/
-__poll_t iio_buffer_poll(struct file *filp,
- struct poll_table_struct *wait)
+static __poll_t iio_buffer_poll(struct file *filp,
+ struct poll_table_struct *wait)
{
- struct iio_dev *indio_dev = filp->private_data;
- struct iio_buffer *rb = indio_dev->buffer;
+ struct iio_dev_buffer_pair *ib = filp->private_data;
+ struct iio_buffer *rb = ib->buffer;
+ struct iio_dev *indio_dev = ib->indio_dev;
if (!indio_dev->info || rb == NULL)
return 0;
@@ -182,6 +186,32 @@ __poll_t iio_buffer_poll(struct file *filp,
return 0;
}
+ssize_t iio_buffer_read_wrapper(struct file *filp, char __user *buf,
+ size_t n, loff_t *f_ps)
+{
+ struct iio_dev_buffer_pair *ib = filp->private_data;
+ struct iio_buffer *rb = ib->buffer;
+
+ /* check if buffer was opened through new API */
+ if (test_bit(IIO_BUSY_BIT_POS, &rb->flags))
+ return -EBUSY;
+
+ return iio_buffer_read(filp, buf, n, f_ps);
+}
+
+__poll_t iio_buffer_poll_wrapper(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct iio_dev_buffer_pair *ib = filp->private_data;
+ struct iio_buffer *rb = ib->buffer;
+
+ /* check if buffer was opened through new API */
+ if (test_bit(IIO_BUSY_BIT_POS, &rb->flags))
+ return 0;
+
+ return iio_buffer_poll(filp, wait);
+}
+
/**
* iio_buffer_wakeup_poll - Wakes up the buffer waitqueue
* @indio_dev: The IIO device
@@ -191,12 +221,14 @@ __poll_t iio_buffer_poll(struct file *filp,
*/
void iio_buffer_wakeup_poll(struct iio_dev *indio_dev)
{
- struct iio_buffer *buffer = indio_dev->buffer;
-
- if (!buffer)
- return;
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ struct iio_buffer *buffer;
+ unsigned int i;
- wake_up(&buffer->pollq);
+ for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) {
+ buffer = iio_dev_opaque->attached_buffers[i];
+ wake_up(&buffer->pollq);
+ }
}
void iio_buffer_init(struct iio_buffer *buffer)
@@ -210,6 +242,20 @@ void iio_buffer_init(struct iio_buffer *buffer)
}
EXPORT_SYMBOL(iio_buffer_init);
+void iio_device_detach_buffers(struct iio_dev *indio_dev)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ struct iio_buffer *buffer;
+ unsigned int i;
+
+ for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) {
+ buffer = iio_dev_opaque->attached_buffers[i];
+ iio_buffer_put(buffer);
+ }
+
+ kfree(iio_dev_opaque->attached_buffers);
+}
+
static ssize_t iio_show_scan_index(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -253,8 +299,7 @@ static ssize_t iio_scan_el_show(struct device *dev,
char *buf)
{
int ret;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
/* Ensure ret is 0 or 1. */
ret = !!test_bit(to_iio_dev_attr(attr)->address,
@@ -367,8 +412,8 @@ static ssize_t iio_scan_el_store(struct device *dev,
int ret;
bool state;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct iio_buffer *buffer = this_attr->buffer;
ret = strtobool(buf, &state);
if (ret < 0)
@@ -402,8 +447,7 @@ static ssize_t iio_scan_el_ts_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
return sprintf(buf, "%d\n", buffer->scan_timestamp);
}
@@ -415,7 +459,7 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
bool state;
ret = strtobool(buf, &state);
@@ -447,7 +491,8 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
0,
IIO_SEPARATE,
&indio_dev->dev,
- &buffer->scan_el_dev_attr_list);
+ buffer,
+ &buffer->buffer_attr_list);
if (ret)
return ret;
attrcount++;
@@ -458,7 +503,8 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
0,
0,
&indio_dev->dev,
- &buffer->scan_el_dev_attr_list);
+ buffer,
+ &buffer->buffer_attr_list);
if (ret)
return ret;
attrcount++;
@@ -470,7 +516,8 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
chan->scan_index,
0,
&indio_dev->dev,
- &buffer->scan_el_dev_attr_list);
+ buffer,
+ &buffer->buffer_attr_list);
else
ret = __iio_add_chan_devattr("en",
chan,
@@ -479,7 +526,8 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
chan->scan_index,
0,
&indio_dev->dev,
- &buffer->scan_el_dev_attr_list);
+ buffer,
+ &buffer->buffer_attr_list);
if (ret)
return ret;
attrcount++;
@@ -491,8 +539,7 @@ static ssize_t iio_buffer_read_length(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
return sprintf(buf, "%d\n", buffer->length);
}
@@ -502,7 +549,7 @@ static ssize_t iio_buffer_write_length(struct device *dev,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
unsigned int val;
int ret;
@@ -534,8 +581,7 @@ static ssize_t iio_buffer_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
return sprintf(buf, "%d\n", iio_buffer_is_active(buffer));
}
@@ -1150,7 +1196,7 @@ static ssize_t iio_buffer_store_enable(struct device *dev,
int ret;
bool requested_state;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
bool inlist;
ret = strtobool(buf, &requested_state);
@@ -1175,14 +1221,11 @@ done:
return (ret < 0) ? ret : len;
}
-static const char * const iio_scan_elements_group_name = "scan_elements";
-
static ssize_t iio_buffer_show_watermark(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
return sprintf(buf, "%u\n", buffer->watermark);
}
@@ -1193,7 +1236,7 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
unsigned int val;
int ret;
@@ -1226,8 +1269,7 @@ static ssize_t iio_dma_show_data_available(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
return sprintf(buf, "%zu\n", iio_buffer_data_available(buffer));
}
@@ -1252,45 +1294,193 @@ static struct attribute *iio_buffer_attrs[] = {
&dev_attr_data_available.attr,
};
-static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
- struct iio_dev *indio_dev)
+#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
+
+static struct attribute *iio_buffer_wrap_attr(struct iio_buffer *buffer,
+ struct attribute *attr)
{
- struct iio_dev_attr *p;
- struct attribute **attr;
- int ret, i, attrn, attrcount;
- const struct iio_chan_spec *channels;
+ struct device_attribute *dattr = to_dev_attr(attr);
+ struct iio_dev_attr *iio_attr;
- attrcount = 0;
- if (buffer->attrs) {
- while (buffer->attrs[attrcount] != NULL)
- attrcount++;
- }
+ iio_attr = kzalloc(sizeof(*iio_attr), GFP_KERNEL);
+ if (!iio_attr)
+ return NULL;
+
+ iio_attr->buffer = buffer;
+ memcpy(&iio_attr->dev_attr, dattr, sizeof(iio_attr->dev_attr));
+ iio_attr->dev_attr.attr.name = kstrdup_const(attr->name, GFP_KERNEL);
+
+ list_add(&iio_attr->l, &buffer->buffer_attr_list);
+
+ return &iio_attr->dev_attr.attr;
+}
+
+static int iio_buffer_register_legacy_sysfs_groups(struct iio_dev *indio_dev,
+ struct attribute **buffer_attrs,
+ int buffer_attrcount,
+ int scan_el_attrcount)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ struct attribute_group *group;
+ struct attribute **attrs;
+ int ret;
- attr = kcalloc(attrcount + ARRAY_SIZE(iio_buffer_attrs) + 1,
- sizeof(struct attribute *), GFP_KERNEL);
- if (!attr)
+ attrs = kcalloc(buffer_attrcount + 1, sizeof(*attrs), GFP_KERNEL);
+ if (!attrs)
return -ENOMEM;
- memcpy(attr, iio_buffer_attrs, sizeof(iio_buffer_attrs));
- if (!buffer->access->set_length)
- attr[0] = &dev_attr_length_ro.attr;
+ memcpy(attrs, buffer_attrs, buffer_attrcount * sizeof(*attrs));
- if (buffer->access->flags & INDIO_BUFFER_FLAG_FIXED_WATERMARK)
- attr[2] = &dev_attr_watermark_ro.attr;
+ group = &iio_dev_opaque->legacy_buffer_group;
+ group->attrs = attrs;
+ group->name = "buffer";
- if (buffer->attrs)
- memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs,
- sizeof(struct attribute *) * attrcount);
+ ret = iio_device_register_sysfs_group(indio_dev, group);
+ if (ret)
+ goto error_free_buffer_attrs;
+
+ attrs = kcalloc(scan_el_attrcount + 1, sizeof(*attrs), GFP_KERNEL);
+ if (!attrs) {
+ ret = -ENOMEM;
+ goto error_free_buffer_attrs;
+ }
- attr[attrcount + ARRAY_SIZE(iio_buffer_attrs)] = NULL;
+ memcpy(attrs, &buffer_attrs[buffer_attrcount],
+ scan_el_attrcount * sizeof(*attrs));
- buffer->buffer_group.name = "buffer";
- buffer->buffer_group.attrs = attr;
+ group = &iio_dev_opaque->legacy_scan_el_group;
+ group->attrs = attrs;
+ group->name = "scan_elements";
- indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group;
+ ret = iio_device_register_sysfs_group(indio_dev, group);
+ if (ret)
+ goto error_free_scan_el_attrs;
+
+ return 0;
+
+error_free_buffer_attrs:
+ kfree(iio_dev_opaque->legacy_buffer_group.attrs);
+error_free_scan_el_attrs:
+ kfree(iio_dev_opaque->legacy_scan_el_group.attrs);
+
+ return ret;
+}
+
+static void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+
+ kfree(iio_dev_opaque->legacy_buffer_group.attrs);
+ kfree(iio_dev_opaque->legacy_scan_el_group.attrs);
+}
- attrcount = 0;
- INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
+static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep)
+{
+ struct iio_dev_buffer_pair *ib = filep->private_data;
+ struct iio_dev *indio_dev = ib->indio_dev;
+ struct iio_buffer *buffer = ib->buffer;
+
+ wake_up(&buffer->pollq);
+
+ kfree(ib);
+ clear_bit(IIO_BUSY_BIT_POS, &buffer->flags);
+ iio_device_put(indio_dev);
+
+ return 0;
+}
+
+static const struct file_operations iio_buffer_chrdev_fileops = {
+ .owner = THIS_MODULE,
+ .llseek = noop_llseek,
+ .read = iio_buffer_read,
+ .poll = iio_buffer_poll,
+ .release = iio_buffer_chrdev_release,
+};
+
+static long iio_device_buffer_getfd(struct iio_dev *indio_dev, unsigned long arg)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ int __user *ival = (int __user *)arg;
+ struct iio_dev_buffer_pair *ib;
+ struct iio_buffer *buffer;
+ int fd, idx, ret;
+
+ if (copy_from_user(&idx, ival, sizeof(idx)))
+ return -EFAULT;
+
+ if (idx >= iio_dev_opaque->attached_buffers_cnt)
+ return -ENODEV;
+
+ iio_device_get(indio_dev);
+
+ buffer = iio_dev_opaque->attached_buffers[idx];
+
+ if (test_and_set_bit(IIO_BUSY_BIT_POS, &buffer->flags)) {
+ ret = -EBUSY;
+ goto error_iio_dev_put;
+ }
+
+ ib = kzalloc(sizeof(*ib), GFP_KERNEL);
+ if (!ib) {
+ ret = -ENOMEM;
+ goto error_clear_busy_bit;
+ }
+
+ ib->indio_dev = indio_dev;
+ ib->buffer = buffer;
+
+ fd = anon_inode_getfd("iio:buffer", &iio_buffer_chrdev_fileops,
+ ib, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ ret = fd;
+ goto error_free_ib;
+ }
+
+ if (copy_to_user(ival, &fd, sizeof(fd))) {
+ put_unused_fd(fd);
+ ret = -EFAULT;
+ goto error_free_ib;
+ }
+
+ return fd;
+
+error_free_ib:
+ kfree(ib);
+error_clear_busy_bit:
+ clear_bit(IIO_BUSY_BIT_POS, &buffer->flags);
+error_iio_dev_put:
+ iio_device_put(indio_dev);
+ return ret;
+}
+
+static long iio_device_buffer_ioctl(struct iio_dev *indio_dev, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case IIO_BUFFER_GET_FD_IOCTL:
+ return iio_device_buffer_getfd(indio_dev, arg);
+ default:
+ return IIO_IOCTL_UNHANDLED;
+ }
+}
+
+static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
+ struct iio_dev *indio_dev,
+ int index)
+{
+ struct iio_dev_attr *p;
+ struct attribute **attr;
+ int ret, i, attrn, scan_el_attrcount, buffer_attrcount;
+ const struct iio_chan_spec *channels;
+
+ buffer_attrcount = 0;
+ if (buffer->attrs) {
+ while (buffer->attrs[buffer_attrcount] != NULL)
+ buffer_attrcount++;
+ }
+
+ scan_el_attrcount = 0;
+ INIT_LIST_HEAD(&buffer->buffer_attr_list);
channels = indio_dev->channels;
if (channels) {
/* new magic */
@@ -1302,7 +1492,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
&channels[i]);
if (ret < 0)
goto error_cleanup_dynamic;
- attrcount += ret;
+ scan_el_attrcount += ret;
if (channels[i].type == IIO_TIMESTAMP)
indio_dev->scan_index_timestamp =
channels[i].scan_index;
@@ -1317,37 +1507,93 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
}
}
- buffer->scan_el_group.name = iio_scan_elements_group_name;
-
- buffer->scan_el_group.attrs = kcalloc(attrcount + 1,
- sizeof(buffer->scan_el_group.attrs[0]),
- GFP_KERNEL);
- if (buffer->scan_el_group.attrs == NULL) {
+ attrn = buffer_attrcount + scan_el_attrcount + ARRAY_SIZE(iio_buffer_attrs);
+ attr = kcalloc(attrn + 1, sizeof(* attr), GFP_KERNEL);
+ if (!attr) {
ret = -ENOMEM;
goto error_free_scan_mask;
}
+
+ memcpy(attr, iio_buffer_attrs, sizeof(iio_buffer_attrs));
+ if (!buffer->access->set_length)
+ attr[0] = &dev_attr_length_ro.attr;
+
+ if (buffer->access->flags & INDIO_BUFFER_FLAG_FIXED_WATERMARK)
+ attr[2] = &dev_attr_watermark_ro.attr;
+
+ if (buffer->attrs)
+ memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs,
+ sizeof(struct attribute *) * buffer_attrcount);
+
+ buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs);
+
+ for (i = 0; i < buffer_attrcount; i++) {
+ struct attribute *wrapped;
+
+ wrapped = iio_buffer_wrap_attr(buffer, attr[i]);
+ if (!wrapped) {
+ ret = -ENOMEM;
+ goto error_free_scan_mask;
+ }
+ attr[i] = wrapped;
+ }
+
attrn = 0;
+ list_for_each_entry(p, &buffer->buffer_attr_list, l)
+ attr[attrn++] = &p->dev_attr.attr;
+
+ buffer->buffer_group.name = kasprintf(GFP_KERNEL, "buffer%d", index);
+ if (!buffer->buffer_group.name) {
+ ret = -ENOMEM;
+ goto error_free_buffer_attrs;
+ }
+
+ buffer->buffer_group.attrs = attr;
+
+ ret = iio_device_register_sysfs_group(indio_dev, &buffer->buffer_group);
+ if (ret)
+ goto error_free_buffer_attr_group_name;
+
+ /* we only need to register the legacy groups for the first buffer */
+ if (index > 0)
+ return 0;
- list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
- buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
- indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group;
+ ret = iio_buffer_register_legacy_sysfs_groups(indio_dev, attr,
+ buffer_attrcount,
+ scan_el_attrcount);
+ if (ret)
+ goto error_free_buffer_attr_group_name;
return 0;
+error_free_buffer_attr_group_name:
+ kfree(buffer->buffer_group.name);
+error_free_buffer_attrs:
+ kfree(buffer->buffer_group.attrs);
error_free_scan_mask:
bitmap_free(buffer->scan_mask);
error_cleanup_dynamic:
- iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
- kfree(buffer->buffer_group.attrs);
+ iio_free_chan_devattr_list(&buffer->buffer_attr_list);
return ret;
}
-int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
+static void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer)
+{
+ bitmap_free(buffer->scan_mask);
+ kfree(buffer->buffer_group.name);
+ kfree(buffer->buffer_group.attrs);
+ iio_free_chan_devattr_list(&buffer->buffer_attr_list);
+}
+
+int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
{
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
const struct iio_chan_spec *channels;
- int i;
+ struct iio_buffer *buffer;
+ int unwind_idx;
+ int ret, i;
+ size_t sz;
channels = indio_dev->channels;
if (channels) {
@@ -1358,28 +1604,58 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
indio_dev->masklength = ml;
}
- if (!buffer)
+ if (!iio_dev_opaque->attached_buffers_cnt)
return 0;
- return __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev);
-}
+ for (i = 0; i < iio_dev_opaque->attached_buffers_cnt; i++) {
+ buffer = iio_dev_opaque->attached_buffers[i];
+ ret = __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev, i);
+ if (ret) {
+ unwind_idx = i;
+ goto error_unwind_sysfs_and_mask;
+ }
+ }
+ unwind_idx = iio_dev_opaque->attached_buffers_cnt - 1;
-static void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer)
-{
- bitmap_free(buffer->scan_mask);
- kfree(buffer->buffer_group.attrs);
- kfree(buffer->scan_el_group.attrs);
- iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
+ sz = sizeof(*(iio_dev_opaque->buffer_ioctl_handler));
+ iio_dev_opaque->buffer_ioctl_handler = kzalloc(sz, GFP_KERNEL);
+ if (!iio_dev_opaque->buffer_ioctl_handler) {
+ ret = -ENOMEM;
+ goto error_unwind_sysfs_and_mask;
+ }
+
+ iio_dev_opaque->buffer_ioctl_handler->ioctl = iio_device_buffer_ioctl;
+ iio_device_ioctl_handler_register(indio_dev,
+ iio_dev_opaque->buffer_ioctl_handler);
+
+ return 0;
+
+error_unwind_sysfs_and_mask:
+ for (; unwind_idx >= 0; unwind_idx--) {
+ buffer = iio_dev_opaque->attached_buffers[unwind_idx];
+ __iio_buffer_free_sysfs_and_mask(buffer);
+ }
+ return ret;
}
-void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev)
+void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev)
{
- struct iio_buffer *buffer = indio_dev->buffer;
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ struct iio_buffer *buffer;
+ int i;
- if (!buffer)
+ if (!iio_dev_opaque->attached_buffers_cnt)
return;
- __iio_buffer_free_sysfs_and_mask(buffer);
+ iio_device_ioctl_handler_unregister(iio_dev_opaque->buffer_ioctl_handler);
+ kfree(iio_dev_opaque->buffer_ioctl_handler);
+
+ iio_buffer_unregister_legacy_sysfs_groups(indio_dev);
+
+ for (i = iio_dev_opaque->attached_buffers_cnt - 1; i >= 0; i--) {
+ buffer = iio_dev_opaque->attached_buffers[i];
+ __iio_buffer_free_sysfs_and_mask(buffer);
+ }
}
/**
@@ -1497,13 +1773,37 @@ EXPORT_SYMBOL_GPL(iio_buffer_put);
* @indio_dev: The device the buffer should be attached to
* @buffer: The buffer to attach to the device
*
+ * Return 0 if successful, negative if error.
+ *
* This function attaches a buffer to a IIO device. The buffer stays attached to
- * the device until the device is freed. The function should only be called at
- * most once per device.
+ * the device until the device is freed. For legacy reasons, the first attached
+ * buffer will also be assigned to 'indio_dev->buffer'.
+ * The array allocated here, will be free'd via the iio_device_detach_buffers()
+ * call which is handled by the iio_device_free().
*/
-void iio_device_attach_buffer(struct iio_dev *indio_dev,
- struct iio_buffer *buffer)
+int iio_device_attach_buffer(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer)
{
- indio_dev->buffer = iio_buffer_get(buffer);
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ struct iio_buffer **new, **old = iio_dev_opaque->attached_buffers;
+ unsigned int cnt = iio_dev_opaque->attached_buffers_cnt;
+
+ cnt++;
+
+ new = krealloc(old, sizeof(*new) * cnt, GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+ iio_dev_opaque->attached_buffers = new;
+
+ buffer = iio_buffer_get(buffer);
+
+ /* first buffer is legacy; attach it to the IIO device directly */
+ if (!indio_dev->buffer)
+ indio_dev->buffer = buffer;
+
+ iio_dev_opaque->attached_buffers[cnt - 1] = buffer;
+ iio_dev_opaque->attached_buffers_cnt = cnt;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(iio_device_attach_buffer);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 7db761afa578..b5750edf935c 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -157,6 +157,7 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_PHASE] = "phase",
[IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
[IIO_CHAN_INFO_HYSTERESIS] = "hysteresis",
+ [IIO_CHAN_INFO_HYSTERESIS_RELATIVE] = "hysteresis_relative",
[IIO_CHAN_INFO_INT_TIME] = "integration_time",
[IIO_CHAN_INFO_ENABLE] = "en",
[IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
@@ -625,7 +626,6 @@ EXPORT_SYMBOL(iio_read_mount_matrix);
static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
int size, const int *vals)
{
- unsigned long long tmp;
int tmp0, tmp1;
s64 tmp2;
bool scale_db = false;
@@ -658,9 +658,12 @@ static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
else
return snprintf(buf, len, "%d.%09u", tmp0, abs(tmp1));
case IIO_VAL_FRACTIONAL_LOG2:
- tmp = shift_right((s64)vals[0] * 1000000000LL, vals[1]);
- tmp0 = (int)div_s64_rem(tmp, 1000000000LL, &tmp1);
- return scnprintf(buf, len, "%d.%09u", tmp0, abs(tmp1));
+ tmp2 = shift_right((s64)vals[0] * 1000000000LL, vals[1]);
+ tmp0 = (int)div_s64_rem(tmp2, 1000000000LL, &tmp1);
+ if (tmp0 == 0 && tmp2 < 0)
+ return snprintf(buf, len, "-0.%09u", abs(tmp1));
+ else
+ return scnprintf(buf, len, "%d.%09u", tmp0, abs(tmp1));
case IIO_VAL_INT_MULTIPLE:
{
int i;
@@ -1114,6 +1117,7 @@ int __iio_add_chan_devattr(const char *postfix,
u64 mask,
enum iio_shared_by shared_by,
struct device *dev,
+ struct iio_buffer *buffer,
struct list_head *attr_list)
{
int ret;
@@ -1129,6 +1133,7 @@ int __iio_add_chan_devattr(const char *postfix,
goto error_iio_dev_attr_free;
iio_attr->c = chan;
iio_attr->address = mask;
+ iio_attr->buffer = buffer;
list_for_each_entry(t, attr_list, l)
if (strcmp(t->dev_attr.attr.name,
iio_attr->dev_attr.attr.name) == 0) {
@@ -1165,6 +1170,7 @@ static int iio_device_add_channel_label(struct iio_dev *indio_dev,
0,
IIO_SEPARATE,
&indio_dev->dev,
+ NULL,
&iio_dev_opaque->channel_attr_list);
if (ret < 0)
return ret;
@@ -1190,6 +1196,7 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev,
i,
shared_by,
&indio_dev->dev,
+ NULL,
&iio_dev_opaque->channel_attr_list);
if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE))
continue;
@@ -1226,6 +1233,7 @@ static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev,
i,
shared_by,
&indio_dev->dev,
+ NULL,
&iio_dev_opaque->channel_attr_list);
kfree(avail_postfix);
if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE))
@@ -1322,6 +1330,7 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
i,
ext_info->shared,
&indio_dev->dev,
+ NULL,
&iio_dev_opaque->channel_attr_list);
i++;
if (ret == -EBUSY && ext_info->shared)
@@ -1349,7 +1358,7 @@ void iio_free_chan_devattr_list(struct list_head *attr_list)
struct iio_dev_attr *p, *n;
list_for_each_entry_safe(p, n, attr_list, l) {
- kfree(p->dev_attr.attr.name);
+ kfree_const(p->dev_attr.attr.name);
list_del(&p->l);
kfree(p);
}
@@ -1452,6 +1461,25 @@ static ssize_t iio_store_timestamp_clock(struct device *dev,
return len;
}
+int iio_device_register_sysfs_group(struct iio_dev *indio_dev,
+ const struct attribute_group *group)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ const struct attribute_group **new, **old = iio_dev_opaque->groups;
+ unsigned int cnt = iio_dev_opaque->groupcounter;
+
+ new = krealloc(old, sizeof(*new) * (cnt + 2), GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+
+ new[iio_dev_opaque->groupcounter++] = group;
+ new[iio_dev_opaque->groupcounter] = NULL;
+
+ iio_dev_opaque->groups = new;
+
+ return 0;
+}
+
static DEVICE_ATTR(current_timestamp_clock, S_IRUGO | S_IWUSR,
iio_show_timestamp_clock, iio_store_timestamp_clock);
@@ -1525,8 +1553,10 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
if (clk)
iio_dev_opaque->chan_attr_group.attrs[attrn++] = clk;
- indio_dev->groups[indio_dev->groupcounter++] =
- &iio_dev_opaque->chan_attr_group;
+ ret = iio_device_register_sysfs_group(indio_dev,
+ &iio_dev_opaque->chan_attr_group);
+ if (ret)
+ goto error_clear_attrs;
return 0;
@@ -1543,6 +1573,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list);
kfree(iio_dev_opaque->chan_attr_group.attrs);
iio_dev_opaque->chan_attr_group.attrs = NULL;
+ kfree(iio_dev_opaque->groups);
}
static void iio_dev_release(struct device *device)
@@ -1555,7 +1586,7 @@ static void iio_dev_release(struct device *device)
iio_device_unregister_eventset(indio_dev);
iio_device_unregister_sysfs(indio_dev);
- iio_buffer_put(indio_dev->buffer);
+ iio_device_detach_buffers(indio_dev);
ida_simple_remove(&iio_ida, indio_dev->id);
kfree(iio_dev_opaque);
@@ -1574,7 +1605,7 @@ struct device_type iio_device_type = {
struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
{
struct iio_dev_opaque *iio_dev_opaque;
- struct iio_dev *dev;
+ struct iio_dev *indio_dev;
size_t alloc_size;
alloc_size = sizeof(struct iio_dev_opaque);
@@ -1587,32 +1618,31 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
if (!iio_dev_opaque)
return NULL;
- dev = &iio_dev_opaque->indio_dev;
- dev->priv = (char *)iio_dev_opaque +
+ indio_dev = &iio_dev_opaque->indio_dev;
+ indio_dev->priv = (char *)iio_dev_opaque +
ALIGN(sizeof(struct iio_dev_opaque), IIO_ALIGN);
- dev->dev.parent = parent;
- dev->dev.groups = dev->groups;
- dev->dev.type = &iio_device_type;
- dev->dev.bus = &iio_bus_type;
- device_initialize(&dev->dev);
- dev_set_drvdata(&dev->dev, (void *)dev);
- mutex_init(&dev->mlock);
- mutex_init(&dev->info_exist_lock);
+ indio_dev->dev.parent = parent;
+ indio_dev->dev.type = &iio_device_type;
+ indio_dev->dev.bus = &iio_bus_type;
+ device_initialize(&indio_dev->dev);
+ iio_device_set_drvdata(indio_dev, (void *)indio_dev);
+ mutex_init(&indio_dev->mlock);
+ mutex_init(&indio_dev->info_exist_lock);
INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list);
- dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
- if (dev->id < 0) {
+ indio_dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
+ if (indio_dev->id < 0) {
/* cannot use a dev_err as the name isn't available */
pr_err("failed to get device id\n");
kfree(iio_dev_opaque);
return NULL;
}
- dev_set_name(&dev->dev, "iio:device%d", dev->id);
+ dev_set_name(&indio_dev->dev, "iio:device%d", indio_dev->id);
INIT_LIST_HEAD(&iio_dev_opaque->buffer_list);
INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers);
- return dev;
+ return indio_dev;
}
EXPORT_SYMBOL(iio_device_alloc);
@@ -1676,13 +1706,24 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp)
{
struct iio_dev *indio_dev = container_of(inode->i_cdev,
struct iio_dev, chrdev);
+ struct iio_dev_buffer_pair *ib;
if (test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->flags))
return -EBUSY;
iio_device_get(indio_dev);
- filp->private_data = indio_dev;
+ ib = kmalloc(sizeof(*ib), GFP_KERNEL);
+ if (!ib) {
+ iio_device_put(indio_dev);
+ clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags);
+ return -ENOMEM;
+ }
+
+ ib->indio_dev = indio_dev;
+ ib->buffer = indio_dev->buffer;
+
+ filp->private_data = ib;
return 0;
}
@@ -1696,8 +1737,10 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp)
*/
static int iio_chrdev_release(struct inode *inode, struct file *filp)
{
+ struct iio_dev_buffer_pair *ib = filp->private_data;
struct iio_dev *indio_dev = container_of(inode->i_cdev,
struct iio_dev, chrdev);
+ kfree(ib);
clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags);
iio_device_put(indio_dev);
@@ -1719,7 +1762,8 @@ void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h)
static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
- struct iio_dev *indio_dev = filp->private_data;
+ struct iio_dev_buffer_pair *ib = filp->private_data;
+ struct iio_dev *indio_dev = ib->indio_dev;
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_ioctl_handler *h;
int ret = -ENODEV;
@@ -1761,6 +1805,15 @@ static const struct file_operations iio_buffer_fileops = {
.release = iio_chrdev_release,
};
+static const struct file_operations iio_event_fileops = {
+ .owner = THIS_MODULE,
+ .llseek = noop_llseek,
+ .unlocked_ioctl = iio_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
+ .open = iio_chrdev_open,
+ .release = iio_chrdev_release,
+};
+
static int iio_check_unique_scan_index(struct iio_dev *indio_dev)
{
int i, j;
@@ -1788,6 +1841,8 @@ static const struct iio_buffer_setup_ops noop_ring_setup_ops;
int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ const char *label;
int ret;
if (!indio_dev->info)
@@ -1798,19 +1853,17 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
if (!indio_dev->dev.of_node && indio_dev->dev.parent)
indio_dev->dev.of_node = indio_dev->dev.parent->of_node;
- indio_dev->label = of_get_property(indio_dev->dev.of_node, "label",
- NULL);
+ label = of_get_property(indio_dev->dev.of_node, "label", NULL);
+ if (label)
+ indio_dev->label = label;
ret = iio_check_unique_scan_index(indio_dev);
if (ret < 0)
return ret;
- /* configure elements for the chrdev */
- indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
-
iio_device_register_debugfs(indio_dev);
- ret = iio_buffer_alloc_sysfs_and_mask(indio_dev);
+ ret = iio_buffers_alloc_sysfs_and_mask(indio_dev);
if (ret) {
dev_err(indio_dev->dev.parent,
"Failed to create buffer sysfs interfaces\n");
@@ -1836,9 +1889,18 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
indio_dev->setup_ops == NULL)
indio_dev->setup_ops = &noop_ring_setup_ops;
- cdev_init(&indio_dev->chrdev, &iio_buffer_fileops);
+ if (iio_dev_opaque->attached_buffers_cnt)
+ cdev_init(&indio_dev->chrdev, &iio_buffer_fileops);
+ else if (iio_dev_opaque->event_interface)
+ cdev_init(&indio_dev->chrdev, &iio_event_fileops);
+
+ if (iio_dev_opaque->attached_buffers_cnt || iio_dev_opaque->event_interface) {
+ indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
+ indio_dev->chrdev.owner = this_mod;
+ }
- indio_dev->chrdev.owner = this_mod;
+ /* assign device groups now; they should be all registered now */
+ indio_dev->dev.groups = iio_dev_opaque->groups;
ret = cdev_device_add(&indio_dev->chrdev, &indio_dev->dev);
if (ret < 0)
@@ -1851,7 +1913,7 @@ error_unreg_eventset:
error_free_sysfs:
iio_device_unregister_sysfs(indio_dev);
error_buffer_free_sysfs:
- iio_buffer_free_sysfs_and_mask(indio_dev);
+ iio_buffers_free_sysfs_and_mask(indio_dev);
error_unreg_debugfs:
iio_device_unregister_debugfs(indio_dev);
return ret;
@@ -1885,7 +1947,7 @@ void iio_device_unregister(struct iio_dev *indio_dev)
mutex_unlock(&indio_dev->info_exist_lock);
- iio_buffer_free_sysfs_and_mask(indio_dev);
+ iio_buffers_free_sysfs_and_mask(indio_dev);
}
EXPORT_SYMBOL(iio_device_unregister);
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 7e532117ac55..a30e289fc362 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -385,6 +385,7 @@ static int iio_device_add_event(struct iio_dev *indio_dev,
ret = __iio_add_chan_devattr(postfix, chan, show, store,
(i << 16) | spec_index, shared_by, &indio_dev->dev,
+ NULL,
&iio_dev_opaque->event_interface->dev_attr_list);
kfree(postfix);
@@ -544,7 +545,10 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
/* Add all elements from the list. */
list_for_each_entry(p, &ev_int->dev_attr_list, l)
ev_int->group.attrs[attrn++] = &p->dev_attr.attr;
- indio_dev->groups[indio_dev->groupcounter++] = &ev_int->group;
+
+ ret = iio_device_register_sysfs_group(indio_dev, &ev_int->group);
+ if (ret)
+ goto error_free_setup_event_lines;
ev_int->ioctl_handler.ioctl = iio_event_ioctl;
iio_device_ioctl_handler_register(&iio_dev_opaque->indio_dev,
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index ea3c9859b258..32ac1bec25e3 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -514,8 +514,10 @@ static void iio_trig_subirqunmask(struct irq_data *d)
trig->subirqs[d->irq - trig->subirq_base].enabled = true;
}
-static __printf(1, 0)
-struct iio_trigger *viio_trigger_alloc(const char *fmt, va_list vargs)
+static __printf(2, 0)
+struct iio_trigger *viio_trigger_alloc(struct device *parent,
+ const char *fmt,
+ va_list vargs)
{
struct iio_trigger *trig;
int i;
@@ -524,6 +526,7 @@ struct iio_trigger *viio_trigger_alloc(const char *fmt, va_list vargs)
if (!trig)
return NULL;
+ trig->dev.parent = parent;
trig->dev.type = &iio_trig_type;
trig->dev.bus = &iio_bus_type;
device_initialize(&trig->dev);
@@ -559,13 +562,23 @@ free_trig:
return NULL;
}
-struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
+/**
+ * iio_trigger_alloc - Allocate a trigger
+ * @parent: Device to allocate iio_trigger for
+ * @fmt: trigger name format. If it includes format
+ * specifiers, the additional arguments following
+ * format are formatted and inserted in the resulting
+ * string replacing their respective specifiers.
+ * RETURNS:
+ * Pointer to allocated iio_trigger on success, NULL on failure.
+ */
+struct iio_trigger *iio_trigger_alloc(struct device *parent, const char *fmt, ...)
{
struct iio_trigger *trig;
va_list vargs;
va_start(vargs, fmt);
- trig = viio_trigger_alloc(fmt, vargs);
+ trig = viio_trigger_alloc(parent, fmt, vargs);
va_end(vargs);
return trig;
@@ -586,20 +599,19 @@ static void devm_iio_trigger_release(struct device *dev, void *res)
/**
* devm_iio_trigger_alloc - Resource-managed iio_trigger_alloc()
- * @dev: Device to allocate iio_trigger for
+ * Managed iio_trigger_alloc. iio_trigger allocated with this function is
+ * automatically freed on driver detach.
+ * @parent: Device to allocate iio_trigger for
* @fmt: trigger name format. If it includes format
* specifiers, the additional arguments following
* format are formatted and inserted in the resulting
* string replacing their respective specifiers.
*
- * Managed iio_trigger_alloc. iio_trigger allocated with this function is
- * automatically freed on driver detach.
*
* RETURNS:
* Pointer to allocated iio_trigger on success, NULL on failure.
*/
-struct iio_trigger *devm_iio_trigger_alloc(struct device *dev,
- const char *fmt, ...)
+struct iio_trigger *devm_iio_trigger_alloc(struct device *parent, const char *fmt, ...)
{
struct iio_trigger **ptr, *trig;
va_list vargs;
@@ -611,11 +623,11 @@ struct iio_trigger *devm_iio_trigger_alloc(struct device *dev,
/* use raw alloc_dr for kmalloc caller tracing */
va_start(vargs, fmt);
- trig = viio_trigger_alloc(fmt, vargs);
+ trig = viio_trigger_alloc(parent, fmt, vargs);
va_end(vargs);
if (trig) {
*ptr = trig;
- devres_add(dev, ptr);
+ devres_add(parent, ptr);
} else {
devres_free(ptr);
}
@@ -692,10 +704,10 @@ int iio_trigger_validate_own_device(struct iio_trigger *trig,
}
EXPORT_SYMBOL(iio_trigger_validate_own_device);
-void iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
+int iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
{
- indio_dev->groups[indio_dev->groupcounter++] =
- &iio_trigger_consumer_attr_group;
+ return iio_device_register_sysfs_group(indio_dev,
+ &iio_trigger_consumer_attr_group);
}
void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index db77a2d4a56b..c61fc06f98b8 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -688,7 +688,8 @@ int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2)
}
EXPORT_SYMBOL_GPL(iio_read_channel_offset);
-int iio_read_channel_processed(struct iio_channel *chan, int *val)
+int iio_read_channel_processed_scale(struct iio_channel *chan, int *val,
+ unsigned int scale)
{
int ret;
@@ -701,11 +702,15 @@ int iio_read_channel_processed(struct iio_channel *chan, int *val)
if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) {
ret = iio_channel_read(chan, val, NULL,
IIO_CHAN_INFO_PROCESSED);
+ if (ret)
+ goto err_unlock;
+ *val *= scale;
} else {
ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
if (ret < 0)
goto err_unlock;
- ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1);
+ ret = iio_convert_raw_to_processed_unlocked(chan, *val, val,
+ scale);
}
err_unlock:
@@ -713,6 +718,13 @@ err_unlock:
return ret;
}
+EXPORT_SYMBOL_GPL(iio_read_channel_processed_scale);
+
+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);
int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c
index 2be7180e2cbf..30393f08e082 100644
--- a/drivers/iio/light/acpi-als.c
+++ b/drivers/iio/light/acpi-als.c
@@ -16,11 +16,14 @@
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/err.h>
+#include <linux/irq.h>
#include <linux/mutex.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
#define ACPI_ALS_CLASS "als"
#define ACPI_ALS_DEVICE_NAME "acpi-als"
@@ -45,24 +48,23 @@ static const struct iio_chan_spec acpi_als_channels[] = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_PROCESSED),
},
+ IIO_CHAN_SOFT_TIMESTAMP(1),
};
/*
* The event buffer contains timestamp and all the data from
* the ACPI0008 block. There are multiple, but so far we only
- * support _ALI (illuminance). Once someone adds new channels
- * to acpi_als_channels[], the evt_buffer below will grow
- * automatically.
+ * support _ALI (illuminance): One channel, padding and timestamp.
*/
-#define ACPI_ALS_EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels)
#define ACPI_ALS_EVT_BUFFER_SIZE \
- (sizeof(s64) + (ACPI_ALS_EVT_NR_SOURCES * sizeof(s32)))
+ (sizeof(s32) + sizeof(s32) + sizeof(s64))
struct acpi_als {
struct acpi_device *device;
struct mutex lock;
+ struct iio_trigger *trig;
- s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE];
+ s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE / sizeof(s32)] __aligned(8);
};
/*
@@ -104,33 +106,19 @@ static void acpi_als_notify(struct acpi_device *device, u32 event)
{
struct iio_dev *indio_dev = acpi_driver_data(device);
struct acpi_als *als = iio_priv(indio_dev);
- s32 *buffer = als->evt_buffer;
- s64 time_ns = iio_get_time_ns(indio_dev);
- s32 val;
- int ret;
-
- mutex_lock(&als->lock);
- memset(buffer, 0, ACPI_ALS_EVT_BUFFER_SIZE);
-
- switch (event) {
- case ACPI_ALS_NOTIFY_ILLUMINANCE:
- ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
- if (ret < 0)
- goto out;
- *buffer++ = val;
- break;
- default:
- /* Unhandled event */
- dev_dbg(&device->dev, "Unhandled ACPI ALS event (%08x)!\n",
- event);
- goto out;
+ if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev)) {
+ switch (event) {
+ case ACPI_ALS_NOTIFY_ILLUMINANCE:
+ iio_trigger_poll_chained(als->trig);
+ break;
+ default:
+ /* Unhandled event */
+ dev_dbg(&device->dev,
+ "Unhandled ACPI ALS event (%08x)!\n",
+ event);
+ }
}
-
- iio_push_to_buffers_with_timestamp(indio_dev, als->evt_buffer, time_ns);
-
-out:
- mutex_unlock(&als->lock);
}
static int acpi_als_read_raw(struct iio_dev *indio_dev,
@@ -161,13 +149,49 @@ static const struct iio_info acpi_als_info = {
.read_raw = acpi_als_read_raw,
};
+static irqreturn_t acpi_als_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct acpi_als *als = iio_priv(indio_dev);
+ s32 *buffer = als->evt_buffer;
+ s32 val;
+ int ret;
+
+ mutex_lock(&als->lock);
+
+ ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
+ if (ret < 0)
+ goto out;
+ *buffer = val;
+
+ /*
+ * When coming from own trigger via polls, set polling function
+ * timestamp here. Given ACPI notifier is already in a thread and call
+ * function directly, there is no need to set the timestamp in the
+ * notify function.
+ *
+ * If the timestamp was actually 0, the timestamp is set one more time.
+ */
+ if (!pf->timestamp)
+ pf->timestamp = iio_get_time_ns(indio_dev);
+
+ iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
+out:
+ mutex_unlock(&als->lock);
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
static int acpi_als_add(struct acpi_device *device)
{
- struct acpi_als *als;
+ struct device *dev = &device->dev;
struct iio_dev *indio_dev;
- struct iio_buffer *buffer;
+ struct acpi_als *als;
+ int ret;
- indio_dev = devm_iio_device_alloc(&device->dev, sizeof(*als));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*als));
if (!indio_dev)
return -ENOMEM;
@@ -179,17 +203,30 @@ static int acpi_als_add(struct acpi_device *device)
indio_dev->name = ACPI_ALS_DEVICE_NAME;
indio_dev->info = &acpi_als_info;
- indio_dev->modes = INDIO_BUFFER_SOFTWARE;
indio_dev->channels = acpi_als_channels;
indio_dev->num_channels = ARRAY_SIZE(acpi_als_channels);
- buffer = devm_iio_kfifo_allocate(&device->dev);
- if (!buffer)
+ als->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id);
+ if (!als->trig)
return -ENOMEM;
- iio_device_attach_buffer(indio_dev, buffer);
+ ret = devm_iio_trigger_register(dev, als->trig);
+ if (ret)
+ return ret;
+ /*
+ * Set hardware trigger by default to let events flow when
+ * BIOS support notification.
+ */
+ indio_dev->trig = iio_trigger_get(als->trig);
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ iio_pollfunc_store_time,
+ acpi_als_trigger_handler,
+ NULL);
+ if (ret)
+ return ret;
- return devm_iio_device_register(&device->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct acpi_device_id acpi_als_device_ids[] = {
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index df0647856e5d..4141c0fa7bc4 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -988,7 +988,6 @@ static int apds9960_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct apds9960_data *data;
- struct iio_buffer *buffer;
struct iio_dev *indio_dev;
int ret;
@@ -996,19 +995,18 @@ static int apds9960_probe(struct i2c_client *client,
if (!indio_dev)
return -ENOMEM;
- buffer = devm_iio_kfifo_allocate(&client->dev);
- if (!buffer)
- return -ENOMEM;
-
- iio_device_attach_buffer(indio_dev, buffer);
-
indio_dev->info = &apds9960_info;
indio_dev->name = APDS9960_DRV_NAME;
indio_dev->channels = apds9960_channels;
indio_dev->num_channels = ARRAY_SIZE(apds9960_channels);
indio_dev->available_scan_masks = apds9960_scan_masks;
- indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
- indio_dev->setup_ops = &apds9960_buffer_setup_ops;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &apds9960_buffer_setup_ops);
+ if (ret)
+ return ret;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c
index 75d6b5fcf2cc..de472f23d1cb 100644
--- a/drivers/iio/light/cros_ec_light_prox.c
+++ b/drivers/iio/light/cros_ec_light_prox.c
@@ -182,8 +182,7 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
cros_ec_sensors_capture,
- cros_ec_sensors_push_data,
- true);
+ cros_ec_sensors_push_data);
if (ret)
return ret;
diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c
index 7ba7aa59437c..d048ae257c51 100644
--- a/drivers/iio/light/gp2ap002.c
+++ b/drivers/iio/light/gp2ap002.c
@@ -465,8 +465,7 @@ static int gp2ap002_probe(struct i2c_client *client,
regmap = devm_regmap_init(dev, &gp2ap002_regmap_bus, dev, &config);
if (IS_ERR(regmap)) {
- dev_err(dev, "Failed to register i2c regmap %d\n",
- (int)PTR_ERR(regmap));
+ dev_err(dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap));
return PTR_ERR(regmap);
}
gp2ap002->map = regmap;
diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c
index e2850c1a7353..d1d9f2d319e4 100644
--- a/drivers/iio/light/gp2ap020a00f.c
+++ b/drivers/iio/light/gp2ap020a00f.c
@@ -1551,7 +1551,6 @@ static int gp2ap020a00f_probe(struct i2c_client *client,
}
data->trig->ops = &gp2ap020a00f_trigger_ops;
- data->trig->dev.parent = &data->client->dev;
init_irq_work(&data->work, gp2ap020a00f_iio_trigger_work);
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index 4093f2353d95..85c8a05b73cb 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -39,6 +39,11 @@ struct als_state {
s64 timestamp;
};
+static const u32 als_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_DATA_LIGHT,
+ HID_USAGE_SENSOR_LIGHT_ILLUM,
+};
+
/* Channel definitions */
static const struct iio_chan_spec als_channels[] = {
{
@@ -49,7 +54,8 @@ static const struct iio_chan_spec als_channels[] = {
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
- BIT(IIO_CHAN_INFO_HYSTERESIS),
+ BIT(IIO_CHAN_INFO_HYSTERESIS) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
.scan_index = CHANNEL_SCAN_INDEX_INTENSITY,
},
{
@@ -58,7 +64,8 @@ static const struct iio_chan_spec als_channels[] = {
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
- BIT(IIO_CHAN_INFO_HYSTERESIS),
+ BIT(IIO_CHAN_INFO_HYSTERESIS) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
.scan_index = CHANNEL_SCAN_INDEX_ILLUM,
},
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
@@ -136,6 +143,10 @@ static int als_read_raw(struct iio_dev *indio_dev,
ret_type = hid_sensor_read_raw_hyst_value(
&als_state->common_attributes, val, val2);
break;
+ case IIO_CHAN_INFO_HYSTERESIS_RELATIVE:
+ ret_type = hid_sensor_read_raw_hyst_rel_value(
+ &als_state->common_attributes, val, val2);
+ break;
default:
ret_type = -EINVAL;
break;
@@ -163,6 +174,10 @@ static int als_write_raw(struct iio_dev *indio_dev,
ret = hid_sensor_write_raw_hyst_value(
&als_state->common_attributes, val, val2);
break;
+ case IIO_CHAN_INFO_HYSTERESIS_RELATIVE:
+ ret = hid_sensor_write_raw_hyst_rel_value(
+ &als_state->common_attributes, val, val2);
+ break;
default:
ret = -EINVAL;
}
@@ -252,17 +267,6 @@ static int als_parse_report(struct platform_device *pdev,
&st->als_illum,
&st->scale_pre_decml, &st->scale_post_decml);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->common_attributes.sensitivity.index < 0) {
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_DATA_LIGHT,
- &st->common_attributes.sensitivity);
- dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
- st->common_attributes.sensitivity.index,
- st->common_attributes.sensitivity.report_id);
- }
return ret;
}
@@ -285,7 +289,9 @@ static int hid_als_probe(struct platform_device *pdev)
als_state->common_attributes.pdev = pdev;
ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS,
- &als_state->common_attributes);
+ &als_state->common_attributes,
+ als_sensitivity_addresses,
+ ARRAY_SIZE(als_sensitivity_addresses));
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index e9e00ce0c6d4..17d167c3d595 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -28,6 +28,11 @@ struct prox_state {
int scale_precision;
};
+static const u32 prox_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_HUMAN_PRESENCE,
+ HID_USAGE_SENSOR_DATA_PRESENCE,
+};
+
/* Channel definitions */
static const struct iio_chan_spec prox_channels[] = {
{
@@ -220,29 +225,6 @@ static int prox_parse_report(struct platform_device *pdev,
dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr.index,
st->prox_attr.report_id);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->common_attributes.sensitivity.index < 0) {
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_DATA_PRESENCE,
- &st->common_attributes.sensitivity);
- dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
- st->common_attributes.sensitivity.index,
- st->common_attributes.sensitivity.report_id);
- }
- if (st->common_attributes.sensitivity.index < 0)
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_HUMAN_PRESENCE,
- &st->common_attributes.sensitivity);
-
- st->scale_precision = hid_sensor_format_scale(
- hsdev->usage,
- &st->prox_attr,
- &st->scale_pre_decml, &st->scale_post_decml);
-
return ret;
}
@@ -266,7 +248,9 @@ static int hid_prox_probe(struct platform_device *pdev)
prox_state->common_attributes.pdev = pdev;
ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX,
- &prox_state->common_attributes);
+ &prox_state->common_attributes,
+ prox_sensitivity_addresses,
+ ARRAY_SIZE(prox_sensitivity_addresses));
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c
index 2d48d61909a4..52963da401a7 100644
--- a/drivers/iio/light/opt3001.c
+++ b/drivers/iio/light/opt3001.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* opt3001.c - Texas Instruments OPT3001 Light Sensor
*
* Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index 31224a33bade..033578f444e4 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -990,7 +990,6 @@ static int rpr0521_probe(struct i2c_client *client,
ret = -ENOMEM;
goto err_pm_disable;
}
- data->drdy_trigger0->dev.parent = indio_dev->dev.parent;
data->drdy_trigger0->ops = &rpr0521_trigger_ops;
indio_dev->available_scan_masks = rpr0521_available_scan_masks;
iio_trigger_set_drvdata(data->drdy_trigger0, indio_dev);
diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c
index b304801c7916..9b5c99823943 100644
--- a/drivers/iio/light/si1145.c
+++ b/drivers/iio/light/si1145.c
@@ -1247,7 +1247,6 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev)
if (!trig)
return -ENOMEM;
- trig->dev.parent = &client->dev;
trig->ops = &si1145_trigger_ops;
iio_trigger_set_drvdata(trig, indio_dev);
diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c
index 1055594b2276..41a2ce5a2d53 100644
--- a/drivers/iio/light/st_uvis25_core.c
+++ b/drivers/iio/light/st_uvis25_core.c
@@ -210,7 +210,6 @@ static int st_uvis25_allocate_trigger(struct iio_dev *iio_dev)
return -ENOMEM;
iio_trigger_set_drvdata(hw->trig, iio_dev);
- hw->trig->dev.parent = dev;
return devm_iio_trigger_register(dev, hw->trig);
}
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index a2827d03ab0f..07e91846307c 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* Sensortek STK3310/STK3311 Ambient Light and Proximity Sensor
*
* Copyright (c) 2015, Intel Corporation.
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index fff4b36b8b58..2f7916f95689 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -1002,7 +1002,6 @@ static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)
if (!trigger)
return -ENOMEM;
- trigger->dev.parent = &client->dev;
trigger->ops = &vcnl4010_trigger_ops;
iio_trigger_set_drvdata(trigger, indio_dev);
diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c
index 73a28e30dddc..ae87740d9cef 100644
--- a/drivers/iio/light/vcnl4035.c
+++ b/drivers/iio/light/vcnl4035.c
@@ -511,7 +511,6 @@ static int vcnl4035_probe_trigger(struct iio_dev *indio_dev)
if (!data->drdy_trigger0)
return -ENOMEM;
- data->drdy_trigger0->dev.parent = indio_dev->dev.parent;
data->drdy_trigger0->ops = &vcnl4035_trigger_ops;
iio_trigger_set_drvdata(data->drdy_trigger0, indio_dev);
ret = devm_iio_trigger_register(indio_dev->dev.parent,
diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c
index b2f3129e1b4f..00f9766bad5c 100644
--- a/drivers/iio/magnetometer/bmc150_magn.c
+++ b/drivers/iio/magnetometer/bmc150_magn.c
@@ -922,7 +922,6 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap,
goto err_poweroff;
}
- data->dready_trig->dev.parent = dev;
data->dready_trig->ops = &bmc150_magn_trigger_ops;
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
ret = iio_trigger_register(data->dready_trig);
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index fa48044b7f5b..b78691523dd4 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -62,6 +62,11 @@ static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = {
HID_USAGE_SENSOR_TIME_TIMESTAMP,
};
+static const u32 magn_3d_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_DATA_ORIENTATION,
+ HID_USAGE_SENSOR_ORIENT_MAGN_FLUX,
+};
+
/* Channel definitions */
static const struct iio_chan_spec magn_3d_channels[] = {
{
@@ -448,27 +453,6 @@ static int magn_3d_parse_report(struct platform_device *pdev,
&st->rot_attr.scale_pre_decml,
&st->rot_attr.scale_post_decml);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->magn_flux_attributes.sensitivity.index < 0) {
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_DATA_ORIENTATION,
- &st->magn_flux_attributes.sensitivity);
- dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
- st->magn_flux_attributes.sensitivity.index,
- st->magn_flux_attributes.sensitivity.report_id);
- }
- if (st->magn_flux_attributes.sensitivity.index < 0) {
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_ORIENT_MAGN_FLUX,
- &st->magn_flux_attributes.sensitivity);
- dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
- st->magn_flux_attributes.sensitivity.index,
- st->magn_flux_attributes.sensitivity.report_id);
- }
if (st->rot_attributes.sensitivity.index < 0) {
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
@@ -507,12 +491,16 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
ret = hid_sensor_parse_common_attributes(hsdev,
HID_USAGE_SENSOR_COMPASS_3D,
- &magn_state->magn_flux_attributes);
+ &magn_state->magn_flux_attributes,
+ magn_3d_sensitivity_addresses,
+ ARRAY_SIZE(magn_3d_sensitivity_addresses));
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
}
magn_state->rot_attributes = magn_state->magn_flux_attributes;
+ /* sensitivity of rot_attribute is not the same as magn_flux_attributes */
+ magn_state->rot_attributes.sensitivity.index = -1;
ret = magn_3d_parse_report(pdev, hsdev,
&channels, &chan_count,
diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c
index 7242897a05e9..dd811da9cb6d 100644
--- a/drivers/iio/magnetometer/rm3100-core.c
+++ b/drivers/iio/magnetometer/rm3100-core.c
@@ -579,7 +579,6 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq)
if (!data->drdy_trig)
return -ENOMEM;
- data->drdy_trig->dev.parent = dev;
ret = devm_iio_trigger_register(dev, data->drdy_trig);
if (ret < 0)
return ret;
diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h
index 204b285725c8..7ba6a6ba5c58 100644
--- a/drivers/iio/magnetometer/st_magn.h
+++ b/drivers/iio/magnetometer/st_magn.h
@@ -21,6 +21,7 @@
#define LSM303AGR_MAGN_DEV_NAME "lsm303agr_magn"
#define LIS2MDL_MAGN_DEV_NAME "lis2mdl"
#define LSM9DS1_MAGN_DEV_NAME "lsm9ds1_magn"
+#define IIS2MDC_MAGN_DEV_NAME "iis2mdc"
const struct st_sensor_settings *st_magn_get_settings(const char *name);
int st_magn_common_probe(struct iio_dev *indio_dev);
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
index 79de721e6015..71faebd07feb 100644
--- a/drivers/iio/magnetometer/st_magn_core.c
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -337,6 +337,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
.sensors_supported = {
[0] = LSM303AGR_MAGN_DEV_NAME,
[1] = LIS2MDL_MAGN_DEV_NAME,
+ [2] = IIS2MDC_MAGN_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_magn_3_16bit_channels,
.odr = {
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
index c6bb4ce77594..36f4e7b53b24 100644
--- a/drivers/iio/magnetometer/st_magn_i2c.c
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -46,6 +46,10 @@ static const struct of_device_id st_magn_of_match[] = {
.compatible = "st,lsm9ds1-magn",
.data = LSM9DS1_MAGN_DEV_NAME,
},
+ {
+ .compatible = "st,iis2mdc",
+ .data = IIS2MDC_MAGN_DEV_NAME,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_magn_of_match);
@@ -101,6 +105,7 @@ static const struct i2c_device_id st_magn_id_table[] = {
{ LSM303AGR_MAGN_DEV_NAME },
{ LIS2MDL_MAGN_DEV_NAME },
{ LSM9DS1_MAGN_DEV_NAME },
+ { IIS2MDC_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 3d08d74c367d..0e2323dfc687 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -41,6 +41,10 @@ static const struct of_device_id st_magn_of_match[] = {
.compatible = "st,lsm9ds1-magn",
.data = LSM9DS1_MAGN_DEV_NAME,
},
+ {
+ .compatible = "st,iis2mdc",
+ .data = IIS2MDC_MAGN_DEV_NAME,
+ },
{}
};
MODULE_DEVICE_TABLE(of, st_magn_of_match);
@@ -92,6 +96,7 @@ static const struct spi_device_id st_magn_id_table[] = {
{ LSM303AGR_MAGN_DEV_NAME },
{ LIS2MDL_MAGN_DEV_NAME },
{ LSM9DS1_MAGN_DEV_NAME },
+ { IIS2MDC_MAGN_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_magn_id_table);
diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c
index 52ebef30f9be..7af48d336285 100644
--- a/drivers/iio/orientation/hid-sensor-incl-3d.c
+++ b/drivers/iio/orientation/hid-sensor-incl-3d.c
@@ -47,6 +47,11 @@ static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = {
HID_USAGE_SENSOR_ORIENT_TILT_Z
};
+static const u32 incl_3d_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_DATA_ORIENTATION,
+ HID_USAGE_SENSOR_ORIENT_TILT,
+};
+
/* Channel definitions */
static const struct iio_chan_spec incl_3d_channels[] = {
{
@@ -291,17 +296,6 @@ static int incl_3d_parse_report(struct platform_device *pdev,
&st->incl[CHANNEL_SCAN_INDEX_X],
&st->scale_pre_decml, &st->scale_post_decml);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->common_attributes.sensitivity.index < 0) {
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_DATA_ORIENTATION,
- &st->common_attributes.sensitivity);
- dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
- st->common_attributes.sensitivity.index,
- st->common_attributes.sensitivity.report_id);
- }
return ret;
}
@@ -327,7 +321,9 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
ret = hid_sensor_parse_common_attributes(hsdev,
HID_USAGE_SENSOR_INCLINOMETER_3D,
- &incl_state->common_attributes);
+ &incl_state->common_attributes,
+ incl_3d_sensitivity_addresses,
+ ARRAY_SIZE(incl_3d_sensitivity_addresses));
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
index 18e4ef060096..cf7f57a47681 100644
--- a/drivers/iio/orientation/hid-sensor-rotation.c
+++ b/drivers/iio/orientation/hid-sensor-rotation.c
@@ -21,7 +21,7 @@ struct dev_rot_state {
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info quaternion;
struct {
- u32 sampled_vals[4] __aligned(16);
+ s32 sampled_vals[4] __aligned(16);
u64 timestamp __aligned(8);
} scan;
int scale_pre_decml;
@@ -31,6 +31,11 @@ struct dev_rot_state {
s64 timestamp;
};
+static const u32 rotation_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_DATA_ORIENTATION,
+ HID_USAGE_SENSOR_ORIENT_QUATERNION,
+};
+
/* Channel definitions */
static const struct iio_chan_spec dev_rot_channels[] = {
{
@@ -170,8 +175,15 @@ static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev,
struct dev_rot_state *rot_state = iio_priv(indio_dev);
if (usage_id == HID_USAGE_SENSOR_ORIENT_QUATERNION) {
- memcpy(&rot_state->scan.sampled_vals, raw_data,
- sizeof(rot_state->scan.sampled_vals));
+ if (raw_len / 4 == sizeof(s16)) {
+ rot_state->scan.sampled_vals[0] = ((s16 *)raw_data)[0];
+ rot_state->scan.sampled_vals[1] = ((s16 *)raw_data)[1];
+ rot_state->scan.sampled_vals[2] = ((s16 *)raw_data)[2];
+ rot_state->scan.sampled_vals[3] = ((s16 *)raw_data)[3];
+ } else {
+ memcpy(&rot_state->scan.sampled_vals, raw_data,
+ sizeof(rot_state->scan.sampled_vals));
+ }
dev_dbg(&indio_dev->dev, "Recd Quat len:%zu::%zu\n", raw_len,
sizeof(rot_state->scan.sampled_vals));
@@ -214,18 +226,6 @@ static int dev_rot_parse_report(struct platform_device *pdev,
&st->quaternion,
&st->scale_pre_decml, &st->scale_post_decml);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->common_attributes.sensitivity.index < 0) {
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_DATA_ORIENTATION,
- &st->common_attributes.sensitivity);
- dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
- st->common_attributes.sensitivity.index,
- st->common_attributes.sensitivity.report_id);
- }
-
return 0;
}
@@ -263,8 +263,11 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
return -EINVAL;
}
- ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage,
- &rot_state->common_attributes);
+ ret = hid_sensor_parse_common_attributes(hsdev,
+ hsdev->usage,
+ &rot_state->common_attributes,
+ rotation_sensitivity_addresses,
+ ARRAY_SIZE(rotation_sensitivity_addresses));
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
index 64a7fa7db6af..fd77e7ee87f3 100644
--- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c
+++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
@@ -47,6 +47,10 @@ struct hinge_state {
u64 timestamp;
};
+static const u32 hinge_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1),
+};
+
/* Channel definitions */
static const struct iio_chan_spec hinge_channels[] = {
{
@@ -251,18 +255,6 @@ static int hinge_parse_report(struct platform_device *pdev,
&st->hinge[CHANNEL_SCAN_INDEX_HINGE_ANGLE],
&st->scale_pre_decml, &st->scale_post_decml);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->common_attributes.sensitivity.index < 0) {
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1),
- &st->common_attributes.sensitivity);
- dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
- st->common_attributes.sensitivity.index,
- st->common_attributes.sensitivity.report_id);
- }
-
return ret;
}
@@ -289,7 +281,9 @@ static int hid_hinge_probe(struct platform_device *pdev)
st->labels[i] = hinge_labels[i];
ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage,
- &st->common_attributes);
+ &st->common_attributes,
+ hinge_sensitivity_addresses,
+ ARRAY_SIZE(hinge_sensitivity_addresses));
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c
index a88ed0eb3adc..6e22b538091f 100644
--- a/drivers/iio/potentiometer/max5481.c
+++ b/drivers/iio/potentiometer/max5481.c
@@ -136,7 +136,7 @@ static int max5481_probe(struct spi_device *spi)
if (!indio_dev)
return -ENOMEM;
- dev_set_drvdata(&spi->dev, indio_dev);
+ spi_set_drvdata(spi, indio_dev);
data = iio_priv(indio_dev);
data->spi = spi;
@@ -163,7 +163,7 @@ static int max5481_probe(struct spi_device *spi)
static int max5481_remove(struct spi_device *spi)
{
- struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev);
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct max5481_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c
index 7ec51976ec99..1c0d46a96200 100644
--- a/drivers/iio/potentiometer/max5487.c
+++ b/drivers/iio/potentiometer/max5487.c
@@ -92,7 +92,7 @@ static int max5487_spi_probe(struct spi_device *spi)
if (!indio_dev)
return -ENOMEM;
- dev_set_drvdata(&spi->dev, indio_dev);
+ spi_set_drvdata(spi, indio_dev);
data = iio_priv(indio_dev);
data->spi = spi;
@@ -114,7 +114,7 @@ static int max5487_spi_probe(struct spi_device *spi)
static int max5487_spi_remove(struct spi_device *spi)
{
- struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev);
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
iio_device_unregister(indio_dev);
diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c
index f34ca769dc20..8a9c576616ee 100644
--- a/drivers/iio/potentiostat/lmp91000.c
+++ b/drivers/iio/potentiostat/lmp91000.c
@@ -322,7 +322,7 @@ static int lmp91000_probe(struct i2c_client *client,
return PTR_ERR(data->regmap);
}
- data->trig = devm_iio_trigger_alloc(data->dev, "%s-mux%d",
+ data->trig = devm_iio_trigger_alloc(dev, "%s-mux%d",
indio_dev->name, indio_dev->id);
if (!data->trig) {
dev_err(dev, "cannot allocate iio trigger.\n");
@@ -330,7 +330,6 @@ static int lmp91000_probe(struct i2c_client *client,
}
data->trig->ops = &lmp91000_trigger_ops;
- data->trig->dev.parent = dev;
init_completion(&data->completion);
ret = lmp91000_read_config(data);
diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c
index aa043cb9ac42..2f882e109423 100644
--- a/drivers/iio/pressure/cros_ec_baro.c
+++ b/drivers/iio/pressure/cros_ec_baro.c
@@ -139,8 +139,7 @@ static int cros_ec_baro_probe(struct platform_device *pdev)
ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
cros_ec_sensors_capture,
- cros_ec_sensors_push_data,
- true);
+ cros_ec_sensors_push_data);
if (ret)
return ret;
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
index 5c458788f346..c416d261e3e3 100644
--- a/drivers/iio/pressure/hid-sensor-press.c
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -29,6 +29,11 @@ struct press_state {
int value_offset;
};
+static const u32 press_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE,
+ HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE
+};
+
/* Channel definitions */
static const struct iio_chan_spec press_channels[] = {
{
@@ -225,17 +230,6 @@ static int press_parse_report(struct platform_device *pdev,
&st->press_attr,
&st->scale_pre_decml, &st->scale_post_decml);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->common_attributes.sensitivity.index < 0) {
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE,
- &st->common_attributes.sensitivity);
- dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
- st->common_attributes.sensitivity.index,
- st->common_attributes.sensitivity.report_id);
- }
return ret;
}
@@ -260,7 +254,9 @@ static int hid_press_probe(struct platform_device *pdev)
ret = hid_sensor_parse_common_attributes(hsdev,
HID_USAGE_SENSOR_PRESSURE,
- &press_state->common_attributes);
+ &press_state->common_attributes,
+ press_sensitivity_addresses,
+ ARRAY_SIZE(press_sensitivity_addresses));
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c
index 2cecbe0adb3f..a93411216aee 100644
--- a/drivers/iio/pressure/zpa2326.c
+++ b/drivers/iio/pressure/zpa2326.c
@@ -103,7 +103,7 @@ static const struct zpa2326_frequency *zpa2326_highest_frequency(void)
}
/**
- * struct zpa_private - Per-device internal private state
+ * struct zpa2326_private - Per-device internal private state
* @timestamp: Buffered samples ready datum.
* @regmap: Underlying I2C / SPI bus adapter used to abstract slave register
* accesses.
@@ -1382,7 +1382,7 @@ static const struct iio_trigger_ops zpa2326_trigger_ops = {
};
/**
- * zpa2326_init_trigger() - Create an interrupt driven / hardware trigger
+ * zpa2326_init_managed_trigger() - Create interrupt driven / hardware trigger
* allowing to notify external devices a new sample is
* ready.
* @parent: Hardware sampling device @indio_dev is a child of.
@@ -1413,7 +1413,6 @@ static int zpa2326_init_managed_trigger(struct device *parent,
return -ENOMEM;
/* Basic setup. */
- trigger->dev.parent = parent;
trigger->ops = &zpa2326_trigger_ops;
private->trigger = trigger;
diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index 12672a0e89ed..7c7203ca3ac6 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -21,6 +21,17 @@ endmenu
menu "Proximity and distance sensors"
+config CROS_EC_MKBP_PROXIMITY
+ tristate "ChromeOS EC MKBP Proximity sensor"
+ depends on CROS_EC
+ help
+ Say Y here to enable the proximity sensor implemented via the ChromeOS EC MKBP
+ switches protocol. You must enable one bus option (CROS_EC_I2C or CROS_EC_SPI)
+ to use this.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cros_ec_mkbp_proximity.
+
config ISL29501
tristate "Intersil ISL29501 Time Of Flight sensor"
depends on I2C
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index 9c1aca1a8b79..cbdac09433eb 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -5,6 +5,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AS3935) += as3935.o
+obj-$(CONFIG_CROS_EC_MKBP_PROXIMITY) += cros_ec_mkbp_proximity.o
obj-$(CONFIG_ISL29501) += isl29501.o
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
obj-$(CONFIG_MB1232) += mb1232.o
diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c
index b79ada839e01..edc4a35ae66d 100644
--- a/drivers/iio/proximity/as3935.c
+++ b/drivers/iio/proximity/as3935.c
@@ -411,7 +411,6 @@ static int as3935_probe(struct spi_device *spi)
st->trig = trig;
st->noise_tripped = jiffies - HZ;
- trig->dev.parent = indio_dev->dev.parent;
iio_trigger_set_drvdata(trig, indio_dev);
trig->ops = &iio_interrupt_trigger_ops;
diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c
new file mode 100644
index 000000000000..8213b0081713
--- /dev/null
+++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for cros-ec proximity sensor exposed through MKBP switch
+ *
+ * Copyright 2021 Google LLC.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/platform_data/cros_ec_commands.h>
+#include <linux/platform_data/cros_ec_proto.h>
+
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include <asm/unaligned.h>
+
+struct cros_ec_mkbp_proximity_data {
+ struct cros_ec_device *ec;
+ struct iio_dev *indio_dev;
+ struct mutex lock;
+ struct notifier_block notifier;
+ int last_proximity;
+ bool enabled;
+};
+
+static const struct iio_event_spec cros_ec_mkbp_proximity_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+static const struct iio_chan_spec cros_ec_mkbp_proximity_chan_spec[] = {
+ {
+ .type = IIO_PROXIMITY,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .event_spec = cros_ec_mkbp_proximity_events,
+ .num_event_specs = ARRAY_SIZE(cros_ec_mkbp_proximity_events),
+ },
+};
+
+static int cros_ec_mkbp_proximity_parse_state(const void *data)
+{
+ u32 switches = get_unaligned_le32(data);
+
+ return !!(switches & BIT(EC_MKBP_FRONT_PROXIMITY));
+}
+
+static int cros_ec_mkbp_proximity_query(struct cros_ec_device *ec_dev,
+ int *state)
+{
+ struct {
+ struct cros_ec_command msg;
+ union {
+ struct ec_params_mkbp_info params;
+ u32 switches;
+ };
+ } __packed buf = { };
+ struct ec_params_mkbp_info *params = &buf.params;
+ struct cros_ec_command *msg = &buf.msg;
+ u32 *switches = &buf.switches;
+ size_t insize = sizeof(*switches);
+ int ret;
+
+ msg->command = EC_CMD_MKBP_INFO;
+ msg->version = 1;
+ msg->outsize = sizeof(*params);
+ msg->insize = insize;
+
+ params->info_type = EC_MKBP_INFO_CURRENT;
+ params->event_type = EC_MKBP_EVENT_SWITCH;
+
+ ret = cros_ec_cmd_xfer_status(ec_dev, msg);
+ if (ret < 0)
+ return ret;
+
+ if (ret != insize) {
+ dev_warn(ec_dev->dev, "wrong result size: %d != %zu\n", ret,
+ insize);
+ return -EPROTO;
+ }
+
+ *state = cros_ec_mkbp_proximity_parse_state(switches);
+ return IIO_VAL_INT;
+}
+
+static void cros_ec_mkbp_proximity_push_event(struct cros_ec_mkbp_proximity_data *data, int state)
+{
+ s64 timestamp;
+ u64 ev;
+ int dir;
+ struct iio_dev *indio_dev = data->indio_dev;
+ struct cros_ec_device *ec = data->ec;
+
+ mutex_lock(&data->lock);
+ if (state != data->last_proximity) {
+ if (data->enabled) {
+ timestamp = ktime_to_ns(ec->last_event_time);
+ if (iio_device_get_clock(indio_dev) != CLOCK_BOOTTIME)
+ timestamp = iio_get_time_ns(indio_dev);
+
+ dir = state ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
+ ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
+ IIO_EV_TYPE_THRESH, dir);
+ iio_push_event(indio_dev, ev, timestamp);
+ }
+ data->last_proximity = state;
+ }
+ mutex_unlock(&data->lock);
+}
+
+static int cros_ec_mkbp_proximity_notify(struct notifier_block *nb,
+ unsigned long queued_during_suspend,
+ void *_ec)
+{
+ struct cros_ec_mkbp_proximity_data *data;
+ struct cros_ec_device *ec = _ec;
+ u8 event_type = ec->event_data.event_type & EC_MKBP_EVENT_TYPE_MASK;
+ void *switches;
+ int state;
+
+ if (event_type == EC_MKBP_EVENT_SWITCH) {
+ data = container_of(nb, struct cros_ec_mkbp_proximity_data,
+ notifier);
+
+ switches = &ec->event_data.data.switches;
+ state = cros_ec_mkbp_proximity_parse_state(switches);
+ cros_ec_mkbp_proximity_push_event(data, state);
+ }
+
+ return NOTIFY_OK;
+}
+
+static int cros_ec_mkbp_proximity_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *val,
+ int *val2, long mask)
+{
+ struct cros_ec_mkbp_proximity_data *data = iio_priv(indio_dev);
+ struct cros_ec_device *ec = data->ec;
+
+ if (chan->type == IIO_PROXIMITY && mask == IIO_CHAN_INFO_RAW)
+ return cros_ec_mkbp_proximity_query(ec, val);
+
+ return -EINVAL;
+}
+
+static int cros_ec_mkbp_proximity_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 cros_ec_mkbp_proximity_data *data = iio_priv(indio_dev);
+
+ return data->enabled;
+}
+
+static int cros_ec_mkbp_proximity_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ struct cros_ec_mkbp_proximity_data *data = iio_priv(indio_dev);
+
+ mutex_lock(&data->lock);
+ data->enabled = state;
+ mutex_unlock(&data->lock);
+
+ return 0;
+}
+
+static const struct iio_info cros_ec_mkbp_proximity_info = {
+ .read_raw = cros_ec_mkbp_proximity_read_raw,
+ .read_event_config = cros_ec_mkbp_proximity_read_event_config,
+ .write_event_config = cros_ec_mkbp_proximity_write_event_config,
+};
+
+static __maybe_unused int cros_ec_mkbp_proximity_resume(struct device *dev)
+{
+ struct cros_ec_mkbp_proximity_data *data = dev_get_drvdata(dev);
+ struct cros_ec_device *ec = data->ec;
+ int ret, state;
+
+ ret = cros_ec_mkbp_proximity_query(ec, &state);
+ if (ret < 0) {
+ dev_warn(dev, "failed to fetch proximity state on resume: %d\n",
+ ret);
+ } else {
+ cros_ec_mkbp_proximity_push_event(data, state);
+ }
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cros_ec_mkbp_proximity_pm_ops, NULL,
+ cros_ec_mkbp_proximity_resume);
+
+static int cros_ec_mkbp_proximity_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct cros_ec_device *ec = dev_get_drvdata(dev->parent);
+ struct iio_dev *indio_dev;
+ struct cros_ec_mkbp_proximity_data *data;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->ec = ec;
+ data->indio_dev = indio_dev;
+ data->last_proximity = -1; /* Unknown to start */
+ mutex_init(&data->lock);
+ platform_set_drvdata(pdev, data);
+
+ indio_dev->name = dev->driver->name;
+ indio_dev->info = &cros_ec_mkbp_proximity_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = cros_ec_mkbp_proximity_chan_spec;
+ indio_dev->num_channels = ARRAY_SIZE(cros_ec_mkbp_proximity_chan_spec);
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return ret;
+
+ data->notifier.notifier_call = cros_ec_mkbp_proximity_notify;
+ blocking_notifier_chain_register(&ec->event_notifier, &data->notifier);
+
+ return 0;
+}
+
+static int cros_ec_mkbp_proximity_remove(struct platform_device *pdev)
+{
+ struct cros_ec_mkbp_proximity_data *data = platform_get_drvdata(pdev);
+ struct cros_ec_device *ec = data->ec;
+
+ blocking_notifier_chain_unregister(&ec->event_notifier,
+ &data->notifier);
+
+ return 0;
+}
+
+static const struct of_device_id cros_ec_mkbp_proximity_of_match[] = {
+ { .compatible = "google,cros-ec-mkbp-proximity" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cros_ec_mkbp_proximity_of_match);
+
+static struct platform_driver cros_ec_mkbp_proximity_driver = {
+ .driver = {
+ .name = "cros-ec-mkbp-proximity",
+ .of_match_table = cros_ec_mkbp_proximity_of_match,
+ .pm = &cros_ec_mkbp_proximity_pm_ops,
+ },
+ .probe = cros_ec_mkbp_proximity_probe,
+ .remove = cros_ec_mkbp_proximity_remove,
+};
+module_platform_driver(cros_ec_mkbp_proximity_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ChromeOS EC MKBP proximity sensor driver");
diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c
index 37fd0b65a014..394c2afe0f23 100644
--- a/drivers/iio/proximity/sx9310.c
+++ b/drivers/iio/proximity/sx9310.c
@@ -1453,7 +1453,6 @@ static int sx9310_probe(struct i2c_client *client)
if (!data->trig)
return -ENOMEM;
- data->trig->dev.parent = dev;
data->trig->ops = &sx9310_trigger_ops;
iio_trigger_set_drvdata(data->trig, indio_dev);
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index acb821cbad46..a87f4a8e4327 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -758,7 +758,7 @@ static const struct sx9500_reg_default sx9500_default_regs[] = {
.reg = SX9500_REG_PROX_CTRL5,
/*
* Debouncer off, lowest average negative filter,
- * highest average postive filter.
+ * highest average positive filter.
*/
.def = 0x0f,
},
@@ -950,7 +950,6 @@ static int sx9500_probe(struct i2c_client *client,
if (!data->trig)
return -ENOMEM;
- data->trig->dev.parent = &client->dev;
data->trig->ops = &sx9500_trigger_ops;
iio_trigger_set_drvdata(data->trig, indio_dev);
diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c
index 37264f801ad0..43817f6b3086 100644
--- a/drivers/iio/proximity/vcnl3020.c
+++ b/drivers/iio/proximity/vcnl3020.c
@@ -40,6 +40,17 @@
#define VCNL_ON_DEMAND_TIMEOUT_US 100000
#define VCNL_POLL_US 20000
+static const int vcnl3020_prox_sampling_frequency[][2] = {
+ {1, 950000},
+ {3, 906250},
+ {7, 812500},
+ {16, 625000},
+ {31, 250000},
+ {62, 500000},
+ {125, 0},
+ {250, 0},
+};
+
/**
* struct vcnl3020_data - vcnl3020 specific data.
* @regmap: device register map.
@@ -165,10 +176,51 @@ err_unlock:
return rc;
}
+static int vcnl3020_read_proxy_samp_freq(struct vcnl3020_data *data, int *val,
+ int *val2)
+{
+ int rc;
+ unsigned int prox_rate;
+
+ rc = regmap_read(data->regmap, VCNL_PROXIMITY_RATE, &prox_rate);
+ if (rc)
+ return rc;
+
+ if (prox_rate >= ARRAY_SIZE(vcnl3020_prox_sampling_frequency))
+ return -EINVAL;
+
+ *val = vcnl3020_prox_sampling_frequency[prox_rate][0];
+ *val2 = vcnl3020_prox_sampling_frequency[prox_rate][1];
+
+ return 0;
+}
+
+static int vcnl3020_write_proxy_samp_freq(struct vcnl3020_data *data, int val,
+ int val2)
+{
+ unsigned int i;
+ int index = -1;
+
+ for (i = 0; i < ARRAY_SIZE(vcnl3020_prox_sampling_frequency); i++) {
+ if (val == vcnl3020_prox_sampling_frequency[i][0] &&
+ val2 == vcnl3020_prox_sampling_frequency[i][1]) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index < 0)
+ return -EINVAL;
+
+ return regmap_write(data->regmap, VCNL_PROXIMITY_RATE, index);
+}
+
static const struct iio_chan_spec vcnl3020_channels[] = {
{
.type = IIO_PROXIMITY,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
};
@@ -185,6 +237,47 @@ static int vcnl3020_read_raw(struct iio_dev *indio_dev,
if (rc)
return rc;
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ rc = vcnl3020_read_proxy_samp_freq(data, val, val2);
+ if (rc < 0)
+ return rc;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vcnl3020_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ int rc;
+ struct vcnl3020_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ rc = iio_device_claim_direct_mode(indio_dev);
+ if (rc)
+ return rc;
+ rc = vcnl3020_write_proxy_samp_freq(data, val, val2);
+ iio_device_release_direct_mode(indio_dev);
+ return rc;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vcnl3020_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = (int *)vcnl3020_prox_sampling_frequency;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *length = 2 * ARRAY_SIZE(vcnl3020_prox_sampling_frequency);
+ return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
@@ -192,6 +285,8 @@ static int vcnl3020_read_raw(struct iio_dev *indio_dev,
static const struct iio_info vcnl3020_info = {
.read_raw = vcnl3020_read_raw,
+ .write_raw = vcnl3020_write_raw,
+ .read_avail = vcnl3020_read_avail,
};
static const struct regmap_config vcnl3020_regmap_config = {
diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c
index da9a247097fa..dc534ed784c3 100644
--- a/drivers/iio/temperature/hid-sensor-temperature.c
+++ b/drivers/iio/temperature/hid-sensor-temperature.c
@@ -25,6 +25,10 @@ struct temperature_state {
int value_offset;
};
+static const u32 temperature_sensitivity_addresses[] = {
+ HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE,
+};
+
/* Channel definitions */
static const struct iio_chan_spec temperature_channels[] = {
{
@@ -173,14 +177,6 @@ static int temperature_parse_report(struct platform_device *pdev,
&st->temperature_attr,
&st->scale_pre_decml, &st->scale_post_decml);
- /* Set Sensitivity field ids, when there is no individual modifier */
- if (st->common_attributes.sensitivity.index < 0)
- sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, usage_id,
- HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
- HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE,
- &st->common_attributes.sensitivity);
-
return ret;
}
@@ -209,7 +205,9 @@ static int hid_temperature_probe(struct platform_device *pdev)
ret = hid_sensor_parse_common_attributes(hsdev,
HID_USAGE_SENSOR_TEMPERATURE,
- &temp_st->common_attributes);
+ &temp_st->common_attributes,
+ temperature_sensitivity_addresses,
+ ARRAY_SIZE(temperature_sensitivity_addresses));
if (ret)
return ret;
diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c
index ad2b35c65548..b422371a4674 100644
--- a/drivers/iio/temperature/tmp007.c
+++ b/drivers/iio/temperature/tmp007.c
@@ -439,6 +439,13 @@ static bool tmp007_identify(struct i2c_client *client)
return (manf_id == TMP007_MANUFACTURER_MAGIC && dev_id == TMP007_DEVICE_MAGIC);
}
+static void tmp007_powerdown_action_cb(void *priv)
+{
+ struct tmp007_data *data = priv;
+
+ tmp007_powerdown(data);
+}
+
static int tmp007_probe(struct i2c_client *client,
const struct i2c_device_id *tmp007_id)
{
@@ -489,6 +496,10 @@ static int tmp007_probe(struct i2c_client *client,
if (ret < 0)
return ret;
+ ret = devm_add_action_or_reset(&client->dev, tmp007_powerdown_action_cb, data);
+ if (ret)
+ return ret;
+
/*
* Only the following flags can activate ALERT pin. Data conversion/validity flags
* flags can still be polled for getting temperature data
@@ -502,7 +513,7 @@ static int tmp007_probe(struct i2c_client *client,
ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS_MASK);
if (ret < 0)
- goto error_powerdown;
+ return ret;
data->status_mask = ret;
data->status_mask |= (TMP007_STATUS_OHF | TMP007_STATUS_OLF
@@ -510,7 +521,7 @@ static int tmp007_probe(struct i2c_client *client,
ret = i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK, data->status_mask);
if (ret < 0)
- goto error_powerdown;
+ return ret;
if (client->irq) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
@@ -519,27 +530,11 @@ static int tmp007_probe(struct i2c_client *client,
tmp007_id->name, indio_dev);
if (ret) {
dev_err(&client->dev, "irq request error %d\n", -ret);
- goto error_powerdown;
+ return ret;
}
}
- return iio_device_register(indio_dev);
-
-error_powerdown:
- tmp007_powerdown(data);
-
- return ret;
-}
-
-static int tmp007_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct tmp007_data *data = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- tmp007_powerdown(data);
-
- return 0;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -582,7 +577,6 @@ static struct i2c_driver tmp007_driver = {
.pm = &tmp007_pm_ops,
},
.probe = tmp007_probe,
- .remove = tmp007_remove,
.id_table = tmp007_id,
};
module_i2c_driver(tmp007_driver);
diff --git a/drivers/iio/test/Kconfig b/drivers/iio/test/Kconfig
new file mode 100644
index 000000000000..679a7794af20
--- /dev/null
+++ b/drivers/iio/test/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Industrial I/O subsystem unit tests configuration
+#
+
+# Keep in alphabetical order
+config IIO_TEST_FORMAT
+ bool "Test IIO formatting functions"
+ depends on KUNIT=y
diff --git a/drivers/iio/test/Makefile b/drivers/iio/test/Makefile
new file mode 100644
index 000000000000..f1099b495301
--- /dev/null
+++ b/drivers/iio/test/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the industrial I/O unit tests.
+#
+
+# Keep in alphabetical order
+obj-$(CONFIG_IIO_TEST_FORMAT) += iio-test-format.o
diff --git a/drivers/iio/test/iio-test-format.c b/drivers/iio/test/iio-test-format.c
new file mode 100644
index 000000000000..55a0cfe9181d
--- /dev/null
+++ b/drivers/iio/test/iio-test-format.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Unit tests for IIO formatting functions
+ *
+ * Copyright (c) 2020 Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <kunit/test.h>
+#include <linux/iio/iio.h>
+
+#define IIO_TEST_FORMAT_EXPECT_EQ(_test, _buf, _ret, _val) do { \
+ KUNIT_EXPECT_EQ(_test, (int)strlen(_buf), _ret); \
+ KUNIT_EXPECT_STREQ(_test, (_buf), (_val)); \
+ } while (0)
+
+static void iio_test_iio_format_value_integer(struct kunit *test)
+{
+ char *buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL);
+ int val;
+ int ret;
+
+ val = 42;
+ ret = iio_format_value(buf, IIO_VAL_INT, 1, &val);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "42\n");
+
+ val = -23;
+ ret = iio_format_value(buf, IIO_VAL_INT, 1, &val);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-23\n");
+
+ val = 0;
+ ret = iio_format_value(buf, IIO_VAL_INT, 1, &val);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0\n");
+
+ val = INT_MAX;
+ ret = iio_format_value(buf, IIO_VAL_INT, 1, &val);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "2147483647\n");
+
+ val = INT_MIN;
+ ret = iio_format_value(buf, IIO_VAL_INT, 1, &val);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-2147483648\n");
+}
+
+static void iio_test_iio_format_value_fixedpoint(struct kunit *test)
+{
+ char *buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL);
+ int values[2];
+ int ret;
+
+ /* positive >= 1 */
+ values[0] = 1;
+ values[1] = 10;
+
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.000010\n");
+
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO_DB, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.000010 dB\n");
+
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_NANO, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.000000010\n");
+
+ /* positive < 1 */
+ values[0] = 0;
+ values[1] = 12;
+
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000012\n");
+
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO_DB, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000012 dB\n");
+
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_NANO, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000000012\n");
+
+ /* negative <= -1 */
+ values[0] = -1;
+ values[1] = 10;
+
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-1.000010\n");
+
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO_DB, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-1.000010 dB\n");
+
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_NANO, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-1.000000010\n");
+
+ /* negative > -1 */
+ values[0] = 0;
+ values[1] = -123;
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.000123\n");
+
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO_DB, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.000123 dB\n");
+
+ ret = iio_format_value(buf, IIO_VAL_INT_PLUS_NANO, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.000000123\n");
+}
+
+static void iio_test_iio_format_value_fractional(struct kunit *test)
+{
+ char *buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL);
+ int values[2];
+ int ret;
+
+ /* positive < 1 */
+ values[0] = 1;
+ values[1] = 10;
+ ret = iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.100000000\n");
+
+ /* positive >= 1 */
+ values[0] = 100;
+ values[1] = 3;
+ ret = iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "33.333333333\n");
+
+ /* negative > -1 */
+ values[0] = -1;
+ values[1] = 1000000000;
+ ret = iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.000000001\n");
+
+ /* negative <= -1 */
+ values[0] = -200;
+ values[1] = 3;
+ ret = iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-66.666666666\n");
+
+ /* Zero */
+ values[0] = 0;
+ values[1] = -10;
+ ret = iio_format_value(buf, IIO_VAL_FRACTIONAL, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000000000\n");
+}
+
+static void iio_test_iio_format_value_fractional_log2(struct kunit *test)
+{
+ char *buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL);
+ int values[2];
+ int ret;
+
+ /* positive < 1 */
+ values[0] = 123;
+ values[1] = 10;
+ ret = iio_format_value(buf, IIO_VAL_FRACTIONAL_LOG2, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.120117187\n");
+
+ /* positive >= 1 */
+ values[0] = 1234567;
+ values[1] = 10;
+ ret = iio_format_value(buf, IIO_VAL_FRACTIONAL_LOG2, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1205.631835937\n");
+
+ /* negative > -1 */
+ values[0] = -123;
+ values[1] = 10;
+ ret = iio_format_value(buf, IIO_VAL_FRACTIONAL_LOG2, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.120117187\n");
+
+ /* negative <= -1 */
+ values[0] = -1234567;
+ values[1] = 10;
+ ret = iio_format_value(buf, IIO_VAL_FRACTIONAL_LOG2, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-1205.631835937\n");
+
+ /* Zero */
+ values[0] = 0;
+ values[1] = 10;
+ ret = iio_format_value(buf, IIO_VAL_FRACTIONAL_LOG2, 2, values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000000000\n");
+}
+
+static void iio_test_iio_format_value_multiple(struct kunit *test)
+{
+ char *buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL);
+ int values[] = {1, -2, 3, -4, 5};
+ int ret;
+
+ ret = iio_format_value(buf, IIO_VAL_INT_MULTIPLE,
+ ARRAY_SIZE(values), values);
+ IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1 -2 3 -4 5 \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),
+ KUNIT_CASE(iio_test_iio_format_value_fractional),
+ KUNIT_CASE(iio_test_iio_format_value_fractional_log2),
+ KUNIT_CASE(iio_test_iio_format_value_multiple),
+ {}
+};
+
+static struct kunit_suite iio_format_test_suite = {
+ .name = "iio-format",
+ .test_cases = iio_format_test_cases,
+};
+kunit_test_suite(iio_format_test_suite);
diff --git a/drivers/iio/trigger/iio-trig-hrtimer.c b/drivers/iio/trigger/iio-trig-hrtimer.c
index 410de837d041..51e362f091c2 100644
--- a/drivers/iio/trigger/iio-trig-hrtimer.c
+++ b/drivers/iio/trigger/iio-trig-hrtimer.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* The industrial I/O periodic hrtimer trigger driver
*
* Copyright (C) Intuitive Aerial AB
@@ -16,13 +16,16 @@
#include <linux/iio/trigger.h>
#include <linux/iio/sw_trigger.h>
+/* Defined locally, not in time64.h yet. */
+#define PSEC_PER_SEC 1000000000000LL
+
/* default sampling frequency - 100Hz */
#define HRTIMER_DEFAULT_SAMPLING_FREQUENCY 100
struct iio_hrtimer_info {
struct iio_sw_trigger swt;
struct hrtimer timer;
- unsigned long sampling_frequency;
+ int sampling_frequency[2];
ktime_t period;
};
@@ -38,7 +41,9 @@ ssize_t iio_hrtimer_show_sampling_frequency(struct device *dev,
struct iio_trigger *trig = to_iio_trigger(dev);
struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig);
- return snprintf(buf, PAGE_SIZE, "%lu\n", info->sampling_frequency);
+ return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO,
+ ARRAY_SIZE(info->sampling_frequency),
+ info->sampling_frequency);
}
static
@@ -48,18 +53,26 @@ ssize_t iio_hrtimer_store_sampling_frequency(struct device *dev,
{
struct iio_trigger *trig = to_iio_trigger(dev);
struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig);
- unsigned long val;
- int ret;
+ unsigned long long val;
+ u64 period;
+ int integer, fract, ret;
- ret = kstrtoul(buf, 10, &val);
+ ret = iio_str_to_fixpoint(buf, 100, &integer, &fract);
if (ret)
return ret;
+ if (integer < 0 || fract < 0)
+ return -ERANGE;
+
+ val = fract + 1000 * integer; /* mHz */
- if (!val || val > NSEC_PER_SEC)
+ if (!val || val > UINT_MAX)
return -EINVAL;
- info->sampling_frequency = val;
- info->period = NSEC_PER_SEC / val;
+ info->sampling_frequency[0] = integer; /* Hz */
+ info->sampling_frequency[1] = fract * 1000; /* uHz */
+ period = PSEC_PER_SEC;
+ do_div(period, val);
+ info->period = period; /* nS */
return len;
}
@@ -122,7 +135,7 @@ static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name)
if (!trig_info)
return ERR_PTR(-ENOMEM);
- trig_info->swt.trigger = iio_trigger_alloc("%s", name);
+ trig_info->swt.trigger = iio_trigger_alloc(NULL, "%s", name);
if (!trig_info->swt.trigger) {
ret = -ENOMEM;
goto err_free_trig_info;
@@ -135,8 +148,8 @@ static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name)
hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
trig_info->timer.function = iio_hrtimer_trig_handler;
- trig_info->sampling_frequency = HRTIMER_DEFAULT_SAMPLING_FREQUENCY;
- trig_info->period = NSEC_PER_SEC / trig_info->sampling_frequency;
+ trig_info->sampling_frequency[0] = HRTIMER_DEFAULT_SAMPLING_FREQUENCY;
+ trig_info->period = NSEC_PER_SEC / trig_info->sampling_frequency[0];
ret = iio_trigger_register(trig_info->swt.trigger);
if (ret)
diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c
index 94a487caf421..f746c460bf2a 100644
--- a/drivers/iio/trigger/iio-trig-interrupt.c
+++ b/drivers/iio/trigger/iio-trig-interrupt.c
@@ -45,7 +45,7 @@ static int iio_interrupt_trigger_probe(struct platform_device *pdev)
irq = irq_res->start;
- trig = iio_trigger_alloc("irqtrig%d", irq);
+ trig = iio_trigger_alloc(NULL, "irqtrig%d", irq);
if (!trig) {
ret = -ENOMEM;
goto error_ret;
diff --git a/drivers/iio/trigger/iio-trig-loop.c b/drivers/iio/trigger/iio-trig-loop.c
index 4a00668e3258..96ec06bbe546 100644
--- a/drivers/iio/trigger/iio-trig-loop.c
+++ b/drivers/iio/trigger/iio-trig-loop.c
@@ -84,7 +84,7 @@ static struct iio_sw_trigger *iio_trig_loop_probe(const char *name)
if (!trig_info)
return ERR_PTR(-ENOMEM);
- trig_info->swt.trigger = iio_trigger_alloc("%s", name);
+ trig_info->swt.trigger = iio_trigger_alloc(NULL, "%s", name);
if (!trig_info->swt.trigger) {
ret = -ENOMEM;
goto err_free_trig_info;
diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c
index 0f6b512a5c37..e9adfff45b39 100644
--- a/drivers/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/iio/trigger/iio-trig-sysfs.c
@@ -149,7 +149,7 @@ static int iio_sysfs_trigger_probe(int id)
goto out1;
}
t->id = id;
- t->trig = iio_trigger_alloc("sysfstrig%d", id);
+ t->trig = iio_trigger_alloc(&iio_sysfs_trig_dev, "sysfstrig%d", id);
if (!t->trig) {
ret = -ENOMEM;
goto free_t;
@@ -157,7 +157,6 @@ static int iio_sysfs_trigger_probe(int id)
t->trig->dev.groups = iio_sysfs_trigger_attr_groups;
t->trig->ops = &iio_sysfs_trigger_ops;
- t->trig->dev.parent = &iio_sysfs_trig_dev;
iio_trigger_set_drvdata(t->trig, t);
t->work = IRQ_WORK_INIT_HARD(iio_sysfs_trigger_work);
diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c
index 1b42ee0758d2..47cd12db2356 100644
--- a/drivers/rtc/rtc-hid-sensor-time.c
+++ b/drivers/rtc/rtc-hid-sensor-time.c
@@ -238,7 +238,9 @@ static int hid_time_probe(struct platform_device *pdev)
ret = hid_sensor_parse_common_attributes(hsdev,
HID_USAGE_SENSOR_TIME,
- &time_state->common_attributes);
+ &time_state->common_attributes,
+ NULL,
+ 0);
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes!\n");
return ret;
diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO
index 4d469016a13a..0fa6a5500bdb 100644
--- a/drivers/staging/iio/TODO
+++ b/drivers/staging/iio/TODO
@@ -1,9 +1,5 @@
2020-02-25
-ADI Drivers:
-CC the device-drivers-devel@blackfin.uclinux.org mailing list when
-e-mailing the normal IIO list (see below).
-
Contact: Jonathan Cameron <jic23@kernel.org>.
Mailing list: linux-iio@vger.kernel.org
diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index 447937e04ebd..3f1981e287f5 100644
--- a/drivers/staging/iio/frequency/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -86,7 +86,7 @@
* @freq_msg: tuning word spi message
* @phase_xfer: tuning word spi transfer
* @phase_msg: tuning word spi message
- * @lock protect sensor state
+ * @lock: protect sensor state
* @data: spi transmit buffer
* @phase_data: tuning word spi transmit buffer
* @freq_data: tuning word spi transmit buffer
@@ -248,7 +248,7 @@ error_ret:
return ret ? ret : len;
}
-/**
+/*
* see dds.h for further information
*/
diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
index 262c3590e64e..60a3ae5587b9 100644
--- a/drivers/staging/iio/frequency/ad9834.c
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -56,7 +56,6 @@
/**
* struct ad9834_state - driver instance specific data
* @spi: spi_device
- * @reg: supply regulator
* @mclk: external master clock
* @control: cached control word
* @xfer: default spi transfer
@@ -70,7 +69,6 @@
struct ad9834_state {
struct spi_device *spi;
- struct regulator *reg;
struct clk *mclk;
unsigned short control;
unsigned short devid;
@@ -390,6 +388,20 @@ static const struct iio_info ad9833_info = {
.attrs = &ad9833_attribute_group,
};
+static void ad9834_disable_reg(void *data)
+{
+ struct regulator *reg = data;
+
+ regulator_disable(reg);
+}
+
+static void ad9834_disable_clk(void *data)
+{
+ struct clk *clk = data;
+
+ clk_disable_unprepare(clk);
+}
+
static int ad9834_probe(struct spi_device *spi)
{
struct ad9834_state *st;
@@ -407,29 +419,35 @@ static int ad9834_probe(struct spi_device *spi)
return ret;
}
+ ret = devm_add_action_or_reset(&spi->dev, ad9834_disable_reg, reg);
+ if (ret)
+ return ret;
+
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev) {
ret = -ENOMEM;
- goto error_disable_reg;
+ return ret;
}
- spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
mutex_init(&st->lock);
st->mclk = devm_clk_get(&spi->dev, NULL);
if (IS_ERR(st->mclk)) {
ret = PTR_ERR(st->mclk);
- goto error_disable_reg;
+ return ret;
}
ret = clk_prepare_enable(st->mclk);
if (ret) {
dev_err(&spi->dev, "Failed to enable master clock\n");
- goto error_disable_reg;
+ return ret;
}
+ ret = devm_add_action_or_reset(&spi->dev, ad9834_disable_clk, st->mclk);
+ if (ret)
+ return ret;
+
st->spi = spi;
st->devid = spi_get_device_id(spi)->driver_data;
- st->reg = reg;
indio_dev->name = spi_get_device_id(spi)->name;
switch (st->devid) {
case ID_AD9833:
@@ -470,48 +488,26 @@ static int ad9834_probe(struct spi_device *spi)
ret = spi_sync(st->spi, &st->msg);
if (ret) {
dev_err(&spi->dev, "device init failed\n");
- goto error_clock_unprepare;
+ return ret;
}
ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, 1000000);
if (ret)
- goto error_clock_unprepare;
+ return ret;
ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, 5000000);
if (ret)
- goto error_clock_unprepare;
+ return ret;
ret = ad9834_write_phase(st, AD9834_REG_PHASE0, 512);
if (ret)
- goto error_clock_unprepare;
+ return ret;
ret = ad9834_write_phase(st, AD9834_REG_PHASE1, 1024);
if (ret)
- goto error_clock_unprepare;
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_clock_unprepare;
-
- return 0;
-error_clock_unprepare:
- clk_disable_unprepare(st->mclk);
-error_disable_reg:
- regulator_disable(reg);
-
- return ret;
-}
-
-static int ad9834_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad9834_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- clk_disable_unprepare(st->mclk);
- regulator_disable(st->reg);
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad9834_id[] = {
@@ -539,7 +535,6 @@ static struct spi_driver ad9834_driver = {
.of_match_table = ad9834_of_match
},
.probe = ad9834_probe,
- .remove = ad9834_remove,
.id_table = ad9834_id,
};
module_spi_driver(ad9834_driver);
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index dba78896ea8f..793918e1c45f 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -602,23 +602,6 @@ static const struct iio_buffer_setup_ops ad5933_ring_setup_ops = {
.postdisable = ad5933_ring_postdisable,
};
-static int ad5933_register_ring_funcs_and_init(struct device *dev,
- struct iio_dev *indio_dev)
-{
- struct iio_buffer *buffer;
-
- buffer = devm_iio_kfifo_allocate(dev);
- if (!buffer)
- return -ENOMEM;
-
- iio_device_attach_buffer(indio_dev, buffer);
-
- /* Ring buffer functions - here trigger setup related */
- indio_dev->setup_ops = &ad5933_ring_setup_ops;
-
- return 0;
-}
-
static void ad5933_work(struct work_struct *work)
{
struct ad5933_state *st = container_of(work,
@@ -761,11 +744,13 @@ static int ad5933_probe(struct i2c_client *client,
indio_dev->info = &ad5933_info;
indio_dev->name = id->name;
- indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
+ indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ad5933_channels;
indio_dev->num_channels = ARRAY_SIZE(ad5933_channels);
- ret = ad5933_register_ring_funcs_and_init(&client->dev, indio_dev);
+ ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &ad5933_ring_setup_ops);
if (ret)
return ret;
diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h
index 763802b2b8f9..c27329e2a5ad 100644
--- a/include/linux/hid-sensor-hub.h
+++ b/include/linux/hid-sensor-hub.h
@@ -231,6 +231,7 @@ struct hid_sensor_common {
struct hid_sensor_hub_attribute_info report_state;
struct hid_sensor_hub_attribute_info power_state;
struct hid_sensor_hub_attribute_info sensitivity;
+ struct hid_sensor_hub_attribute_info sensitivity_rel;
struct hid_sensor_hub_attribute_info report_latency;
struct work_struct work;
};
@@ -248,11 +249,17 @@ static inline int hid_sensor_convert_exponent(int unit_expo)
int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
- struct hid_sensor_common *st);
+ struct hid_sensor_common *st,
+ const u32 *sensitivity_addresses,
+ u32 sensitivity_addresses_len);
int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
int val1, int val2);
+int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, int val1,
+ int val2);
int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
int *val1, int *val2);
+int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st,
+ int *val1, int *val2);
int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
int val1, int val2);
int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h
index 3bbdbccc5805..ac631159403a 100644
--- a/include/linux/hid-sensor-ids.h
+++ b/include/linux/hid-sensor-ids.h
@@ -149,6 +149,7 @@
/* Per data field properties */
#define HID_USAGE_SENSOR_DATA_MOD_NONE 0x00
#define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS 0x1000
+#define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_REL_PCT 0xE000
/* Power state enumerations */
#define HID_USAGE_SENSOR_PROP_POWER_STATE_UNDEFINED_ENUM 0x200850
diff --git a/include/linux/iio/adc/adi-axi-adc.h b/include/linux/iio/adc/adi-axi-adc.h
index c5d48e1c2d36..52620e5b8052 100644
--- a/include/linux/iio/adc/adi-axi-adc.h
+++ b/include/linux/iio/adc/adi-axi-adc.h
@@ -15,7 +15,7 @@ struct iio_chan_spec;
* struct adi_axi_adc_chip_info - Chip specific information
* @name Chip name
* @id Chip ID (usually product ID)
- * @channels Channel specifications of type @struct axi_adc_chan_spec
+ * @channels Channel specifications of type @struct iio_chan_spec
* @num_channels Number of @channels
* @scale_table Supported scales by the chip; tuples of 2 ints
* @num_scales Number of scales in the table
diff --git a/include/linux/iio/buffer-dmaengine.h b/include/linux/iio/buffer-dmaengine.h
index 5b502291d6a4..5c355be89814 100644
--- a/include/linux/iio/buffer-dmaengine.h
+++ b/include/linux/iio/buffer-dmaengine.h
@@ -7,10 +7,11 @@
#ifndef __IIO_DMAENGINE_H__
#define __IIO_DMAENGINE_H__
-struct iio_buffer;
+struct iio_dev;
struct device;
-struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev,
- const char *channel);
+int devm_iio_dmaengine_buffer_setup(struct device *dev,
+ struct iio_dev *indio_dev,
+ const char *channel);
#endif
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index 8febc23f5f26..b6928ac5c63d 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -41,7 +41,7 @@ static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev,
bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev,
const unsigned long *mask);
-void iio_device_attach_buffer(struct iio_dev *indio_dev,
- struct iio_buffer *buffer);
+int iio_device_attach_buffer(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer);
#endif /* _IIO_BUFFER_GENERIC_H_ */
diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h
index a63dc07b7350..245b32918ae1 100644
--- a/include/linux/iio/buffer_impl.h
+++ b/include/linux/iio/buffer_impl.h
@@ -6,6 +6,8 @@
#ifdef CONFIG_IIO_BUFFER
+#include <uapi/linux/iio/buffer.h>
+
struct iio_dev;
struct iio_buffer;
@@ -72,6 +74,9 @@ struct iio_buffer {
/** @length: Number of datums in buffer. */
unsigned int length;
+ /** @flags: File ops flags including busy flag. */
+ unsigned long flags;
+
/** @bytes_per_datum: Size of individual datum including timestamp. */
size_t bytes_per_datum;
@@ -97,17 +102,14 @@ struct iio_buffer {
/* @scan_timestamp: Does the scan mode include a timestamp. */
bool scan_timestamp;
- /* @scan_el_dev_attr_list: List of scan element related attributes. */
- struct list_head scan_el_dev_attr_list;
-
- /* @buffer_group: Attributes of the buffer group. */
- struct attribute_group buffer_group;
+ /* @buffer_attr_list: List of buffer attributes. */
+ struct list_head buffer_attr_list;
/*
- * @scan_el_group: Attribute group for those attributes not
- * created from the iio_chan_info array.
+ * @buffer_group: Attributes of the new buffer group.
+ * Includes scan elements attributes.
*/
- struct attribute_group scan_el_group;
+ struct attribute_group buffer_group;
/* @attrs: Standard attributes of the buffer. */
const struct attribute **attrs;
@@ -115,6 +117,9 @@ struct iio_buffer {
/* @demux_bounce: Buffer for doing gather from incoming scan. */
void *demux_bounce;
+ /* @attached_entry: Entry in the devices list of buffers attached by the driver. */
+ struct list_head attached_entry;
+
/* @buffer_list: Entry in the devices list of current buffers. */
struct list_head buffer_list;
diff --git a/include/linux/iio/common/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h
index c9b80be82440..7ce8a8adad58 100644
--- a/include/linux/iio/common/cros_ec_sensors_core.h
+++ b/include/linux/iio/common/cros_ec_sensors_core.h
@@ -96,8 +96,7 @@ struct platform_device;
int cros_ec_sensors_core_init(struct platform_device *pdev,
struct iio_dev *indio_dev, bool physical_device,
cros_ec_sensors_capture_t trigger_capture,
- cros_ec_sensorhub_push_data_cb_t push_data,
- bool has_hw_fifo);
+ cros_ec_sensorhub_push_data_cb_t push_data);
irqreturn_t cros_ec_sensors_capture(int irq, void *p);
int cros_ec_sensors_push_data(struct iio_dev *indio_dev,
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 0a90ba8fa1bb..5fa5957586cf 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -242,6 +242,21 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val);
int iio_read_channel_processed(struct iio_channel *chan, int *val);
/**
+ * iio_read_channel_processed_scale() - read and scale a processed value
+ * @chan: The channel being queried.
+ * @val: Value read back.
+ * @scale: Scale factor to apply during the conversion
+ *
+ * Returns an error code or 0.
+ *
+ * This function will read a processed value from a channel. This will work
+ * like @iio_read_channel_processed() but also scale with an additional
+ * scale factor while attempting to minimize any precision loss.
+ */
+int iio_read_channel_processed_scale(struct iio_channel *chan, int *val,
+ unsigned int scale);
+
+/**
* iio_write_channel_attribute() - Write values to the device attribute.
* @chan: The channel being queried.
* @val: Value being written.
diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h
index 07c5a8e52ca8..32addd5e790e 100644
--- a/include/linux/iio/iio-opaque.h
+++ b/include/linux/iio/iio-opaque.h
@@ -7,11 +7,18 @@
* struct iio_dev_opaque - industrial I/O device opaque information
* @indio_dev: public industrial I/O device information
* @event_interface: event chrdevs associated with interrupt lines
+ * @attached_buffers: array of buffers statically attached by the driver
+ * @attached_buffers_cnt: number of buffers in the array of statically attached buffers
+ * @buffer_ioctl_handler: ioctl() handler for this IIO device's buffer interface
* @buffer_list: list of all buffers currently attached
* @channel_attr_list: keep track of automatically created channel
* attributes
* @chan_attr_group: group for all attrs in base directory
* @ioctl_handlers: ioctl handlers registered with the core handler
+ * @groups: attribute groups
+ * @groupcounter: index of next attribute group
+ * @legacy_scan_el_group: attribute group for legacy scan elements attribute group
+ * @legacy_buffer_group: attribute group for legacy buffer attributes group
* @debugfs_dentry: device specific debugfs dentry
* @cached_reg_addr: cached register address for debugfs reads
* @read_buf: read buffer to be used for the initial reg read
@@ -20,10 +27,17 @@
struct iio_dev_opaque {
struct iio_dev indio_dev;
struct iio_event_interface *event_interface;
+ struct iio_buffer **attached_buffers;
+ unsigned int attached_buffers_cnt;
+ struct iio_ioctl_handler *buffer_ioctl_handler;
struct list_head buffer_list;
struct list_head channel_attr_list;
struct attribute_group chan_attr_group;
struct list_head ioctl_handlers;
+ const struct attribute_group **groups;
+ int groupcounter;
+ struct attribute_group legacy_scan_el_group;
+ struct attribute_group legacy_buffer_group;
#if defined(CONFIG_DEBUG_FS)
struct dentry *debugfs_dentry;
unsigned cached_reg_addr;
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index e4a9822e6495..f2d65e2e88b6 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -518,8 +518,6 @@ struct iio_buffer_setup_ops {
* @setup_ops: [DRIVER] callbacks to call before and after buffer
* enable/disable
* @chrdev: [INTERN] associated character device
- * @groups: [INTERN] attribute groups
- * @groupcounter: [INTERN] index of next attribute group
* @flags: [INTERN] file ops related flags including busy flag.
* @priv: [DRIVER] reference to driver's private information
* **MUST** be accessed **ONLY** via iio_priv() helper
@@ -556,9 +554,6 @@ struct iio_dev {
struct mutex info_exist_lock;
const struct iio_buffer_setup_ops *setup_ops;
struct cdev chrdev;
-#define IIO_MAX_GROUPS 6
- const struct attribute_group *groups[IIO_MAX_GROUPS + 1];
- int groupcounter;
unsigned long flags;
void *priv;
@@ -698,7 +693,7 @@ static inline void *iio_priv(const struct iio_dev *indio_dev)
void iio_device_free(struct iio_dev *indio_dev);
struct iio_dev *devm_iio_device_alloc(struct device *parent, int sizeof_priv);
__printf(2, 3)
-struct iio_trigger *devm_iio_trigger_alloc(struct device *dev,
+struct iio_trigger *devm_iio_trigger_alloc(struct device *parent,
const char *fmt, ...);
/**
* iio_buffer_enabled() - helper function to test if the buffer is enabled
diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
index 04e96d688ba9..f9b728d490b1 100644
--- a/include/linux/iio/imu/adis.h
+++ b/include/linux/iio/imu/adis.h
@@ -428,6 +428,16 @@ static inline int adis_initial_startup(struct adis *adis)
return ret;
}
+static inline void adis_dev_lock(struct adis *adis)
+{
+ mutex_lock(&adis->state_lock);
+}
+
+static inline void adis_dev_unlock(struct adis *adis)
+{
+ mutex_unlock(&adis->state_lock);
+}
+
int adis_single_conversion(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int error_mask,
int *val);
diff --git a/include/linux/iio/kfifo_buf.h b/include/linux/iio/kfifo_buf.h
index 1fc1efa7799d..ccd2ceae7b25 100644
--- a/include/linux/iio/kfifo_buf.h
+++ b/include/linux/iio/kfifo_buf.h
@@ -3,11 +3,20 @@
#define __LINUX_IIO_KFIFO_BUF_H__
struct iio_buffer;
+struct iio_buffer_setup_ops;
+struct iio_dev;
struct device;
struct iio_buffer *iio_kfifo_allocate(void);
void iio_kfifo_free(struct iio_buffer *r);
-struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev);
+int devm_iio_kfifo_buffer_setup_ext(struct device *dev,
+ struct iio_dev *indio_dev,
+ int mode_flags,
+ const struct iio_buffer_setup_ops *setup_ops,
+ const struct attribute **buffer_attrs);
+
+#define devm_iio_kfifo_buffer_setup(dev, indio_dev, mode_flags, setup_ops) \
+ devm_iio_kfifo_buffer_setup_ext((dev), (indio_dev), (mode_flags), (setup_ops), NULL)
#endif
diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h
index b532c875bc24..e51fba66de4b 100644
--- a/include/linux/iio/sysfs.h
+++ b/include/linux/iio/sysfs.h
@@ -9,6 +9,7 @@
#ifndef _INDUSTRIAL_IO_SYSFS_H_
#define _INDUSTRIAL_IO_SYSFS_H_
+struct iio_buffer;
struct iio_chan_spec;
/**
@@ -17,12 +18,14 @@ struct iio_chan_spec;
* @address: associated register address
* @l: list head for maintaining list of dynamically created attrs
* @c: specification for the underlying channel
+ * @buffer: the IIO buffer to which this attribute belongs to (if any)
*/
struct iio_dev_attr {
struct device_attribute dev_attr;
u64 address;
struct list_head l;
struct iio_chan_spec const *c;
+ struct iio_buffer *buffer;
};
#define to_iio_dev_attr(_dev_attr) \
diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h
index 055890b6ffcf..096f68dd2e0c 100644
--- a/include/linux/iio/trigger.h
+++ b/include/linux/iio/trigger.h
@@ -161,7 +161,8 @@ void iio_trigger_poll_chained(struct iio_trigger *trig);
irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private);
-__printf(1, 2) struct iio_trigger *iio_trigger_alloc(const char *fmt, ...);
+__printf(2, 3)
+struct iio_trigger *iio_trigger_alloc(struct device *parent, const char *fmt, ...);
void iio_trigger_free(struct iio_trigger *trig);
/**
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
index 1e3ed6f55bca..5aa7f66d4345 100644
--- a/include/linux/iio/types.h
+++ b/include/linux/iio/types.h
@@ -50,6 +50,7 @@ enum iio_chan_info_enum {
IIO_CHAN_INFO_PHASE,
IIO_CHAN_INFO_HARDWAREGAIN,
IIO_CHAN_INFO_HYSTERESIS,
+ IIO_CHAN_INFO_HYSTERESIS_RELATIVE,
IIO_CHAN_INFO_INT_TIME,
IIO_CHAN_INFO_ENABLE,
IIO_CHAN_INFO_CALIBHEIGHT,
diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index 5ff8597ceabd..6035d9a98fb8 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -3467,6 +3467,7 @@ struct ec_response_get_next_event_v1 {
#define EC_MKBP_LID_OPEN 0
#define EC_MKBP_TABLET_MODE 1
#define EC_MKBP_BASE_ATTACHED 2
+#define EC_MKBP_FRONT_PROXIMITY 3
/* Run keyboard factory test scanning */
#define EC_CMD_KEYBOARD_FACTORY_TEST 0x0068
diff --git a/include/uapi/linux/iio/buffer.h b/include/uapi/linux/iio/buffer.h
new file mode 100644
index 000000000000..13939032b3f6
--- /dev/null
+++ b/include/uapi/linux/iio/buffer.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* industrial I/O buffer definitions needed both in and out of kernel
+ */
+
+#ifndef _UAPI_IIO_BUFFER_H_
+#define _UAPI_IIO_BUFFER_H_
+
+#define IIO_BUFFER_GET_FD_IOCTL _IOWR('i', 0x91, int)
+
+#endif /* _UAPI_IIO_BUFFER_H_ */
diff --git a/tools/iio/Makefile b/tools/iio/Makefile
index 3de763d9ab70..5d12ac4e7f8f 100644
--- a/tools/iio/Makefile
+++ b/tools/iio/Makefile
@@ -27,6 +27,7 @@ include $(srctree)/tools/build/Makefile.include
#
$(OUTPUT)include/linux/iio: ../../include/uapi/linux/iio
mkdir -p $(OUTPUT)include/linux/iio 2>&1 || true
+ ln -sf $(CURDIR)/../../include/uapi/linux/iio/buffer.h $@
ln -sf $(CURDIR)/../../include/uapi/linux/iio/events.h $@
ln -sf $(CURDIR)/../../include/uapi/linux/iio/types.h $@
diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c
index bb03859db89d..0076437f6e3f 100644
--- a/tools/iio/iio_event_monitor.c
+++ b/tools/iio/iio_event_monitor.c
@@ -14,6 +14,7 @@
#include <unistd.h>
#include <stdlib.h>
+#include <dirent.h>
#include <stdbool.h>
#include <stdio.h>
#include <errno.h>
@@ -280,22 +281,69 @@ static void print_event(struct iio_event_data *event)
printf("\n");
}
+/* Enable or disable events in sysfs if the knob is available */
+static void enable_events(char *dev_dir, int enable)
+{
+ const struct dirent *ent;
+ char evdir[256];
+ int ret;
+ DIR *dp;
+
+ snprintf(evdir, sizeof(evdir), FORMAT_EVENTS_DIR, dev_dir);
+ evdir[sizeof(evdir)-1] = '\0';
+
+ dp = opendir(evdir);
+ if (!dp) {
+ fprintf(stderr, "Enabling/disabling events: can't open %s\n",
+ evdir);
+ return;
+ }
+
+ while (ent = readdir(dp), ent) {
+ if (iioutils_check_suffix(ent->d_name, "_en")) {
+ printf("%sabling: %s\n",
+ enable ? "En" : "Dis",
+ ent->d_name);
+ ret = write_sysfs_int(ent->d_name, evdir,
+ enable);
+ if (ret < 0)
+ fprintf(stderr, "Failed to enable/disable %s\n",
+ ent->d_name);
+ }
+ }
+
+ if (closedir(dp) == -1) {
+ perror("Enabling/disabling channels: "
+ "Failed to close directory");
+ return;
+ }
+}
+
int main(int argc, char **argv)
{
struct iio_event_data event;
const char *device_name;
+ char *dev_dir_name = NULL;
char *chrdev_name;
int ret;
int dev_num;
int fd, event_fd;
-
- if (argc <= 1) {
- fprintf(stderr, "Usage: %s <device_name>\n", argv[0]);
+ bool all_events = false;
+
+ if (argc == 2) {
+ device_name = argv[1];
+ } else if (argc == 3) {
+ device_name = argv[2];
+ if (!strcmp(argv[1], "-a"))
+ all_events = true;
+ } else {
+ fprintf(stderr,
+ "Usage: iio_event_monitor [options] <device_name>\n"
+ "Listen and display events from IIO devices\n"
+ " -a Auto-activate all available events\n");
return -1;
}
- device_name = argv[1];
-
dev_num = find_type_by_name(device_name, "iio:device");
if (dev_num >= 0) {
printf("Found IIO device with name %s with device number %d\n",
@@ -303,6 +351,10 @@ int main(int argc, char **argv)
ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num);
if (ret < 0)
return -ENOMEM;
+ /* Look up sysfs dir as well if we can */
+ ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
+ if (ret < 0)
+ return -ENOMEM;
} else {
/*
* If we can't find an IIO device by name assume device_name is
@@ -313,6 +365,9 @@ int main(int argc, char **argv)
return -ENOMEM;
}
+ if (all_events && dev_dir_name)
+ enable_events(dev_dir_name, 1);
+
fd = open(chrdev_name, 0);
if (fd == -1) {
ret = -errno;
@@ -365,6 +420,10 @@ int main(int argc, char **argv)
perror("Failed to close event file");
error_free_chrdev_name:
+ /* Disable events after use */
+ if (all_events && dev_dir_name)
+ enable_events(dev_dir_name, 0);
+
free(chrdev_name);
return ret;
diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c
index 34d63bcebcd2..2491c54a5e4f 100644
--- a/tools/iio/iio_generic_buffer.c
+++ b/tools/iio/iio_generic_buffer.c
@@ -30,6 +30,8 @@
#include <inttypes.h>
#include <stdbool.h>
#include <signal.h>
+#include <sys/ioctl.h>
+#include <linux/iio/buffer.h>
#include "iio_utils.h"
/**
@@ -49,7 +51,7 @@ enum autochan {
* Has the side effect of filling the channels[i].location values used
* in processing the buffer output.
**/
-int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
+static int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
{
int bytes = 0;
int i = 0;
@@ -68,7 +70,7 @@ int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
return bytes;
}
-void print1byte(uint8_t input, struct iio_channel_info *info)
+static void print1byte(uint8_t input, struct iio_channel_info *info)
{
/*
* Shift before conversion to avoid sign extension
@@ -85,7 +87,7 @@ void print1byte(uint8_t input, struct iio_channel_info *info)
}
}
-void print2byte(uint16_t input, struct iio_channel_info *info)
+static void print2byte(uint16_t input, struct iio_channel_info *info)
{
/* First swap if incorrect endian */
if (info->be)
@@ -108,7 +110,7 @@ void print2byte(uint16_t input, struct iio_channel_info *info)
}
}
-void print4byte(uint32_t input, struct iio_channel_info *info)
+static void print4byte(uint32_t input, struct iio_channel_info *info)
{
/* First swap if incorrect endian */
if (info->be)
@@ -131,7 +133,7 @@ void print4byte(uint32_t input, struct iio_channel_info *info)
}
}
-void print8byte(uint64_t input, struct iio_channel_info *info)
+static void print8byte(uint64_t input, struct iio_channel_info *info)
{
/* First swap if incorrect endian */
if (info->be)
@@ -167,9 +169,8 @@ void print8byte(uint64_t input, struct iio_channel_info *info)
* to fill the location offsets.
* @num_channels: number of channels
**/
-void process_scan(char *data,
- struct iio_channel_info *channels,
- int num_channels)
+static void process_scan(char *data, struct iio_channel_info *channels,
+ int num_channels)
{
int k;
@@ -198,7 +199,7 @@ void process_scan(char *data,
printf("\n");
}
-static int enable_disable_all_channels(char *dev_dir_name, int enable)
+static int enable_disable_all_channels(char *dev_dir_name, int buffer_idx, int enable)
{
const struct dirent *ent;
char scanelemdir[256];
@@ -206,7 +207,7 @@ static int enable_disable_all_channels(char *dev_dir_name, int enable)
int ret;
snprintf(scanelemdir, sizeof(scanelemdir),
- FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name);
+ FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name, buffer_idx);
scanelemdir[sizeof(scanelemdir)-1] = '\0';
dp = opendir(scanelemdir);
@@ -238,12 +239,13 @@ static int enable_disable_all_channels(char *dev_dir_name, int enable)
return 0;
}
-void print_usage(void)
+static void print_usage(void)
{
fprintf(stderr, "Usage: generic_buffer [options]...\n"
"Capture, convert and output data from IIO device buffer\n"
" -a Auto-activate all available channels\n"
" -A Force-activate ALL channels\n"
+ " -b <n> The buffer which to open (by index), default 0\n"
" -c <n> Do n conversions, or loop forever if n < 0\n"
" -e Disable wait for event (new data)\n"
" -g Use trigger-less mode\n"
@@ -257,12 +259,13 @@ void print_usage(void)
" -w <n> Set delay between reads in us (event-less mode)\n");
}
-enum autochan autochannels = AUTOCHANNELS_DISABLED;
-char *dev_dir_name = NULL;
-char *buf_dir_name = NULL;
-bool current_trigger_set = false;
+static enum autochan autochannels = AUTOCHANNELS_DISABLED;
+static char *dev_dir_name = NULL;
+static char *buf_dir_name = NULL;
+static int buffer_idx = 0;
+static bool current_trigger_set = false;
-void cleanup(void)
+static void cleanup(void)
{
int ret;
@@ -287,21 +290,21 @@ void cleanup(void)
/* Disable channels if auto-enabled */
if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) {
- ret = enable_disable_all_channels(dev_dir_name, 0);
+ ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 0);
if (ret)
fprintf(stderr, "Failed to disable all channels\n");
autochannels = AUTOCHANNELS_DISABLED;
}
}
-void sig_handler(int signum)
+static void sig_handler(int signum)
{
fprintf(stderr, "Caught signal %d\n", signum);
cleanup();
exit(-signum);
}
-void register_cleanup(void)
+static void register_cleanup(void)
{
struct sigaction sa = { .sa_handler = sig_handler };
const int signums[] = { SIGINT, SIGTERM, SIGABRT };
@@ -334,7 +337,9 @@ int main(int argc, char **argv)
unsigned long long j;
unsigned long toread;
int ret, c;
- int fp = -1;
+ struct stat st;
+ int fd = -1;
+ int buf_fd = -1;
int num_channels = 0;
char *trigger_name = NULL, *device_name = NULL;
@@ -353,7 +358,7 @@ int main(int argc, char **argv)
register_cleanup();
- while ((c = getopt_long(argc, argv, "aAc:egl:n:N:t:T:w:?", longopts,
+ while ((c = getopt_long(argc, argv, "aAb:c:egl:n:N:t:T:w:?", longopts,
NULL)) != -1) {
switch (c) {
case 'a':
@@ -362,7 +367,20 @@ int main(int argc, char **argv)
case 'A':
autochannels = AUTOCHANNELS_ENABLED;
force_autochannels = true;
- break;
+ break;
+ case 'b':
+ errno = 0;
+ buffer_idx = strtoll(optarg, &dummy, 10);
+ if (errno) {
+ ret = -errno;
+ goto error;
+ }
+ if (buffer_idx < 0) {
+ ret = -ERANGE;
+ goto error;
+ }
+
+ break;
case 'c':
errno = 0;
num_loops = strtoll(optarg, &dummy, 10);
@@ -519,7 +537,7 @@ int main(int argc, char **argv)
* Parse the files in scan_elements to identify what channels are
* present
*/
- ret = build_channel_array(dev_dir_name, &channels, &num_channels);
+ ret = build_channel_array(dev_dir_name, buffer_idx, &channels, &num_channels);
if (ret) {
fprintf(stderr, "Problem reading scan element information\n"
"diag %s\n", dev_dir_name);
@@ -536,7 +554,7 @@ int main(int argc, char **argv)
(autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) {
fprintf(stderr, "Enabling all channels\n");
- ret = enable_disable_all_channels(dev_dir_name, 1);
+ ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 1);
if (ret) {
fprintf(stderr, "Failed to enable all channels\n");
goto error;
@@ -545,7 +563,7 @@ int main(int argc, char **argv)
/* This flags that we need to disable the channels again */
autochannels = AUTOCHANNELS_ACTIVE;
- ret = build_channel_array(dev_dir_name, &channels,
+ ret = build_channel_array(dev_dir_name, buffer_idx, &channels,
&num_channels);
if (ret) {
fprintf(stderr, "Problem reading scan element "
@@ -566,7 +584,7 @@ int main(int argc, char **argv)
fprintf(stderr, "Enable channels manually in "
FORMAT_SCAN_ELEMENTS_DIR
"/*_en or pass -a to autoenable channels and "
- "try again.\n", dev_dir_name);
+ "try again.\n", dev_dir_name, buffer_idx);
ret = -ENOENT;
goto error;
}
@@ -577,12 +595,25 @@ int main(int argc, char **argv)
* be built rather than found.
*/
ret = asprintf(&buf_dir_name,
- "%siio:device%d/buffer", iio_dir, dev_num);
+ "%siio:device%d/buffer%d", iio_dir, dev_num, buffer_idx);
if (ret < 0) {
ret = -ENOMEM;
goto error;
}
+ if (stat(buf_dir_name, &st)) {
+ fprintf(stderr, "Could not stat() '%s', got error %d: %s\n",
+ buf_dir_name, errno, strerror(errno));
+ ret = -errno;
+ goto error;
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ fprintf(stderr, "File '%s' is not a directory\n", buf_dir_name);
+ ret = -EFAULT;
+ goto error;
+ }
+
if (!notrigger) {
printf("%s %s\n", dev_dir_name, trigger_name);
/*
@@ -599,6 +630,35 @@ int main(int argc, char **argv)
}
}
+ ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num);
+ if (ret < 0) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* Attempt to open non blocking the access dev */
+ fd = open(buffer_access, O_RDONLY | O_NONBLOCK);
+ if (fd == -1) { /* TODO: If it isn't there make the node */
+ ret = -errno;
+ fprintf(stderr, "Failed to open %s\n", buffer_access);
+ goto error;
+ }
+
+ /* specify for which buffer index we want an FD */
+ buf_fd = buffer_idx;
+
+ ret = ioctl(fd, IIO_BUFFER_GET_FD_IOCTL, &buf_fd);
+ if (ret == -1 || buf_fd == -1) {
+ ret = -errno;
+ if (ret == -ENODEV || ret == -EINVAL)
+ fprintf(stderr,
+ "Device does not have this many buffers\n");
+ else
+ fprintf(stderr, "Failed to retrieve buffer fd\n");
+
+ goto error;
+ }
+
/* Setup ring buffer parameters */
ret = write_sysfs_int("length", buf_dir_name, buf_len);
if (ret < 0)
@@ -608,7 +668,8 @@ int main(int argc, char **argv)
ret = write_sysfs_int("enable", buf_dir_name, 1);
if (ret < 0) {
fprintf(stderr,
- "Failed to enable buffer: %s\n", strerror(-ret));
+ "Failed to enable buffer '%s': %s\n",
+ buf_dir_name, strerror(-ret));
goto error;
}
@@ -619,24 +680,30 @@ int main(int argc, char **argv)
goto error;
}
- ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num);
- if (ret < 0) {
- ret = -ENOMEM;
- goto error;
+ /**
+ * This check is being done here for sanity reasons, however it
+ * should be omitted under normal operation.
+ * If this is buffer0, we check that we get EBUSY after this point.
+ */
+ if (buffer_idx == 0) {
+ errno = 0;
+ read_size = read(fd, data, 1);
+ if (read_size > -1 || errno != EBUSY) {
+ ret = -EFAULT;
+ perror("Reading from '%s' should not be possible after ioctl()");
+ goto error;
+ }
}
- /* Attempt to open non blocking the access dev */
- fp = open(buffer_access, O_RDONLY | O_NONBLOCK);
- if (fp == -1) { /* TODO: If it isn't there make the node */
- ret = -errno;
- fprintf(stderr, "Failed to open %s\n", buffer_access);
- goto error;
- }
+ /* close now the main chardev FD and let the buffer FD work */
+ if (close(fd) == -1)
+ perror("Failed to close character device file");
+ fd = -1;
for (j = 0; j < num_loops || num_loops < 0; j++) {
if (!noevents) {
struct pollfd pfd = {
- .fd = fp,
+ .fd = buf_fd,
.events = POLLIN,
};
@@ -654,7 +721,7 @@ int main(int argc, char **argv)
toread = 64;
}
- read_size = read(fp, data, toread * scan_size);
+ read_size = read(buf_fd, data, toread * scan_size);
if (read_size < 0) {
if (errno == EAGAIN) {
fprintf(stderr, "nothing available\n");
@@ -671,7 +738,9 @@ int main(int argc, char **argv)
error:
cleanup();
- if (fp >= 0 && close(fp) == -1)
+ if (fd >= 0 && close(fd) == -1)
+ perror("Failed to close character device");
+ if (buf_fd >= 0 && close(buf_fd) == -1)
perror("Failed to close buffer");
free(buffer_access);
free(data);
diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c
index 7399eb7f1378..aadee6d34c74 100644
--- a/tools/iio/iio_utils.c
+++ b/tools/iio/iio_utils.c
@@ -77,15 +77,17 @@ int iioutils_break_up_name(const char *full_name, char **generic_name)
* @mask: output a bit mask for the raw data
* @be: output if data in big endian
* @device_dir: the IIO device directory
+ * @buffer_idx: the IIO buffer index
* @name: the channel name
* @generic_name: the channel type name
*
* Returns a value >= 0 on success, otherwise a negative error code.
**/
-int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
- unsigned *shift, uint64_t *mask, unsigned *be,
- const char *device_dir, const char *name,
- const char *generic_name)
+static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes,
+ unsigned int *bits_used, unsigned int *shift,
+ uint64_t *mask, unsigned int *be,
+ const char *device_dir, int buffer_idx,
+ const char *name, const char *generic_name)
{
FILE *sysfsfp;
int ret;
@@ -95,7 +97,7 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
unsigned padint;
const struct dirent *ent;
- ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
+ ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx);
if (ret < 0)
return -ENOMEM;
@@ -303,12 +305,13 @@ void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt)
/**
* build_channel_array() - function to figure out what channels are present
* @device_dir: the IIO device directory in sysfs
+ * @buffer_idx: the IIO buffer for this channel array
* @ci_array: output the resulting array of iio_channel_info
* @counter: output the amount of array elements
*
* Returns 0 on success, otherwise a negative error code.
**/
-int build_channel_array(const char *device_dir,
+int build_channel_array(const char *device_dir, int buffer_idx,
struct iio_channel_info **ci_array, int *counter)
{
DIR *dp;
@@ -321,7 +324,7 @@ int build_channel_array(const char *device_dir,
char *filename;
*counter = 0;
- ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
+ ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx);
if (ret < 0)
return -ENOMEM;
@@ -502,6 +505,7 @@ int build_channel_array(const char *device_dir,
&current->mask,
&current->be,
device_dir,
+ buffer_idx,
current->name,
current->generic_name);
if (ret < 0)
diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h
index 74bde4fde2c8..663c94a6c705 100644
--- a/tools/iio/iio_utils.h
+++ b/tools/iio/iio_utils.h
@@ -12,7 +12,8 @@
/* Made up value to limit allocation sizes */
#define IIO_MAX_NAME_LENGTH 64
-#define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements"
+#define FORMAT_SCAN_ELEMENTS_DIR "%s/buffer%d"
+#define FORMAT_EVENTS_DIR "%s/events"
#define FORMAT_TYPE_FILE "%s_type"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
@@ -57,15 +58,11 @@ static inline int iioutils_check_suffix(const char *str, const char *suffix)
}
int iioutils_break_up_name(const char *full_name, char **generic_name);
-int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
- unsigned *shift, uint64_t *mask, unsigned *be,
- const char *device_dir, const char *name,
- const char *generic_name);
int iioutils_get_param_float(float *output, const char *param_name,
const char *device_dir, const char *name,
const char *generic_name);
void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt);
-int build_channel_array(const char *device_dir,
+int build_channel_array(const char *device_dir, int buffer_idx,
struct iio_channel_info **ci_array, int *counter);
int find_type_by_name(const char *name, const char *type);
int write_sysfs_int(const char *filename, const char *basedir, int val);