mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 15:03:53 +02:00
IIO: 1st set of new device support, features and cleanup for 6.14
Fairly quiet cycle. Usual mix of new drivers, device support in existing drivers, features and more general rework and cleanup. There are a few late breaking or long standing but complex fixes in here as well. There is one expected merge conflict due to an upstream fix touching neighboring code in ti-ads1119. The trivial resolution is the right one with the result ending up as: struct { s16 sample; aligned_s64 timestamp; } scan; New device support ================== adi,ad4000 - Add support for many Pulsar ADC devices: AD7685, AD7686, AD7687, AD7688, AD7690, AD7691, AD7693, AD7942, AD7946, AD7980, AD7982, AD7983, AD7984, AD7988-1 and AD7988-5 ADCs. Generally similar to the AD4000 series but with lower sampling rates and no configuration registers. Includes addition of timestamp channels. adi,adis16480 - Add support for ADIS16486, ADIS16487 and ADIS16489 IMUs. Required a few tweaks to existing driver and addition of tables. kionix,kx022a - Add support for KX134ACR-LBZ accelerometer that is similar to the KX132ACR-LBZ but with a wider (+-64G) sensor range. - Add support for KX134-1211 accelerometer that is similar to the KX132-1211 but with a wider (+-16G) sensor range. nxp,fxls8962af - Add support for fxls8974cf and fxls8967af accelerometers, Both are compatible with fxls8962af but with different device IDs which are used in presence checks. renesas,rzg2l - Add support for Renesas RZ/GS3 SoC ADCs (various driver refactors precede this to allow for chip differences). rohm,bd79704 - New driver for this 6 channel DAC. st,mpu6050 - Support he IAM20380 which is effectively a cut down IAM20608 IMU with only a gyroscope (no accelerometer). st,stm-timmer-trigger - Add support for ADC trigger use case for the STM32MP25 SOC. Do not support the counter functionality in this driver as that is handled by the counter subsystem. ti,opt4060 - New driver for this RGBW color sensor. Driver drop =========== rohm,bu20008 - Drop as decision was made to not mass produce this light sensor after Matti had done all the work to get a driver upstream. Features ======== adi,ad_sigma_delta library + ad7124 - Allow for GPIO to check interrupt status, enabling this device on more platforms that don't obey prior (non general) assumptions on how the interrupt chips work. - Allow variation in reset sequence length allowing chip specific optimizations rather than always using worst case. adi,ad7124 - Add temperature channel support. adi,ad7173 - Add support calibration modes for this family of ADCs. adi,adxl345 - Binding update to allow specification of which interrupt line is connected (or none). - Support interrupts and FIFO based data capture. bosch,bme680 - Add regulators support. Note this required a new binding doc rather than use of trivial-devices - Runtime PM support. microchip,pac1921 - Add ACPI support including _DSM for shunt value and label. renesas,rzg2l - Enable runtime autosuspend. - Add suspend and resume support. tyhx,hx9023s - Add loading of a firmware file used to set defaults for some configuration registers. vishay,veml6030 - Support triggered buffers allowing efficient data capture at higher speeds. - Add regmap cache to reduce access to device. Cleanup and minor fixes ======================= cross-tree - Another batch of conversions to devm_regulator_get_enable_read_voltage() helper and related conversions to full devm that this enables. - Various patches using guard() to allow early returns and simpler code flow. - Various conversions from s64 timestamp __aligned(8) to aligned_s64 type. Includes a few cleanups where this unsigned and it should have been signed. - Fix up some missing types for drive-open-drain in dt-binding docs. core - Add missing documentation for iio_dmaengine_buffer_setup_ext() - Add check that all buffers passed to iio_read_channel_ext_info() and iio_read_channel_label() are page sized and page aligned. Done this way because the callbacks are almost always only used to fill sysfs attributes. The check covers the tiny percentage of cases where use is made of this data in a consumer driver. - Mark scan_timestamp memory of struct iio_dev private ensuring no drivers change the value which belongs to the IIO core. documentation - Various missing ABI docs added. - ABI docs made to use Y consistently as the wildcard for channel number. - Combine duplicate in_currentY_raw entries in ABI docs. iio-mux - Fix alignment of buffers passed to iio_channel_read_ext_info(). adi,ad_sigma_delta library - Respect keep_cs_asserted flag in read path. - Close a race condition around irq enabling and disabling. - Use explicit unsigned int in place of unsigned. adi,ad6695 - Move dt-binding header under adc sub-directory and fix include path in dt example. adi,ad7124 - Check number of channels in DT doesn't exceed what the driver can handle. - Check input specified in DT are possible. - Improved error reporting during probe. adi,ad7173 - Drop unused structure element. adi,ad7293 - Ensure power is turned on before resetting. adi,adxl345 - Some documentation simplification and parameter renames. - Add a function than unifies handling of power up and power down. - Add defines to have a complete set of registers defined. - Add missing \n to end of error messages. amlogic,meson_saradc - Simplify handling of the REG11 register access. awinic,aw96104 - Constify iio_info structure. bosch,bmp085 - Add to dt-binding to indicate devices support SPI. bosch,bmp280 - Use sizeof() to replace a somewhat magic 2. - Rename sleep related variables so the unit is included and use fsleep() to replace usleep_range() calls. bosch,bno055 - Constify struct bin_attribute capella,cm3232 - Reset device before checking hardware ID inline with suggested flow from datasheet. diolan,dln2 - Simplify zeroing of structure used to gather up data by just clearing the whole thing before writing rather than trying to clear out he padding after write. freescale,vf610 - Use devm_ and dev_error_probe() to simplify code and allow dropping of explicit remove() callback. invensense,timestamp library - Use a cast to remove possibility of integer overflow. kionix,kx022a - Increase reset delay a little. maxim,max1363 - Use a buffer of sufficient size in iio_priv() rather than allocating variable sized buffer at use time. microchip,mcp4725 - Replace of_property_read_bool() with of_property_present() for detecting presence of regulator which is obviously not a bool. nxp,fxls8962af - Add wakeup-source property to the dt binding to allow these sensors to wake the system up from suspend. - Enable finer grained build when not all bus types need to be supported. renesas,rzg2l - Use dev_err_probe(), improving handling of probe errors and simplifying code. - Convert to devm_ based cleanup. - Remove unnecessary runtime PM complexity as clocks are managed through PM domains. - Switch pm_ptr() removing need for __maybe_unused markings. - use read_poll_timeout() to replace open coded equivalent. samsung, ssp_sensors - Simplify code by always providing timestamp whether or not it is enabled. st,lsm6dsx - Avoid need to include linux/i3c/master by using i3cdev_to_dev() to get to the contained struct device. st,stm32-timer-trigger - Check for clk_enable() fails. vishay,veml6030 - Use new gts-helper functions and fix the _scale attribute to take into account changes in gain and integration time. Various other typo fixes in variable names + documentation and help text. A few whitespace cleanup patches. -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAmeCb2kRHGppYzIzQGtl cm5lbC5vcmcACgkQVIU0mcT0Foi3UA//e3HT75qbJbqtsSyVDCuYqCovWlb1HsBZ qsROx+56cQG+x0fTaJ1XfESQ9agRrm2+tVRPLrKGnwhp9Lz9b2ZcW+Je2h0rZi+l nwxdGNuv0wpatsZwmrF46ELcwaf0PSwpuTTbM9qXFiHSoulZ5wbDebelSJNGkdok vO4a6K5L4DcuiJ7uuEp9pgGC4k/jGZMGTUBTBGH8ViRC3A0fMcc1ZWKFH5mz6ZWM +1f+cfy09QORPcfSAqRE9j5md3OkmBcG9F8qux73raJfLQQTMWADDTh6rZS5bvqM 4jueqlkIKOee9twlEzux7OZD/oZa+ppmZwuHEbv7M+nGWMFqEkRC6OKkSCKUrTFX do+gdJxsUNMirz6w+ZJ2oAo+jEbwvV7/BkpZ/C3ZeQKH4XPytboo4QYvIU9JXxEr JmcOfheaYqcNIM/CavJSAZmZCKZ+fx0nUkHu2C5KXezb6/qUJFxWO83gWKDmlgJv X+MewmYtBPSeGQSMOLoVIH+59Z3d/Fiz0O4ByfMY5yNhzqqaC5Ro9bEarcxeUUVS OAn8XXuX0IJ2pbWjp72E4Bu1VGjtsyYf4FIkFwt7179TTxUZ7qulHHviojj9AdWe VHlXuWKwwEZDdLbkLDOulLVc9OtCai7mQvjHHKqpZuLfOeQokkiP9cW5ojGChOGz KNnvygVhb3Q= =IRr2 -----END PGP SIGNATURE----- Merge tag 'iio-for-6.14a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next Pull IIO updaate from Jonathan: IIO: 1st set of new device support, features and cleanup for 6.14 Fairly quiet cycle. Usual mix of new drivers, device support in existing drivers, features and more general rework and cleanup. There are a few late breaking or long standing but complex fixes in here as well. There is one expected merge conflict due to an upstream fix touching neighboring code in ti-ads1119. The trivial resolution is the right one with the result ending up as: struct { s16 sample; aligned_s64 timestamp; } scan; New device support ================== adi,ad4000 - Add support for many Pulsar ADC devices: AD7685, AD7686, AD7687, AD7688, AD7690, AD7691, AD7693, AD7942, AD7946, AD7980, AD7982, AD7983, AD7984, AD7988-1 and AD7988-5 ADCs. Generally similar to the AD4000 series but with lower sampling rates and no configuration registers. Includes addition of timestamp channels. adi,adis16480 - Add support for ADIS16486, ADIS16487 and ADIS16489 IMUs. Required a few tweaks to existing driver and addition of tables. kionix,kx022a - Add support for KX134ACR-LBZ accelerometer that is similar to the KX132ACR-LBZ but with a wider (+-64G) sensor range. - Add support for KX134-1211 accelerometer that is similar to the KX132-1211 but with a wider (+-16G) sensor range. nxp,fxls8962af - Add support for fxls8974cf and fxls8967af accelerometers, Both are compatible with fxls8962af but with different device IDs which are used in presence checks. renesas,rzg2l - Add support for Renesas RZ/GS3 SoC ADCs (various driver refactors precede this to allow for chip differences). rohm,bd79704 - New driver for this 6 channel DAC. st,mpu6050 - Support he IAM20380 which is effectively a cut down IAM20608 IMU with only a gyroscope (no accelerometer). st,stm-timmer-trigger - Add support for ADC trigger use case for the STM32MP25 SOC. Do not support the counter functionality in this driver as that is handled by the counter subsystem. ti,opt4060 - New driver for this RGBW color sensor. Driver drop =========== rohm,bu20008 - Drop as decision was made to not mass produce this light sensor after Matti had done all the work to get a driver upstream. Features ======== adi,ad_sigma_delta library + ad7124 - Allow for GPIO to check interrupt status, enabling this device on more platforms that don't obey prior (non general) assumptions on how the interrupt chips work. - Allow variation in reset sequence length allowing chip specific optimizations rather than always using worst case. adi,ad7124 - Add temperature channel support. adi,ad7173 - Add support calibration modes for this family of ADCs. adi,adxl345 - Binding update to allow specification of which interrupt line is connected (or none). - Support interrupts and FIFO based data capture. bosch,bme680 - Add regulators support. Note this required a new binding doc rather than use of trivial-devices - Runtime PM support. microchip,pac1921 - Add ACPI support including _DSM for shunt value and label. renesas,rzg2l - Enable runtime autosuspend. - Add suspend and resume support. tyhx,hx9023s - Add loading of a firmware file used to set defaults for some configuration registers. vishay,veml6030 - Support triggered buffers allowing efficient data capture at higher speeds. - Add regmap cache to reduce access to device. Cleanup and minor fixes ======================= cross-tree - Another batch of conversions to devm_regulator_get_enable_read_voltage() helper and related conversions to full devm that this enables. - Various patches using guard() to allow early returns and simpler code flow. - Various conversions from s64 timestamp __aligned(8) to aligned_s64 type. Includes a few cleanups where this unsigned and it should have been signed. - Fix up some missing types for drive-open-drain in dt-binding docs. core - Add missing documentation for iio_dmaengine_buffer_setup_ext() - Add check that all buffers passed to iio_read_channel_ext_info() and iio_read_channel_label() are page sized and page aligned. Done this way because the callbacks are almost always only used to fill sysfs attributes. The check covers the tiny percentage of cases where use is made of this data in a consumer driver. - Mark scan_timestamp memory of struct iio_dev private ensuring no drivers change the value which belongs to the IIO core. documentation - Various missing ABI docs added. - ABI docs made to use Y consistently as the wildcard for channel number. - Combine duplicate in_currentY_raw entries in ABI docs. iio-mux - Fix alignment of buffers passed to iio_channel_read_ext_info(). adi,ad_sigma_delta library - Respect keep_cs_asserted flag in read path. - Close a race condition around irq enabling and disabling. - Use explicit unsigned int in place of unsigned. adi,ad6695 - Move dt-binding header under adc sub-directory and fix include path in dt example. adi,ad7124 - Check number of channels in DT doesn't exceed what the driver can handle. - Check input specified in DT are possible. - Improved error reporting during probe. adi,ad7173 - Drop unused structure element. adi,ad7293 - Ensure power is turned on before resetting. adi,adxl345 - Some documentation simplification and parameter renames. - Add a function than unifies handling of power up and power down. - Add defines to have a complete set of registers defined. - Add missing \n to end of error messages. amlogic,meson_saradc - Simplify handling of the REG11 register access. awinic,aw96104 - Constify iio_info structure. bosch,bmp085 - Add to dt-binding to indicate devices support SPI. bosch,bmp280 - Use sizeof() to replace a somewhat magic 2. - Rename sleep related variables so the unit is included and use fsleep() to replace usleep_range() calls. bosch,bno055 - Constify struct bin_attribute capella,cm3232 - Reset device before checking hardware ID inline with suggested flow from datasheet. diolan,dln2 - Simplify zeroing of structure used to gather up data by just clearing the whole thing before writing rather than trying to clear out he padding after write. freescale,vf610 - Use devm_ and dev_error_probe() to simplify code and allow dropping of explicit remove() callback. invensense,timestamp library - Use a cast to remove possibility of integer overflow. kionix,kx022a - Increase reset delay a little. maxim,max1363 - Use a buffer of sufficient size in iio_priv() rather than allocating variable sized buffer at use time. microchip,mcp4725 - Replace of_property_read_bool() with of_property_present() for detecting presence of regulator which is obviously not a bool. nxp,fxls8962af - Add wakeup-source property to the dt binding to allow these sensors to wake the system up from suspend. - Enable finer grained build when not all bus types need to be supported. renesas,rzg2l - Use dev_err_probe(), improving handling of probe errors and simplifying code. - Convert to devm_ based cleanup. - Remove unnecessary runtime PM complexity as clocks are managed through PM domains. - Switch pm_ptr() removing need for __maybe_unused markings. - use read_poll_timeout() to replace open coded equivalent. samsung, ssp_sensors - Simplify code by always providing timestamp whether or not it is enabled. st,lsm6dsx - Avoid need to include linux/i3c/master by using i3cdev_to_dev() to get to the contained struct device. st,stm32-timer-trigger - Check for clk_enable() fails. vishay,veml6030 - Use new gts-helper functions and fix the _scale attribute to take into account changes in gain and integration time. Various other typo fixes in variable names + documentation and help text. A few whitespace cleanup patches. * tag 'iio-for-6.14a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (142 commits) iio: iio-mux: kzalloc instead of devm_kzalloc to ensure page alignment iio: adc: ad7625: Add ending newlines to error messages iio: accel: adxl345: complete the list of defines iio: accel: adxl345: add FIFO with watermark events iio: accel: adxl345: initialize FIFO delay value for SPI iio: accel: adxl345: introduce interrupt handling iio: light: veml3235: fix scale to conform to ABI iio: gts-helper: add helpers to ease searches of gain_sel and new_gain iio: light: veml3235: extend regmap to add cache iio: light: veml3235: fix code style dt-bindings: iio: accel: adxl345: add interrupt-names dt-bindings: iio: accel: adxl345: make interrupts not a required property dt-bindings: iio: imu: bmi323: add boolean type for drive-open-drain dt-bindings: iio: imu: bmi270: add boolean type for drive-open-drain dt-bindings: iio: imu: bmi160: add boolean type for drive-open-drain iio: adc: meson: simplify MESON_SAR_ADC_REG11 register access iio: adc: meson: use tabs instead of spaces for some REG11 bit fields iio: adc: meson: fix voltage reference selection field name typo iio: adc: rockchip: correct alignment of timestamp iio: imu: inv_icm42600: switch timestamp type from int64_t __aligned(8) to aligned_s64 ...
This commit is contained in:
commit
6d699ca165
|
@ -168,18 +168,6 @@ Description:
|
|||
is required is a consistent labeling. Units after application
|
||||
of scale and offset are millivolts.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_raw
|
||||
KernelVersion: 3.17
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Raw (unscaled no bias removal etc.) current measurement from
|
||||
channel Y. In special cases where the channel does not
|
||||
correspond to externally available input one of the named
|
||||
versions may be used. The number must always be specified and
|
||||
unique to allow association with event codes. Units after
|
||||
application of scale and offset are milliamps.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_powerY_raw
|
||||
KernelVersion: 4.5
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
|
@ -227,7 +215,7 @@ Description:
|
|||
same scaling as _raw.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_tempX_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_tempY_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_x_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_y_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_ambient_raw
|
||||
|
@ -416,11 +404,11 @@ Contact: linux-iio@vger.kernel.org
|
|||
Description:
|
||||
Scaled humidity measurement in milli percent.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_X_mean_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_Y_mean_raw
|
||||
KernelVersion: 3.5
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Averaged raw measurement from channel X. The number of values
|
||||
Averaged raw measurement from channel Y. The number of values
|
||||
used for averaging is device specific. The converting rules for
|
||||
normal raw values also applies to the averaged raw values.
|
||||
|
||||
|
@ -448,7 +436,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_magn_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_rot_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_angl_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceX_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceY_offset
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -508,6 +496,9 @@ What: /sys/bus/iio/devices/iio:deviceX/in_angl_scale
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_x_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_y_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_z_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_red_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_scale
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
|
@ -660,10 +651,10 @@ What: /sys/.../iio:deviceX/in_magn_scale_available
|
|||
What: /sys/.../iio:deviceX/in_illuminance_scale_available
|
||||
What: /sys/.../iio:deviceX/in_intensity_scale_available
|
||||
What: /sys/.../iio:deviceX/in_proximity_scale_available
|
||||
What: /sys/.../iio:deviceX/in_voltageX_scale_available
|
||||
What: /sys/.../iio:deviceX/in_voltageY_scale_available
|
||||
What: /sys/.../iio:deviceX/in_voltage-voltage_scale_available
|
||||
What: /sys/.../iio:deviceX/out_voltageX_scale_available
|
||||
What: /sys/.../iio:deviceX/out_altvoltageX_scale_available
|
||||
What: /sys/.../iio:deviceX/out_voltageY_scale_available
|
||||
What: /sys/.../iio:deviceX/out_altvoltageY_scale_available
|
||||
What: /sys/.../iio:deviceX/in_capacitance_scale_available
|
||||
What: /sys/.../iio:deviceX/in_pressure_scale_available
|
||||
What: /sys/.../iio:deviceX/in_pressureY_scale_available
|
||||
|
@ -681,6 +672,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_intensity_red_hardwaregain
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_hardwaregain
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_hardwaregain
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_clear_hardwaregain
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_hardwaregain
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -1562,7 +1554,7 @@ Description:
|
|||
This attribute is used to read the amount of quadrature error
|
||||
present in the device at a given time.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_accelX_power_mode
|
||||
What: /sys/.../iio:deviceX/in_accelY_power_mode
|
||||
KernelVersion: 3.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -1633,6 +1625,10 @@ What: /sys/.../iio:deviceX/in_intensityY_uv_raw
|
|||
What: /sys/.../iio:deviceX/in_intensityY_uva_raw
|
||||
What: /sys/.../iio:deviceX/in_intensityY_uvb_raw
|
||||
What: /sys/.../iio:deviceX/in_intensityY_duv_raw
|
||||
What: /sys/.../iio:deviceX/in_intensity_red_raw
|
||||
What: /sys/.../iio:deviceX/in_intensity_green_raw
|
||||
What: /sys/.../iio:deviceX/in_intensity_blue_raw
|
||||
What: /sys/.../iio:deviceX/in_intensity_clear_raw
|
||||
KernelVersion: 3.4
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -1691,16 +1687,19 @@ Description:
|
|||
Raw value of rotation from true/magnetic north measured with
|
||||
or without compensation from tilt sensors.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentX_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentX_i_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentX_q_raw
|
||||
KernelVersion: 3.18
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_raw
|
||||
KernelVersion: 3.17
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Raw current measurement from channel X. Units are in milliamps
|
||||
Raw current measurement from channel Y. Units are in milliamps
|
||||
after application of scale and offset. If no offset or scale is
|
||||
present, output should be considered as processed with the
|
||||
unit in milliamps.
|
||||
unit in milliamps. In special cases where the channel does not
|
||||
correspond to externally available input one of the named
|
||||
versions may be used.
|
||||
|
||||
Channels with 'i' and 'q' modifiers always exist in pairs and both
|
||||
channels refer to the same signal. The 'i' channel contains the in-phase
|
||||
|
@ -1864,9 +1863,9 @@ Description:
|
|||
hardware fifo watermark level.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_calibemissivity
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_tempX_calibemissivity
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_tempY_calibemissivity
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_object_calibemissivity
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_tempX_object_calibemissivity
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_tempY_object_calibemissivity
|
||||
KernelVersion: 4.1
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -1887,17 +1886,17 @@ Description:
|
|||
is considered as one sample for <type>[_name]_sampling_frequency.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_co2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_co2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_ethanol_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_ethanol_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_ethanol_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_h2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_h2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_h2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_o2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_o2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_o2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_voc_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_voc_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationY_voc_raw
|
||||
KernelVersion: 4.3
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -1905,9 +1904,9 @@ Description:
|
|||
after application of scale and offset are percents.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_resistance_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_resistanceX_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_resistanceY_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_resistance_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_resistanceX_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_resistanceY_raw
|
||||
KernelVersion: 4.3
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -2096,7 +2095,7 @@ Description:
|
|||
One of the following thermocouple types: B, E, J, K, N, R, S, T.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_object_calibambient
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_tempX_object_calibambient
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_tempY_object_calibambient
|
||||
KernelVersion: 5.10
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -2172,9 +2171,9 @@ Description:
|
|||
|
||||
- a range specified as "[min step max]"
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageX_sampling_frequency
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sampling_frequency
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_powerY_sampling_frequency
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentZ_sampling_frequency
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_sampling_frequency
|
||||
KernelVersion: 5.20
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
|
23
Documentation/ABI/testing/sysfs-bus-iio-adc-ad-sigma-delta
Normal file
23
Documentation/ABI/testing/sysfs-bus-iio-adc-ad-sigma-delta
Normal file
|
@ -0,0 +1,23 @@
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sys_calibration
|
||||
KernelVersion: 5.5
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This attribute, if available, initiates the system calibration procedure. This is done on a
|
||||
single channel at a time. Write '1' to start the calibration.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sys_calibration_mode_available
|
||||
KernelVersion: 5.5
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This attribute, if available, returns a list with the possible calibration modes.
|
||||
There are two available options:
|
||||
"zero_scale" - calibrate to zero scale
|
||||
"full_scale" - calibrate to full scale
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sys_calibration_mode
|
||||
KernelVersion: 5.5
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This attribute, if available, sets up the calibration mode used in the system calibration
|
||||
procedure. Reading returns the current calibration mode.
|
||||
Writing sets the system calibration mode.
|
|
@ -19,33 +19,9 @@ Description:
|
|||
the bridge can be disconnected (when it is not being used
|
||||
using the bridge_switch_en attribute.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration
|
||||
KernelVersion:
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Initiates the system calibration procedure. This is done on a
|
||||
single channel at a time. Write '1' to start the calibration.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage2-voltage2_shorted_raw
|
||||
KernelVersion:
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Measure voltage from AIN2 pin connected to AIN(+)
|
||||
and AIN(-) shorted.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration_mode_available
|
||||
KernelVersion:
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Reading returns a list with the possible calibration modes.
|
||||
There are two available options:
|
||||
"zero_scale" - calibrate to zero scale
|
||||
"full_scale" - calibrate to full scale
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration_mode
|
||||
KernelVersion:
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Sets up the calibration mode used in the system calibration
|
||||
procedure. Reading returns the current calibration mode.
|
||||
Writing sets the system calibration mode.
|
||||
|
|
|
@ -37,10 +37,17 @@ properties:
|
|||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- enum: [INT1, INT2]
|
||||
|
||||
dependencies:
|
||||
interrupts: [ interrupt-names ]
|
||||
interrupt-names: [ interrupts ]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
@ -61,6 +68,7 @@ examples:
|
|||
reg = <0x2a>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "INT1";
|
||||
};
|
||||
};
|
||||
- |
|
||||
|
@ -79,5 +87,6 @@ examples:
|
|||
spi-cpha;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "INT2";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -4,23 +4,26 @@
|
|||
$id: http://devicetree.org/schemas/iio/accel/kionix,kx022a.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ROHM/Kionix KX022A, KX132-1211 and KX132ACR-LBZ Accelerometers
|
||||
title: ROHM/Kionix KX022A, KX132/134-1211 and KX132/134ACR-LBZ Accelerometers
|
||||
|
||||
maintainers:
|
||||
- Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
|
||||
description: |
|
||||
KX022A, KX132ACR-LBZ and KX132-1211 are 3-axis accelerometers supporting
|
||||
+/- 2G, 4G, 8G and 16G ranges, variable output data-rates and a
|
||||
hardware-fifo buffering. These accelerometers can be accessed either
|
||||
via I2C or SPI.
|
||||
+/- 2G, 4G, 8G and 16G ranges. The KX134ACR-LBZ and KX134-1211 support
|
||||
+/- 8G, 16G, 32G and 64G. All the sensors also have variable output
|
||||
data-rates and a hardware-fifo buffering. These accelerometers can be
|
||||
accessed either via I2C or SPI.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- kionix,kx022a
|
||||
- kionix,kx132-1211
|
||||
- kionix,kx134-1211
|
||||
- rohm,kx132acr-lbz
|
||||
- rohm,kx134acr-lbz
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
@ -14,12 +14,20 @@ description: |
|
|||
SPI and I2C interface.
|
||||
https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf
|
||||
https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf
|
||||
https://www.nxp.com/docs/en/data-sheet/FXLS8967AF.pdf
|
||||
https://www.nxp.com/docs/en/data-sheet/FXLS8974CF.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- nxp,fxls8962af
|
||||
- nxp,fxls8964af
|
||||
oneOf:
|
||||
- enum:
|
||||
- nxp,fxls8962af
|
||||
- nxp,fxls8964af
|
||||
- items:
|
||||
- enum:
|
||||
- nxp,fxls8967af
|
||||
- nxp,fxls8974cf
|
||||
- const: nxp,fxls8962af
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -38,6 +46,11 @@ properties:
|
|||
drive-open-drain:
|
||||
type: boolean
|
||||
|
||||
wakeup-source:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Enable wake on accelerometer event
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -61,6 +74,7 @@ examples:
|
|||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "INT1";
|
||||
wakeup-source;
|
||||
};
|
||||
};
|
||||
- |
|
||||
|
|
|
@ -19,49 +19,82 @@ description: |
|
|||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4020-4021-4022.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4001.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4003.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7685.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7686.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7687.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7688.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7690.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7691.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7693.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7942.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7946.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7980.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7982.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7983.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7984.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7988-1_7988-5.pdf
|
||||
|
||||
$ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: adi,ad4000
|
||||
- enum:
|
||||
- adi,ad4000
|
||||
- adi,ad4001
|
||||
- adi,ad4002
|
||||
- adi,ad4003
|
||||
- adi,ad4020
|
||||
- adi,adaq4001
|
||||
- adi,adaq4003
|
||||
- adi,ad7687
|
||||
- adi,ad7691
|
||||
- adi,ad7942
|
||||
- adi,ad7946
|
||||
- adi,ad7983
|
||||
- items:
|
||||
- enum:
|
||||
- adi,ad4004
|
||||
- adi,ad4008
|
||||
- const: adi,ad4000
|
||||
|
||||
- const: adi,ad4001
|
||||
- items:
|
||||
- enum:
|
||||
- adi,ad4005
|
||||
- const: adi,ad4001
|
||||
|
||||
- const: adi,ad4002
|
||||
- items:
|
||||
- enum:
|
||||
- adi,ad4006
|
||||
- adi,ad4010
|
||||
- const: adi,ad4002
|
||||
|
||||
- const: adi,ad4003
|
||||
- items:
|
||||
- enum:
|
||||
- adi,ad4007
|
||||
- adi,ad4011
|
||||
- const: adi,ad4003
|
||||
|
||||
- const: adi,ad4020
|
||||
- items:
|
||||
- enum:
|
||||
- adi,ad4021
|
||||
- adi,ad4022
|
||||
- const: adi,ad4020
|
||||
|
||||
- const: adi,adaq4001
|
||||
|
||||
- const: adi,adaq4003
|
||||
- items:
|
||||
- enum:
|
||||
- adi,ad7685
|
||||
- adi,ad7686
|
||||
- adi,ad7980
|
||||
- adi,ad7988-1
|
||||
- adi,ad7988-5
|
||||
- const: adi,ad7983
|
||||
- items:
|
||||
- enum:
|
||||
- adi,ad7688
|
||||
- adi,ad7693
|
||||
- const: adi,ad7687
|
||||
- items:
|
||||
- enum:
|
||||
- adi,ad7690
|
||||
- adi,ad7982
|
||||
- adi,ad7984
|
||||
- const: adi,ad7691
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -133,6 +166,22 @@ required:
|
|||
- ref-supply
|
||||
|
||||
allOf:
|
||||
# Single-channel PulSAR devices have SDI either tied to VIO, GND, or host CS.
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad7687
|
||||
- adi,ad7691
|
||||
- adi,ad7942
|
||||
- adi,ad7946
|
||||
- adi,ad7983
|
||||
then:
|
||||
properties:
|
||||
adi,sdi-pin:
|
||||
enum: [ high, low, cs ]
|
||||
default: cs
|
||||
# The configuration register can only be accessed if SDI is connected to MOSI
|
||||
- if:
|
||||
required:
|
||||
|
|
|
@ -134,8 +134,9 @@ patternProperties:
|
|||
description:
|
||||
Describes the common mode channel for single channels. 0xFF is REFGND
|
||||
and OxFE is COM. Macros are available for these values in
|
||||
dt-bindings/iio/adi,ad4695.h. Values 1 to 15 correspond to INx inputs.
|
||||
Only odd numbered INx inputs can be used as common mode channels.
|
||||
dt-bindings/iio/adc/adi,ad4695.h. Values 1 to 15 correspond to INx
|
||||
inputs. Only odd numbered INx inputs can be used as common mode
|
||||
channels.
|
||||
enum: [1, 3, 5, 7, 9, 11, 13, 15, 0xFE, 0xFF]
|
||||
default: 0xFF
|
||||
|
||||
|
@ -209,7 +210,7 @@ unevaluatedProperties: false
|
|||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/iio/adi,ad4695.h>
|
||||
#include <dt-bindings/iio/adc/adi,ad4695.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
|
|
|
@ -37,6 +37,17 @@ properties:
|
|||
description: IRQ line for the ADC
|
||||
maxItems: 1
|
||||
|
||||
rdy-gpios:
|
||||
description:
|
||||
GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but
|
||||
highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its
|
||||
DOUT aka MISO role) and so usually triggers a spurious interrupt. The
|
||||
distinction between such a spurious event and a real one can only be done
|
||||
by reading such a GPIO. (There is a register telling the same
|
||||
information, but accessing that one needs a SPI transfer which then
|
||||
triggers another interrupt event.)
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
|
@ -111,6 +122,7 @@ unevaluatedProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
@ -121,6 +133,7 @@ examples:
|
|||
spi-max-frequency = <5000000>;
|
||||
interrupts = <25 2>;
|
||||
interrupt-parent = <&gpio>;
|
||||
rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
|
||||
refin1-supply = <&adc_vref>;
|
||||
clocks = <&ad7124_mclk>;
|
||||
clock-names = "mclk";
|
||||
|
|
|
@ -135,6 +135,17 @@ properties:
|
|||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
rdy-gpios:
|
||||
description:
|
||||
GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but
|
||||
highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its
|
||||
DOUT aka MISO role) and so usually triggers a spurious interrupt. The
|
||||
distinction between such a spurious event and a real one can only be done
|
||||
by reading such a GPIO. (There is a register telling the same
|
||||
information, but accessing that one needs a SPI transfer which then
|
||||
triggers another interrupt event.)
|
||||
maxItems: 1
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-9a-f]$":
|
||||
type: object
|
||||
|
@ -443,6 +454,7 @@ examples:
|
|||
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-names = "rdy";
|
||||
interrupt-parent = <&gpio>;
|
||||
rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
|
||||
spi-max-frequency = <5000000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
|
|
@ -106,6 +106,17 @@ properties:
|
|||
description: see Documentation/devicetree/bindings/iio/adc/adc.yaml
|
||||
type: boolean
|
||||
|
||||
rdy-gpios:
|
||||
description:
|
||||
GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but
|
||||
highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its
|
||||
DOUT aka MISO role) and so usually triggers a spurious interrupt. The
|
||||
distinction between such a spurious event and a real one can only be done
|
||||
by reading such a GPIO. (There is a register telling the same
|
||||
information, but accessing that one needs a SPI transfer which then
|
||||
triggers another interrupt event.)
|
||||
maxItems: 1
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-9a-f]+$":
|
||||
type: object
|
||||
|
@ -181,6 +192,7 @@ unevaluatedProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
@ -195,6 +207,7 @@ examples:
|
|||
clock-names = "mclk";
|
||||
interrupts = <25 0x2>;
|
||||
interrupt-parent = <&gpio>;
|
||||
rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
|
||||
aincom-supply = <&aincom>;
|
||||
dvdd-supply = <&dvdd>;
|
||||
avdd-supply = <&avdd>;
|
||||
|
@ -207,6 +220,7 @@ examples:
|
|||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
@ -224,6 +238,7 @@ examples:
|
|||
#clock-cells = <0>;
|
||||
interrupts = <25 0x2>;
|
||||
interrupt-parent = <&gpio>;
|
||||
rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
|
||||
aincom-supply = <&aincom>;
|
||||
dvdd-supply = <&dvdd>;
|
||||
avdd-supply = <&avdd>;
|
||||
|
|
|
@ -63,6 +63,17 @@ properties:
|
|||
marked GPIO_ACTIVE_LOW.
|
||||
maxItems: 1
|
||||
|
||||
rdy-gpios:
|
||||
description:
|
||||
GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but
|
||||
highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its
|
||||
DOUT aka MISO role) and so usually triggers a spurious interrupt. The
|
||||
distinction between such a spurious event and a real one can only be done
|
||||
by reading such a GPIO. (There is a register telling the same
|
||||
information, but accessing that one needs a SPI transfer which then
|
||||
triggers another interrupt event.)
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
@ -17,12 +17,15 @@ description: |
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r9a07g043-adc # RZ/G2UL and RZ/Five
|
||||
- renesas,r9a07g044-adc # RZ/G2L
|
||||
- renesas,r9a07g054-adc # RZ/V2L
|
||||
- const: renesas,rzg2l-adc
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,r9a07g043-adc # RZ/G2UL and RZ/Five
|
||||
- renesas,r9a07g044-adc # RZ/G2L
|
||||
- renesas,r9a07g054-adc # RZ/V2L
|
||||
- const: renesas,rzg2l-adc
|
||||
- items:
|
||||
- const: renesas,r9a08g045-adc # RZ/G3S
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -57,6 +60,9 @@ properties:
|
|||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -68,7 +74,7 @@ required:
|
|||
- reset-names
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-7]$":
|
||||
"^channel@[0-8]$":
|
||||
$ref: adc.yaml
|
||||
type: object
|
||||
description: |
|
||||
|
@ -78,6 +84,8 @@ patternProperties:
|
|||
reg:
|
||||
description: |
|
||||
The channel number.
|
||||
minimum: 0
|
||||
maximum: 8
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
@ -92,18 +100,25 @@ allOf:
|
|||
const: renesas,r9a07g043-adc
|
||||
then:
|
||||
patternProperties:
|
||||
"^channel@[2-7]$": false
|
||||
"^channel@[2-8]$": false
|
||||
"^channel@[0-1]$":
|
||||
properties:
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 1
|
||||
else:
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,r9a07g044-adc
|
||||
- renesas,r9a07g054-adc
|
||||
then:
|
||||
patternProperties:
|
||||
"^channel@[8]$": false
|
||||
"^channel@[0-7]$":
|
||||
properties:
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 7
|
||||
|
||||
additionalProperties: false
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/chemical/bosch,bme680.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Bosch BME680 Gas sensor
|
||||
|
||||
maintainers:
|
||||
- Vasileios Amoiridis <vassilisamir@gmail.com>
|
||||
|
||||
description: >
|
||||
BME680 is a gas sensor which combines relative humidity, barometric pressure,
|
||||
ambient temperature and gas (VOC - Volatile Organic Compounds) measurements.
|
||||
|
||||
https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme680-ds001.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: bosch,bme680
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
vddio-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
co2-sensor@77 {
|
||||
compatible = "bosch,bme680";
|
||||
reg = <0x77>;
|
||||
vddio-supply = <&vddio>;
|
||||
vdd-supply = <&vdd>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
co2-sensor@0 {
|
||||
compatible = "bosch,bme680";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <500000>;
|
||||
vddio-supply = <&vddio>;
|
||||
vdd-supply = <&vdd>;
|
||||
};
|
||||
};
|
62
Documentation/devicetree/bindings/iio/dac/rohm,bd79703.yaml
Normal file
62
Documentation/devicetree/bindings/iio/dac/rohm,bd79703.yaml
Normal file
|
@ -0,0 +1,62 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2024 ROHM Semiconductor.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/rohm,bd79703.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ROHM BD79703 DAC device driver
|
||||
|
||||
maintainers:
|
||||
- Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
|
||||
description: |
|
||||
The ROHM BD79703 is a 6 channel, 8-bit DAC.
|
||||
Datasheet can be found here:
|
||||
https://fscdn.rohm.com/en/products/databook/datasheet/ic/data_converter/dac/bd79702fv-lb_bd79703fv-lb-e.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: rohm,bd79703
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 30000000
|
||||
|
||||
vfs-supply:
|
||||
description:
|
||||
The regulator to use as a full scale voltage. The voltage should be between 2.7V .. VCC
|
||||
|
||||
vcc-supply:
|
||||
description:
|
||||
The regulator supplying the operating voltage. Should be between 2.7V ... 5.5V
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- spi-max-frequency
|
||||
- vfs-supply
|
||||
- vcc-supply
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
compatible = "rohm,bd79703";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <30000000>;
|
||||
vcc-supply = <&vcc>;
|
||||
vfs-supply = <&vref>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -11,24 +11,30 @@ maintainers:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,adis16375
|
||||
- adi,adis16480
|
||||
- adi,adis16485
|
||||
- adi,adis16488
|
||||
- adi,adis16490
|
||||
- adi,adis16495-1
|
||||
- adi,adis16495-2
|
||||
- adi,adis16495-3
|
||||
- adi,adis16497-1
|
||||
- adi,adis16497-2
|
||||
- adi,adis16497-3
|
||||
- adi,adis16545-1
|
||||
- adi,adis16545-2
|
||||
- adi,adis16545-3
|
||||
- adi,adis16547-1
|
||||
- adi,adis16547-2
|
||||
- adi,adis16547-3
|
||||
oneOf:
|
||||
- enum:
|
||||
- adi,adis16375
|
||||
- adi,adis16480
|
||||
- adi,adis16485
|
||||
- adi,adis16486
|
||||
- adi,adis16488
|
||||
- adi,adis16489
|
||||
- adi,adis16490
|
||||
- adi,adis16495-1
|
||||
- adi,adis16495-2
|
||||
- adi,adis16495-3
|
||||
- adi,adis16497-1
|
||||
- adi,adis16497-2
|
||||
- adi,adis16497-3
|
||||
- adi,adis16545-1
|
||||
- adi,adis16545-2
|
||||
- adi,adis16545-3
|
||||
- adi,adis16547-1
|
||||
- adi,adis16547-2
|
||||
- adi,adis16547-3
|
||||
- items:
|
||||
- const: adi,adis16487
|
||||
- const: adi,adis16485
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
@ -37,6 +37,7 @@ properties:
|
|||
to "INT2" if INT2 pin should be used instead
|
||||
|
||||
drive-open-drain:
|
||||
type: boolean
|
||||
description: |
|
||||
set if the specified interrupt pin should be configured as
|
||||
open drain. If not set, defaults to push-pull.
|
||||
|
|
|
@ -41,6 +41,7 @@ properties:
|
|||
- INT2
|
||||
|
||||
drive-open-drain:
|
||||
type: boolean
|
||||
description:
|
||||
set if the specified interrupt pins should be configured as
|
||||
open drain. If not set, defaults to push-pull.
|
||||
|
|
|
@ -38,6 +38,7 @@ properties:
|
|||
- INT2
|
||||
|
||||
drive-open-drain:
|
||||
type: boolean
|
||||
description:
|
||||
set if the specified interrupt pin should be configured as
|
||||
open drain. If not set, defaults to push-pull.
|
||||
|
|
|
@ -16,6 +16,7 @@ properties:
|
|||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- invensense,iam20380
|
||||
- invensense,iam20680
|
||||
- invensense,icm20608
|
||||
- invensense,icm20609
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/light/rohm,bu27008.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ROHM BU27008 color sensor
|
||||
|
||||
maintainers:
|
||||
- Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
|
||||
description:
|
||||
The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear
|
||||
and IR) with four configurable channels. Red and green being always
|
||||
available and two out of the rest three (blue, clear, IR) can be
|
||||
selected to be simultaneously measured. Typical application is adjusting
|
||||
LCD backlight of TVs, mobile phones and tablet PCs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: rohm,bu27008
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
light-sensor@38 {
|
||||
compatible = "rohm,bu27008";
|
||||
reg = <0x38>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -1,50 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/light/rohm,bu27010.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ROHM BU27010 color sensor
|
||||
|
||||
maintainers:
|
||||
- Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
|
||||
description: |
|
||||
The ROHM BU27010 is a sensor with 6 photodiodes (red, green, blue, clear,
|
||||
IR and flickering detection) with five configurable channels. Red, green
|
||||
and flickering detection being always available and two out of the rest
|
||||
three (blue, clear, IR) can be selected to be simultaneously measured.
|
||||
Typical application is adjusting LCD/OLED backlight of TVs, mobile phones
|
||||
and tablet PCs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: rohm,bu27010
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
light-sensor@38 {
|
||||
compatible = "rohm,bu27010";
|
||||
reg = <0x38>;
|
||||
vdd-supply = <&vdd>;
|
||||
};
|
||||
};
|
51
Documentation/devicetree/bindings/iio/light/ti,opt4060.yaml
Normal file
51
Documentation/devicetree/bindings/iio/light/ti,opt4060.yaml
Normal file
|
@ -0,0 +1,51 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/light/ti,opt4060.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments OPT4060 RGBW Color Sensor
|
||||
|
||||
maintainers:
|
||||
- Per-Daniel Olsson <perdaniel.olsson@axis.com>
|
||||
|
||||
description:
|
||||
Texas Instrument RGBW high resolution color sensor over I2C.
|
||||
https://www.ti.com/lit/gpn/opt4060
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,opt4060
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
light-sensor@44 {
|
||||
compatible = "ti,opt4060";
|
||||
reg = <0x44>;
|
||||
vdd-supply = <&vdd_reg>;
|
||||
interrupt-parent = <&gpio5>;
|
||||
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -55,12 +55,16 @@ properties:
|
|||
If not set, defaults to push-pull configuration.
|
||||
type: boolean
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 10000000
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- vddd-supply
|
||||
- vdda-supply
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -73,6 +77,16 @@ allOf:
|
|||
then:
|
||||
properties:
|
||||
interrupts: false
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- bosch,bmp085
|
||||
- bosch,bmp180
|
||||
then:
|
||||
properties:
|
||||
spi-max-frequency: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
@ -93,3 +107,18 @@ examples:
|
|||
vdda-supply = <&bar>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
# include <dt-bindings/gpio/gpio.h>
|
||||
# include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
pressure@0 {
|
||||
compatible = "bosch,bmp280";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <10000000>;
|
||||
reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>;
|
||||
vddd-supply = <&foo>;
|
||||
vdda-supply = <&bar>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -55,8 +55,6 @@ properties:
|
|||
- atmel,atsha204a
|
||||
# BPA-RS600: Power Supply
|
||||
- blutek,bpa-rs600
|
||||
# Bosch Sensortec pressure, temperature, humididty and VOC sensor
|
||||
- bosch,bme680
|
||||
# CM32181: Ambient Light Sensor
|
||||
- capella,cm32181
|
||||
# CM3232: Ambient Light Sensor
|
||||
|
|
|
@ -101,7 +101,7 @@ The macro comes from:
|
|||
|
||||
.. code-block::
|
||||
|
||||
#include <dt-bindings/iio/adi,ad4695.h>
|
||||
#include <dt-bindings/iio/adc/adi,ad4695.h>
|
||||
|
||||
Pairing two INx pins
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -12,7 +12,10 @@ This driver supports Analog Device's IMUs on SPI bus.
|
|||
* `ADIS16375 <https://www.analog.com/ADIS16375>`_
|
||||
* `ADIS16480 <https://www.analog.com/ADIS16480>`_
|
||||
* `ADIS16485 <https://www.analog.com/ADIS16485>`_
|
||||
* `ADIS16486 <https://www.analog.com/ADIS16486>`_
|
||||
* `ADIS16487 <https://www.analog.com/ADIS16487>`_
|
||||
* `ADIS16488 <https://www.analog.com/ADIS16488>`_
|
||||
* `ADIS16489 <https://www.analog.com/ADIS16489>`_
|
||||
* `ADIS16490 <https://www.analog.com/ADIS16490>`_
|
||||
* `ADIS16495 <https://www.analog.com/ADIS16495>`_
|
||||
* `ADIS16497 <https://www.analog.com/ADIS16497>`_
|
||||
|
|
|
@ -29,3 +29,4 @@ Industrial I/O Kernel Drivers
|
|||
adxl380
|
||||
bno055
|
||||
ep93xx_adc
|
||||
opt4060
|
||||
|
|
61
Documentation/iio/opt4060.rst
Normal file
61
Documentation/iio/opt4060.rst
Normal file
|
@ -0,0 +1,61 @@
|
|||
==============================
|
||||
OPT4060 driver
|
||||
==============================
|
||||
|
||||
1. Overview
|
||||
=============================
|
||||
|
||||
This driver supports the Texas Instrument RGBW high resolution color sensor over
|
||||
I2C.
|
||||
https://www.ti.com/lit/gpn/opt4060
|
||||
|
||||
The driver supports:
|
||||
- Raw values for red, green, blue and clear.
|
||||
- Illuminance values.
|
||||
- Scaled color values for red, green and blue.
|
||||
- IIO events for thresholds.
|
||||
- IIO triggered buffer using both its own data ready trigger and triggers from
|
||||
other drivers.
|
||||
|
||||
2. Illuminance calculation
|
||||
=============================
|
||||
|
||||
Illuminance is calculated using the wide spectrum green channel.
|
||||
|
||||
lux = GREEN_RAW x 2.15e-3
|
||||
|
||||
The value is accessed from:
|
||||
/sys/bus/iio/devices/iio:deviceX/in_illuminance_input
|
||||
|
||||
See section 8.4.5.2 in the data sheet for additional details.
|
||||
|
||||
3. Color scale values
|
||||
=============================
|
||||
|
||||
The sensor has different sensitivity for the different color components and
|
||||
compensating factors are exposed from the driver.
|
||||
|
||||
The values are accessed from:
|
||||
/sys/bus/iio/devices/iio:deviceX/in_intensity_red_scale
|
||||
/sys/bus/iio/devices/iio:deviceX/in_intensity_green_scale
|
||||
/sys/bus/iio/devices/iio:deviceX/in_intensity_blue_scale
|
||||
|
||||
A userspace application can multiply the raw values with the scale values so
|
||||
that for a particular test light source, typically white, the measurement
|
||||
intensity is the same across the different color channels. This is calculated
|
||||
in the following way:
|
||||
|
||||
R = RED_RAW x SCALE_RED(2.4)
|
||||
G = GREEN_RAW x SCALE_GREEN(1.0)
|
||||
B = BLUE_RAW x SCALE_BLUE(1.3)
|
||||
|
||||
The data sheet suggests using the scaled values to normalize the scaled R, G
|
||||
and B values. This is useful to get a value for the ratio between colors
|
||||
independent of light intensity. A userspace application can do this in the
|
||||
following way:
|
||||
|
||||
R_NORMALIZED = R / (R + G + B)
|
||||
G_NORMALIZED = G / (R + G + B)
|
||||
B_NORMALIZED = B / (R + G + B)
|
||||
|
||||
See section 8.4.5.2 in the data sheet for additional details.
|
|
@ -1292,7 +1292,7 @@ W: https://ez.analog.com/linux-software-drivers
|
|||
F: Documentation/devicetree/bindings/iio/adc/adi,ad4695.yaml
|
||||
F: Documentation/iio/ad4695.rst
|
||||
F: drivers/iio/adc/ad4695.c
|
||||
F: include/dt-bindings/iio/adi,ad4695.h
|
||||
F: include/dt-bindings/iio/adc/adi,ad4695.h
|
||||
|
||||
ANALOG DEVICES INC AD7091R DRIVER
|
||||
M: Marcelo Schmitt <marcelo.schmitt@analog.com>
|
||||
|
@ -20304,6 +20304,11 @@ L: linux-serial@vger.kernel.org
|
|||
S: Odd Fixes
|
||||
F: drivers/tty/serial/rp2.*
|
||||
|
||||
ROHM BD79703 DAC
|
||||
M: Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
S: Supported
|
||||
F: drivers/iio/dac/rohm-bd79703.c
|
||||
|
||||
ROHM BD99954 CHARGER IC
|
||||
M: Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
S: Supported
|
||||
|
@ -20332,7 +20337,6 @@ ROHM BU270xx LIGHT SENSOR DRIVERs
|
|||
M: Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/iio/light/rohm-bu27008.c
|
||||
F: drivers/iio/light/rohm-bu27034.c
|
||||
|
||||
ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS
|
||||
|
|
|
@ -9,37 +9,93 @@
|
|||
#define _ADXL345_H_
|
||||
|
||||
#define ADXL345_REG_DEVID 0x00
|
||||
#define ADXL345_REG_THRESH_TAP 0x1D
|
||||
#define ADXL345_REG_OFSX 0x1E
|
||||
#define ADXL345_REG_OFSY 0x1F
|
||||
#define ADXL345_REG_OFSZ 0x20
|
||||
#define ADXL345_REG_OFS_AXIS(index) (ADXL345_REG_OFSX + (index))
|
||||
|
||||
/* Tap duration */
|
||||
#define ADXL345_REG_DUR 0x21
|
||||
/* Tap latency */
|
||||
#define ADXL345_REG_LATENT 0x22
|
||||
/* Tap window */
|
||||
#define ADXL345_REG_WINDOW 0x23
|
||||
/* Activity threshold */
|
||||
#define ADXL345_REG_THRESH_ACT 0x24
|
||||
/* Inactivity threshold */
|
||||
#define ADXL345_REG_THRESH_INACT 0x25
|
||||
/* Inactivity time */
|
||||
#define ADXL345_REG_TIME_INACT 0x26
|
||||
/* Axis enable control for activity and inactivity detection */
|
||||
#define ADXL345_REG_ACT_INACT_CTRL 0x27
|
||||
/* Free-fall threshold */
|
||||
#define ADXL345_REG_THRESH_FF 0x28
|
||||
/* Free-fall time */
|
||||
#define ADXL345_REG_TIME_FF 0x29
|
||||
/* Axis control for single tap or double tap */
|
||||
#define ADXL345_REG_TAP_AXIS 0x2A
|
||||
/* Source of single tap or double tap */
|
||||
#define ADXL345_REG_ACT_TAP_STATUS 0x2B
|
||||
/* Data rate and power mode control */
|
||||
#define ADXL345_REG_BW_RATE 0x2C
|
||||
#define ADXL345_REG_POWER_CTL 0x2D
|
||||
#define ADXL345_REG_INT_ENABLE 0x2E
|
||||
#define ADXL345_REG_INT_MAP 0x2F
|
||||
#define ADXL345_REG_INT_SOURCE 0x30
|
||||
#define ADXL345_REG_INT_SOURCE_MSK 0xFF
|
||||
#define ADXL345_REG_DATA_FORMAT 0x31
|
||||
#define ADXL345_REG_DATAX0 0x32
|
||||
#define ADXL345_REG_DATAY0 0x34
|
||||
#define ADXL345_REG_DATAZ0 0x36
|
||||
#define ADXL345_REG_DATA_AXIS(index) \
|
||||
(ADXL345_REG_DATAX0 + (index) * sizeof(__le16))
|
||||
#define ADXL345_REG_XYZ_BASE 0x32
|
||||
#define ADXL345_REG_DATA_AXIS(index) \
|
||||
(ADXL345_REG_XYZ_BASE + (index) * sizeof(__le16))
|
||||
|
||||
#define ADXL345_REG_FIFO_CTL 0x38
|
||||
#define ADXL345_FIFO_CTL_SAMPLES_MSK GENMASK(4, 0)
|
||||
/* 0: INT1, 1: INT2 */
|
||||
#define ADXL345_FIFO_CTL_TRIGGER_MSK BIT(5)
|
||||
#define ADXL345_FIFO_CTL_MODE_MSK GENMASK(7, 6)
|
||||
#define ADXL345_REG_FIFO_STATUS 0x39
|
||||
#define ADXL345_REG_FIFO_STATUS_MSK 0x3F
|
||||
|
||||
#define ADXL345_INT_OVERRUN BIT(0)
|
||||
#define ADXL345_INT_WATERMARK BIT(1)
|
||||
#define ADXL345_INT_FREE_FALL BIT(2)
|
||||
#define ADXL345_INT_INACTIVITY BIT(3)
|
||||
#define ADXL345_INT_ACTIVITY BIT(4)
|
||||
#define ADXL345_INT_DOUBLE_TAP BIT(5)
|
||||
#define ADXL345_INT_SINGLE_TAP BIT(6)
|
||||
#define ADXL345_INT_DATA_READY BIT(7)
|
||||
|
||||
/*
|
||||
* BW_RATE bits - Bandwidth and output data rate. The default value is
|
||||
* 0x0A, which translates to a 100 Hz output data rate
|
||||
*/
|
||||
#define ADXL345_BW_RATE GENMASK(3, 0)
|
||||
#define ADXL345_BW_LOW_POWER BIT(4)
|
||||
#define ADXL345_BASE_RATE_NANO_HZ 97656250LL
|
||||
|
||||
#define ADXL345_POWER_CTL_MEASURE BIT(3)
|
||||
#define ADXL345_POWER_CTL_STANDBY 0x00
|
||||
#define ADXL345_POWER_CTL_WAKEUP GENMASK(1, 0)
|
||||
#define ADXL345_POWER_CTL_SLEEP BIT(2)
|
||||
#define ADXL345_POWER_CTL_MEASURE BIT(3)
|
||||
#define ADXL345_POWER_CTL_AUTO_SLEEP BIT(4)
|
||||
#define ADXL345_POWER_CTL_LINK BIT(5)
|
||||
|
||||
#define ADXL345_DATA_FORMAT_RANGE GENMASK(1, 0) /* Set the g range */
|
||||
#define ADXL345_DATA_FORMAT_JUSTIFY BIT(2) /* Left-justified (MSB) mode */
|
||||
#define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */
|
||||
#define ADXL345_DATA_FORMAT_SPI_3WIRE BIT(6) /* 3-wire SPI mode */
|
||||
#define ADXL345_DATA_FORMAT_SELF_TEST BIT(7) /* Enable a self test */
|
||||
|
||||
/* Set the g range */
|
||||
#define ADXL345_DATA_FORMAT_RANGE GENMASK(1, 0)
|
||||
/* Data is left justified */
|
||||
#define ADXL345_DATA_FORMAT_JUSTIFY BIT(2)
|
||||
/* Up to 13-bits resolution */
|
||||
#define ADXL345_DATA_FORMAT_FULL_RES BIT(3)
|
||||
#define ADXL345_DATA_FORMAT_SPI_3WIRE BIT(6)
|
||||
#define ADXL345_DATA_FORMAT_SELF_TEST BIT(7)
|
||||
#define ADXL345_DATA_FORMAT_2G 0
|
||||
#define ADXL345_DATA_FORMAT_4G 1
|
||||
#define ADXL345_DATA_FORMAT_8G 2
|
||||
#define ADXL345_DATA_FORMAT_16G 3
|
||||
|
||||
#define ADXL345_DEVID 0xE5
|
||||
#define ADXL345_FIFO_SIZE 32
|
||||
|
||||
/*
|
||||
* In full-resolution mode, scale factor is maintained at ~4 mg/LSB
|
||||
|
@ -62,6 +118,7 @@ struct adxl345_chip_info {
|
|||
};
|
||||
|
||||
int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
||||
bool fifo_delay_default,
|
||||
int (*setup)(struct device*, struct regmap*));
|
||||
|
||||
#endif /* _ADXL345_H_ */
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
* Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
|
@ -14,36 +16,92 @@
|
|||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
|
||||
#include "adxl345.h"
|
||||
|
||||
struct adxl345_data {
|
||||
#define ADXL345_FIFO_BYPASS 0
|
||||
#define ADXL345_FIFO_FIFO 1
|
||||
#define ADXL345_FIFO_STREAM 2
|
||||
|
||||
#define ADXL345_DIRS 3
|
||||
|
||||
#define ADXL345_INT_NONE 0xff
|
||||
#define ADXL345_INT1 0
|
||||
#define ADXL345_INT2 1
|
||||
|
||||
struct adxl345_state {
|
||||
const struct adxl345_chip_info *info;
|
||||
struct regmap *regmap;
|
||||
bool fifo_delay; /* delay: delay is needed for SPI */
|
||||
int irq;
|
||||
u8 intio;
|
||||
u8 int_map;
|
||||
u8 watermark;
|
||||
u8 fifo_mode;
|
||||
__le16 fifo_buf[ADXL345_DIRS * ADXL345_FIFO_SIZE + 1] __aligned(IIO_DMA_MINALIGN);
|
||||
};
|
||||
|
||||
#define ADXL345_CHANNEL(index, axis) { \
|
||||
#define ADXL345_CHANNEL(index, reg, axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.address = index, \
|
||||
.address = (reg), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.scan_index = (index), \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 13, \
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_LE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec adxl345_channels[] = {
|
||||
ADXL345_CHANNEL(0, X),
|
||||
ADXL345_CHANNEL(1, Y),
|
||||
ADXL345_CHANNEL(2, Z),
|
||||
enum adxl345_chans {
|
||||
chan_x, chan_y, chan_z,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec adxl345_channels[] = {
|
||||
ADXL345_CHANNEL(0, chan_x, X),
|
||||
ADXL345_CHANNEL(1, chan_y, Y),
|
||||
ADXL345_CHANNEL(2, chan_z, Z),
|
||||
};
|
||||
|
||||
static const unsigned long adxl345_scan_masks[] = {
|
||||
BIT(chan_x) | BIT(chan_y) | BIT(chan_z),
|
||||
0
|
||||
};
|
||||
|
||||
static int adxl345_set_interrupts(struct adxl345_state *st)
|
||||
{
|
||||
int ret;
|
||||
unsigned int int_enable = st->int_map;
|
||||
unsigned int int_map;
|
||||
|
||||
/*
|
||||
* Any bits set to 0 in the INT map register send their respective
|
||||
* interrupts to the INT1 pin, whereas bits set to 1 send their respective
|
||||
* interrupts to the INT2 pin. The intio shall convert this accordingly.
|
||||
*/
|
||||
int_map = FIELD_GET(ADXL345_REG_INT_SOURCE_MSK,
|
||||
st->intio ? st->int_map : ~st->int_map);
|
||||
|
||||
ret = regmap_write(st->regmap, ADXL345_REG_INT_MAP, int_map);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, int_enable);
|
||||
}
|
||||
|
||||
static int adxl345_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct adxl345_data *data = iio_priv(indio_dev);
|
||||
struct adxl345_state *st = iio_priv(indio_dev);
|
||||
__le16 accel;
|
||||
long long samp_freq_nhz;
|
||||
unsigned int regval;
|
||||
|
@ -56,7 +114,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
|
|||
* ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte
|
||||
* and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte
|
||||
*/
|
||||
ret = regmap_bulk_read(data->regmap,
|
||||
ret = regmap_bulk_read(st->regmap,
|
||||
ADXL345_REG_DATA_AXIS(chan->address),
|
||||
&accel, sizeof(accel));
|
||||
if (ret < 0)
|
||||
|
@ -66,10 +124,10 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
|
|||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
*val2 = data->info->uscale;
|
||||
*val2 = st->info->uscale;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
ret = regmap_read(data->regmap,
|
||||
ret = regmap_read(st->regmap,
|
||||
ADXL345_REG_OFS_AXIS(chan->address), ®val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -81,7 +139,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
|
|||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = regmap_read(data->regmap, ADXL345_REG_BW_RATE, ®val);
|
||||
ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -99,7 +157,7 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
|
|||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct adxl345_data *data = iio_priv(indio_dev);
|
||||
struct adxl345_state *st = iio_priv(indio_dev);
|
||||
s64 n;
|
||||
|
||||
switch (mask) {
|
||||
|
@ -108,14 +166,14 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
|
|||
* 8-bit resolution at +/- 2g, that is 4x accel data scale
|
||||
* factor
|
||||
*/
|
||||
return regmap_write(data->regmap,
|
||||
return regmap_write(st->regmap,
|
||||
ADXL345_REG_OFS_AXIS(chan->address),
|
||||
val / 4);
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
n = div_s64(val * NANOHZ_PER_HZ + val2,
|
||||
ADXL345_BASE_RATE_NANO_HZ);
|
||||
|
||||
return regmap_update_bits(data->regmap, ADXL345_REG_BW_RATE,
|
||||
return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE,
|
||||
ADXL345_BW_RATE,
|
||||
clamp_val(ilog2(n), 0,
|
||||
ADXL345_BW_RATE));
|
||||
|
@ -124,6 +182,24 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adxl345_set_watermark(struct iio_dev *indio_dev, unsigned int value)
|
||||
{
|
||||
struct adxl345_state *st = iio_priv(indio_dev);
|
||||
unsigned int fifo_mask = 0x1F;
|
||||
int ret;
|
||||
|
||||
value = min(value, ADXL345_FIFO_SIZE - 1);
|
||||
|
||||
ret = regmap_update_bits(st->regmap, ADXL345_REG_FIFO_CTL, fifo_mask, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->watermark = value;
|
||||
st->int_map |= ADXL345_INT_WATERMARK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
long mask)
|
||||
|
@ -138,6 +214,33 @@ static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adxl345_set_measure_en() - Enable and disable measuring.
|
||||
*
|
||||
* @st: The device data.
|
||||
* @en: Enable measurements, else standby mode.
|
||||
*
|
||||
* For lowest power operation, standby mode can be used. In standby mode,
|
||||
* current consumption is supposed to be reduced to 0.1uA (typical). In this
|
||||
* mode no measurements are made. Placing the device into standby mode
|
||||
* preserves the contents of FIFO.
|
||||
*
|
||||
* Return: Returns 0 if successful, or a negative error value.
|
||||
*/
|
||||
static int adxl345_set_measure_en(struct adxl345_state *st, bool en)
|
||||
{
|
||||
unsigned int val = en ? ADXL345_POWER_CTL_MEASURE : ADXL345_POWER_CTL_STANDBY;
|
||||
|
||||
return regmap_write(st->regmap, ADXL345_REG_POWER_CTL, val);
|
||||
}
|
||||
|
||||
static void adxl345_powerdown(void *ptr)
|
||||
{
|
||||
struct adxl345_state *st = ptr;
|
||||
|
||||
adxl345_set_measure_en(st, false);
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
|
||||
"0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200"
|
||||
);
|
||||
|
@ -151,37 +254,244 @@ static const struct attribute_group adxl345_attrs_group = {
|
|||
.attrs = adxl345_attrs,
|
||||
};
|
||||
|
||||
static int adxl345_set_fifo(struct adxl345_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* FIFO should only be configured while in standby mode */
|
||||
ret = adxl345_set_measure_en(st, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL,
|
||||
FIELD_PREP(ADXL345_FIFO_CTL_SAMPLES_MSK,
|
||||
st->watermark) |
|
||||
FIELD_PREP(ADXL345_FIFO_CTL_TRIGGER_MSK,
|
||||
st->intio) |
|
||||
FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK,
|
||||
st->fifo_mode));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return adxl345_set_measure_en(st, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* adxl345_get_samples() - Read number of FIFO entries.
|
||||
* @st: The initialized state instance of this driver.
|
||||
*
|
||||
* The sensor does not support treating any axis individually, or exclude them
|
||||
* from measuring.
|
||||
*
|
||||
* Return: negative error, or value.
|
||||
*/
|
||||
static int adxl345_get_samples(struct adxl345_state *st)
|
||||
{
|
||||
unsigned int regval = 0;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(st->regmap, ADXL345_REG_FIFO_STATUS, ®val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return FIELD_GET(ADXL345_REG_FIFO_STATUS_MSK, regval);
|
||||
}
|
||||
|
||||
/**
|
||||
* adxl345_fifo_transfer() - Read samples number of elements.
|
||||
* @st: The instance of the state object of this sensor.
|
||||
* @samples: The number of lines in the FIFO referred to as fifo_entry.
|
||||
*
|
||||
* It is recommended that a multiple-byte read of all registers be performed to
|
||||
* prevent a change in data between reads of sequential registers. That is to
|
||||
* read out the data registers X0, X1, Y0, Y1, Z0, Z1, i.e. 6 bytes at once.
|
||||
*
|
||||
* Return: 0 or error value.
|
||||
*/
|
||||
static int adxl345_fifo_transfer(struct adxl345_state *st, int samples)
|
||||
{
|
||||
size_t count;
|
||||
int i, ret = 0;
|
||||
|
||||
/* count is the 3x the fifo_buf element size, hence 6B */
|
||||
count = sizeof(st->fifo_buf[0]) * ADXL345_DIRS;
|
||||
for (i = 0; i < samples; i++) {
|
||||
/* read 3x 2 byte elements from base address into next fifo_buf position */
|
||||
ret = regmap_bulk_read(st->regmap, ADXL345_REG_XYZ_BASE,
|
||||
st->fifo_buf + (i * count / 2), count);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* To ensure that the FIFO has completely popped, there must be at least 5
|
||||
* us between the end of reading the data registers, signified by the
|
||||
* transition to register 0x38 from 0x37 or the CS pin going high, and the
|
||||
* start of new reads of the FIFO or reading the FIFO_STATUS register. For
|
||||
* SPI operation at 1.5 MHz or lower, the register addressing portion of the
|
||||
* transmission is sufficient delay to ensure the FIFO has completely
|
||||
* popped. It is necessary for SPI operation greater than 1.5 MHz to
|
||||
* de-assert the CS pin to ensure a total of 5 us, which is at most 3.4 us
|
||||
* at 5 MHz operation.
|
||||
*/
|
||||
if (st->fifo_delay && samples > 1)
|
||||
udelay(3);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* adxl345_fifo_reset() - Empty the FIFO in error condition.
|
||||
* @st: The instance to the state object of the sensor.
|
||||
*
|
||||
* Read all elements of the FIFO. Reading the interrupt source register
|
||||
* resets the sensor.
|
||||
*/
|
||||
static void adxl345_fifo_reset(struct adxl345_state *st)
|
||||
{
|
||||
int regval;
|
||||
int samples;
|
||||
|
||||
adxl345_set_measure_en(st, false);
|
||||
|
||||
samples = adxl345_get_samples(st);
|
||||
if (samples > 0)
|
||||
adxl345_fifo_transfer(st, samples);
|
||||
|
||||
regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, ®val);
|
||||
|
||||
adxl345_set_measure_en(st, true);
|
||||
}
|
||||
|
||||
static int adxl345_buffer_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct adxl345_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = adxl345_set_interrupts(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st->fifo_mode = ADXL345_FIFO_STREAM;
|
||||
return adxl345_set_fifo(st);
|
||||
}
|
||||
|
||||
static int adxl345_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct adxl345_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
st->fifo_mode = ADXL345_FIFO_BYPASS;
|
||||
ret = adxl345_set_fifo(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st->int_map = 0x00;
|
||||
return adxl345_set_interrupts(st);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops adxl345_buffer_ops = {
|
||||
.postenable = adxl345_buffer_postenable,
|
||||
.predisable = adxl345_buffer_predisable,
|
||||
};
|
||||
|
||||
static int adxl345_get_status(struct adxl345_state *st)
|
||||
{
|
||||
int ret;
|
||||
unsigned int regval;
|
||||
|
||||
ret = regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, ®val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return FIELD_GET(ADXL345_REG_INT_SOURCE_MSK, regval);
|
||||
}
|
||||
|
||||
static int adxl345_fifo_push(struct iio_dev *indio_dev,
|
||||
int samples)
|
||||
{
|
||||
struct adxl345_state *st = iio_priv(indio_dev);
|
||||
int i, ret;
|
||||
|
||||
if (samples <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = adxl345_fifo_transfer(st, samples);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ADXL345_DIRS * samples; i += ADXL345_DIRS)
|
||||
iio_push_to_buffers(indio_dev, &st->fifo_buf[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* adxl345_irq_handler() - Handle irqs of the ADXL345.
|
||||
* @irq: The irq being handled.
|
||||
* @p: The struct iio_device pointer for the device.
|
||||
*
|
||||
* Return: The interrupt was handled.
|
||||
*/
|
||||
static irqreturn_t adxl345_irq_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_dev *indio_dev = p;
|
||||
struct adxl345_state *st = iio_priv(indio_dev);
|
||||
int int_stat;
|
||||
int samples;
|
||||
|
||||
int_stat = adxl345_get_status(st);
|
||||
if (int_stat <= 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
if (int_stat & ADXL345_INT_OVERRUN)
|
||||
goto err;
|
||||
|
||||
if (int_stat & ADXL345_INT_WATERMARK) {
|
||||
samples = adxl345_get_samples(st);
|
||||
if (samples < 0)
|
||||
goto err;
|
||||
|
||||
if (adxl345_fifo_push(indio_dev, samples) < 0)
|
||||
goto err;
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
|
||||
err:
|
||||
adxl345_fifo_reset(st);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct iio_info adxl345_info = {
|
||||
.attrs = &adxl345_attrs_group,
|
||||
.read_raw = adxl345_read_raw,
|
||||
.write_raw = adxl345_write_raw,
|
||||
.write_raw_get_fmt = adxl345_write_raw_get_fmt,
|
||||
.hwfifo_set_watermark = adxl345_set_watermark,
|
||||
};
|
||||
|
||||
static int adxl345_powerup(void *regmap)
|
||||
{
|
||||
return regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_MEASURE);
|
||||
}
|
||||
|
||||
static void adxl345_powerdown(void *regmap)
|
||||
{
|
||||
regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY);
|
||||
}
|
||||
|
||||
/**
|
||||
* adxl345_core_probe() - probe and setup for the adxl345 accelerometer,
|
||||
* also covers the adlx375 accelerometer
|
||||
* adxl345_core_probe() - Probe and setup for the accelerometer.
|
||||
* @dev: Driver model representation of the device
|
||||
* @regmap: Regmap instance for the device
|
||||
* @fifo_delay_default: Using FIFO with SPI needs delay
|
||||
* @setup: Setup routine to be executed right before the standard device
|
||||
* setup
|
||||
*
|
||||
* For SPI operation greater than 1.6 MHz, it is necessary to deassert the CS
|
||||
* pin to ensure a total delay of 5 us; otherwise, the delay is not sufficient.
|
||||
* The total delay necessary for 5 MHz operation is at most 3.4 us. This is not
|
||||
* a concern when using I2C mode because the communication rate is low enough
|
||||
* to ensure a sufficient delay between FIFO reads.
|
||||
* Ref: "Retrieving Data from FIFO", p. 21 of 36, Data Sheet ADXL345 Rev. G
|
||||
*
|
||||
* Return: 0 on success, negative errno on error
|
||||
*/
|
||||
int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
||||
bool fifo_delay_default,
|
||||
int (*setup)(struct device*, struct regmap*))
|
||||
{
|
||||
struct adxl345_data *data;
|
||||
struct adxl345_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
u32 regval;
|
||||
unsigned int data_format_mask = (ADXL345_DATA_FORMAT_RANGE |
|
||||
|
@ -190,30 +500,32 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
|||
ADXL345_DATA_FORMAT_SELF_TEST);
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
data->regmap = regmap;
|
||||
data->info = device_get_match_data(dev);
|
||||
if (!data->info)
|
||||
st = iio_priv(indio_dev);
|
||||
st->regmap = regmap;
|
||||
st->info = device_get_match_data(dev);
|
||||
if (!st->info)
|
||||
return -ENODEV;
|
||||
st->fifo_delay = fifo_delay_default;
|
||||
|
||||
indio_dev->name = data->info->name;
|
||||
indio_dev->name = st->info->name;
|
||||
indio_dev->info = &adxl345_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = adxl345_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adxl345_channels);
|
||||
indio_dev->available_scan_masks = adxl345_scan_masks;
|
||||
|
||||
if (setup) {
|
||||
/* Perform optional initial bus specific configuration */
|
||||
ret = setup(dev, data->regmap);
|
||||
ret = setup(dev, st->regmap);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable full-resolution mode */
|
||||
ret = regmap_update_bits(data->regmap, ADXL345_REG_DATA_FORMAT,
|
||||
ret = regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT,
|
||||
data_format_mask,
|
||||
ADXL345_DATA_FORMAT_FULL_RES);
|
||||
if (ret)
|
||||
|
@ -222,14 +534,14 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
|||
|
||||
} else {
|
||||
/* Enable full-resolution mode (init all data_format bits) */
|
||||
ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT,
|
||||
ret = regmap_write(st->regmap, ADXL345_REG_DATA_FORMAT,
|
||||
ADXL345_DATA_FORMAT_FULL_RES);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to set data range\n");
|
||||
}
|
||||
|
||||
ret = regmap_read(data->regmap, ADXL345_REG_DEVID, ®val);
|
||||
ret = regmap_read(st->regmap, ADXL345_REG_DEVID, ®val);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Error reading device ID\n");
|
||||
|
||||
|
@ -238,14 +550,43 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
|||
regval, ADXL345_DEVID);
|
||||
|
||||
/* Enable measurement mode */
|
||||
ret = adxl345_powerup(data->regmap);
|
||||
ret = adxl345_set_measure_en(st, true);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to enable measurement mode\n");
|
||||
|
||||
ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap);
|
||||
ret = devm_add_action_or_reset(dev, adxl345_powerdown, st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st->intio = ADXL345_INT1;
|
||||
st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT1");
|
||||
if (st->irq < 0) {
|
||||
st->intio = ADXL345_INT2;
|
||||
st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2");
|
||||
if (st->irq < 0)
|
||||
st->intio = ADXL345_INT_NONE;
|
||||
}
|
||||
|
||||
if (st->intio != ADXL345_INT_NONE) {
|
||||
/* FIFO_STREAM mode is going to be activated later */
|
||||
ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &adxl345_buffer_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_threaded_irq(dev, st->irq, NULL,
|
||||
&adxl345_irq_handler,
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
indio_dev->name, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL,
|
||||
FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK,
|
||||
ADXL345_FIFO_BYPASS));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, "IIO_ADXL345");
|
||||
|
|
|
@ -27,7 +27,7 @@ static int adxl345_i2c_probe(struct i2c_client *client)
|
|||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(regmap), "Error initializing regmap\n");
|
||||
|
||||
return adxl345_core_probe(&client->dev, regmap, NULL);
|
||||
return adxl345_core_probe(&client->dev, regmap, false, NULL);
|
||||
}
|
||||
|
||||
static const struct adxl345_chip_info adxl345_i2c_info = {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "adxl345.h"
|
||||
|
||||
#define ADXL345_MAX_SPI_FREQ_HZ 5000000
|
||||
#define ADXL345_MAX_FREQ_NO_FIFO_DELAY 1500000
|
||||
|
||||
static const struct regmap_config adxl345_spi_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
|
@ -28,6 +29,7 @@ static int adxl345_spi_setup(struct device *dev, struct regmap *regmap)
|
|||
static int adxl345_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
bool needs_delay;
|
||||
|
||||
/* Bail out if max_speed_hz exceeds 5 MHz */
|
||||
if (spi->max_speed_hz > ADXL345_MAX_SPI_FREQ_HZ)
|
||||
|
@ -38,10 +40,11 @@ static int adxl345_spi_probe(struct spi_device *spi)
|
|||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n");
|
||||
|
||||
needs_delay = spi->max_speed_hz > ADXL345_MAX_FREQ_NO_FIFO_DELAY;
|
||||
if (spi->mode & SPI_3WIRE)
|
||||
return adxl345_core_probe(&spi->dev, regmap, adxl345_spi_setup);
|
||||
return adxl345_core_probe(&spi->dev, regmap, needs_delay, adxl345_spi_setup);
|
||||
else
|
||||
return adxl345_core_probe(&spi->dev, regmap, NULL);
|
||||
return adxl345_core_probe(&spi->dev, regmap, needs_delay, NULL);
|
||||
}
|
||||
|
||||
static const struct adxl345_chip_info adxl345_spi_info = {
|
||||
|
|
|
@ -66,7 +66,7 @@ struct bma220_data {
|
|||
struct {
|
||||
s8 chans[3];
|
||||
/* Ensure timestamp is naturally aligned. */
|
||||
s64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} scan;
|
||||
u8 tx_buf[2] __aligned(IIO_DMA_MINALIGN);
|
||||
};
|
||||
|
|
|
@ -129,6 +129,8 @@
|
|||
|
||||
#define FXLS8962AF_DEVICE_ID 0x62
|
||||
#define FXLS8964AF_DEVICE_ID 0x84
|
||||
#define FXLS8974CF_DEVICE_ID 0x86
|
||||
#define FXLS8967AF_DEVICE_ID 0x87
|
||||
|
||||
/* Raw temp channel offset */
|
||||
#define FXLS8962AF_TEMP_CENTER_VAL 25
|
||||
|
@ -766,6 +768,18 @@ static const struct fxls8962af_chip_info fxls_chip_info_table[] = {
|
|||
.channels = fxls8962af_channels,
|
||||
.num_channels = ARRAY_SIZE(fxls8962af_channels),
|
||||
},
|
||||
[fxls8967af] = {
|
||||
.chip_id = FXLS8967AF_DEVICE_ID,
|
||||
.name = "fxls8967af",
|
||||
.channels = fxls8962af_channels,
|
||||
.num_channels = ARRAY_SIZE(fxls8962af_channels),
|
||||
},
|
||||
[fxls8974cf] = {
|
||||
.chip_id = FXLS8974CF_DEVICE_ID,
|
||||
.name = "fxls8974cf",
|
||||
.channels = fxls8962af_channels,
|
||||
.num_channels = ARRAY_SIZE(fxls8962af_channels),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_info fxls8962af_info = {
|
||||
|
|
|
@ -30,6 +30,8 @@ static int fxls8962af_probe(struct i2c_client *client)
|
|||
static const struct i2c_device_id fxls8962af_id[] = {
|
||||
{ "fxls8962af", fxls8962af },
|
||||
{ "fxls8964af", fxls8964af },
|
||||
{ "fxls8967af", fxls8967af },
|
||||
{ "fxls8974cf", fxls8974cf },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, fxls8962af_id);
|
||||
|
|
|
@ -11,6 +11,8 @@ struct device;
|
|||
enum {
|
||||
fxls8962af,
|
||||
fxls8964af,
|
||||
fxls8967af,
|
||||
fxls8974cf,
|
||||
};
|
||||
|
||||
int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq);
|
||||
|
|
|
@ -38,7 +38,9 @@ static int kx022a_i2c_probe(struct i2c_client *i2c)
|
|||
static const struct i2c_device_id kx022a_i2c_id[] = {
|
||||
{ .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
|
||||
{ .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info },
|
||||
{ .name = "kx134-1211", .driver_data = (kernel_ulong_t)&kx134_chip_info },
|
||||
{ .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info },
|
||||
{ .name = "kx134acr-lbz", .driver_data = (kernel_ulong_t)&kx134acr_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id);
|
||||
|
@ -46,7 +48,9 @@ MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id);
|
|||
static const struct of_device_id kx022a_of_match[] = {
|
||||
{ .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
|
||||
{ .compatible = "kionix,kx132-1211", .data = &kx132_chip_info },
|
||||
{ .compatible = "kionix,kx134-1211", .data = &kx134_chip_info },
|
||||
{ .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info },
|
||||
{ .compatible = "rohm,kx134acr-lbz", .data = &kx134acr_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, kx022a_of_match);
|
||||
|
|
|
@ -38,7 +38,9 @@ static int kx022a_spi_probe(struct spi_device *spi)
|
|||
static const struct spi_device_id kx022a_id[] = {
|
||||
{ .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
|
||||
{ .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info },
|
||||
{ .name = "kx134-1211", .driver_data = (kernel_ulong_t)&kx134_chip_info },
|
||||
{ .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info },
|
||||
{ .name = "kx134acr-lbz", .driver_data = (kernel_ulong_t)&kx134acr_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, kx022a_id);
|
||||
|
@ -46,7 +48,9 @@ MODULE_DEVICE_TABLE(spi, kx022a_id);
|
|||
static const struct of_device_id kx022a_of_match[] = {
|
||||
{ .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
|
||||
{ .compatible = "kionix,kx132-1211", .data = &kx132_chip_info },
|
||||
{ .compatible = "kionix,kx134-1211", .data = &kx134_chip_info },
|
||||
{ .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info },
|
||||
{ .compatible = "rohm,kx134acr-lbz", .data = &kx134acr_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, kx022a_of_match);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* ROHM/KIONIX accelerometer driver
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -407,11 +408,21 @@ static const int kx022a_scale_table[][2] = {
|
|||
{ 0, 4788403 },
|
||||
};
|
||||
|
||||
/* KX134ACR-LBZ ranges are (+/-) 8, 16, 32, 64 G */
|
||||
static const int kx134acr_lbz_scale_table[][2] = {
|
||||
{ 0, 2394202 },
|
||||
{ 0, 4788403 },
|
||||
{ 0, 9576807 },
|
||||
{ 0, 19153613 },
|
||||
};
|
||||
|
||||
static int kx022a_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length,
|
||||
long mask)
|
||||
{
|
||||
struct kx022a_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*vals = (const int *)kx022a_accel_samp_freq_table;
|
||||
|
@ -420,9 +431,8 @@ static int kx022a_read_avail(struct iio_dev *indio_dev,
|
|||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
return IIO_AVAIL_LIST;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*vals = (const int *)kx022a_scale_table;
|
||||
*length = ARRAY_SIZE(kx022a_scale_table) *
|
||||
ARRAY_SIZE(kx022a_scale_table[0]);
|
||||
*vals = (const int *)data->chip_info->scale_table;
|
||||
*length = data->chip_info->scale_table_size;
|
||||
*type = IIO_VAL_INT_PLUS_NANO;
|
||||
return IIO_AVAIL_LIST;
|
||||
default:
|
||||
|
@ -438,17 +448,17 @@ static void kx022a_reg2freq(unsigned int val, int *val1, int *val2)
|
|||
*val2 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][1];
|
||||
}
|
||||
|
||||
static void kx022a_reg2scale(unsigned int val, unsigned int *val1,
|
||||
unsigned int *val2)
|
||||
static void kx022a_reg2scale(struct kx022a_data *data, unsigned int val,
|
||||
unsigned int *val1, unsigned int *val2)
|
||||
{
|
||||
val &= KX022A_MASK_GSEL;
|
||||
val >>= KX022A_GSEL_SHIFT;
|
||||
|
||||
*val1 = kx022a_scale_table[val][0];
|
||||
*val2 = kx022a_scale_table[val][1];
|
||||
*val1 = data->chip_info->scale_table[val][0];
|
||||
*val2 = data->chip_info->scale_table[val][1];
|
||||
}
|
||||
|
||||
static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on)
|
||||
static int __kx022a_turn_on_off(struct kx022a_data *data, bool on)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -469,7 +479,7 @@ static int kx022a_turn_off_lock(struct kx022a_data *data)
|
|||
int ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
ret = kx022a_turn_on_off_unlocked(data, false);
|
||||
ret = __kx022a_turn_on_off(data, false);
|
||||
if (ret)
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
|
@ -480,7 +490,7 @@ static int kx022a_turn_on_unlock(struct kx022a_data *data)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = kx022a_turn_on_off_unlocked(data, true);
|
||||
ret = __kx022a_turn_on_off(data, true);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return ret;
|
||||
|
@ -543,11 +553,11 @@ static int kx022a_write_raw(struct iio_dev *idev,
|
|||
kx022a_turn_on_unlock(data);
|
||||
break;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
n = ARRAY_SIZE(kx022a_scale_table);
|
||||
n = data->chip_info->scale_table_size / 2;
|
||||
|
||||
while (n-- > 0)
|
||||
if (val == kx022a_scale_table[n][0] &&
|
||||
val2 == kx022a_scale_table[n][1])
|
||||
if (val == data->chip_info->scale_table[n][0] &&
|
||||
val2 == data->chip_info->scale_table[n][1])
|
||||
break;
|
||||
if (n < 0) {
|
||||
ret = -EINVAL;
|
||||
|
@ -642,7 +652,7 @@ static int kx022a_read_raw(struct iio_dev *idev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
kx022a_reg2scale(regval, val, val2);
|
||||
kx022a_reg2scale(data, regval, val, val2);
|
||||
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
}
|
||||
|
@ -912,18 +922,19 @@ static int kx022a_fifo_disable(struct kx022a_data *data)
|
|||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = kx022a_turn_off_lock(data);
|
||||
guard(mutex)(&data->mutex);
|
||||
ret = __kx022a_turn_on_off(data, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_clear_bits(data->regmap, data->ien_reg, KX022A_MASK_WMI);
|
||||
if (ret)
|
||||
goto unlock_out;
|
||||
return ret;
|
||||
|
||||
ret = regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2,
|
||||
KX022A_MASK_BUF_EN);
|
||||
if (ret)
|
||||
goto unlock_out;
|
||||
return ret;
|
||||
|
||||
data->state &= ~KX022A_STATE_FIFO;
|
||||
|
||||
|
@ -931,12 +942,7 @@ static int kx022a_fifo_disable(struct kx022a_data *data)
|
|||
|
||||
kfree(data->fifo_buffer);
|
||||
|
||||
return kx022a_turn_on_unlock(data);
|
||||
|
||||
unlock_out:
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return ret;
|
||||
return __kx022a_turn_on_off(data, true);
|
||||
}
|
||||
|
||||
static int kx022a_buffer_predisable(struct iio_dev *idev)
|
||||
|
@ -959,33 +965,29 @@ static int kx022a_fifo_enable(struct kx022a_data *data)
|
|||
if (!data->fifo_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = kx022a_turn_off_lock(data);
|
||||
guard(mutex)(&data->mutex);
|
||||
ret = __kx022a_turn_on_off(data, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Update watermark to HW */
|
||||
ret = kx022a_fifo_set_wmi(data);
|
||||
if (ret)
|
||||
goto unlock_out;
|
||||
return ret;
|
||||
|
||||
/* Enable buffer */
|
||||
ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
|
||||
KX022A_MASK_BUF_EN);
|
||||
if (ret)
|
||||
goto unlock_out;
|
||||
return ret;
|
||||
|
||||
data->state |= KX022A_STATE_FIFO;
|
||||
ret = regmap_set_bits(data->regmap, data->ien_reg,
|
||||
KX022A_MASK_WMI);
|
||||
if (ret)
|
||||
goto unlock_out;
|
||||
return ret;
|
||||
|
||||
return kx022a_turn_on_unlock(data);
|
||||
|
||||
unlock_out:
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return ret;
|
||||
return __kx022a_turn_on_off(data, true);
|
||||
}
|
||||
|
||||
static int kx022a_buffer_postenable(struct iio_dev *idev)
|
||||
|
@ -1053,7 +1055,7 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private)
|
|||
struct kx022a_data *data = iio_priv(idev);
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
guard(mutex)(&data->mutex);
|
||||
|
||||
if (data->trigger_enabled) {
|
||||
iio_trigger_poll_nested(data->trig);
|
||||
|
@ -1068,8 +1070,6 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private)
|
|||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1079,32 +1079,26 @@ static int kx022a_trigger_set_state(struct iio_trigger *trig,
|
|||
struct kx022a_data *data = iio_trigger_get_drvdata(trig);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
guard(mutex)(&data->mutex);
|
||||
|
||||
if (data->trigger_enabled == state)
|
||||
goto unlock_out;
|
||||
return 0;
|
||||
|
||||
if (data->state & KX022A_STATE_FIFO) {
|
||||
dev_warn(data->dev, "Can't set trigger when FIFO enabled\n");
|
||||
ret = -EBUSY;
|
||||
goto unlock_out;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = kx022a_turn_on_off_unlocked(data, false);
|
||||
ret = __kx022a_turn_on_off(data, false);
|
||||
if (ret)
|
||||
goto unlock_out;
|
||||
return ret;
|
||||
|
||||
data->trigger_enabled = state;
|
||||
ret = kx022a_set_drdy_irq(data, state);
|
||||
if (ret)
|
||||
goto unlock_out;
|
||||
return ret;
|
||||
|
||||
ret = kx022a_turn_on_off_unlocked(data, true);
|
||||
|
||||
unlock_out:
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return ret;
|
||||
return __kx022a_turn_on_off(data, true);
|
||||
}
|
||||
|
||||
static const struct iio_trigger_ops kx022a_trigger_ops = {
|
||||
|
@ -1121,10 +1115,15 @@ static int kx022a_chip_init(struct kx022a_data *data)
|
|||
return ret;
|
||||
|
||||
/*
|
||||
* I've seen I2C read failures if we poll too fast after the sensor
|
||||
* reset. Slight delay gives I2C block the time to recover.
|
||||
* According to the power-on procedure documents, there is (at least)
|
||||
* 2ms delay required after the software reset. This should be same for
|
||||
* all, KX022ACR-Z, KX132-1211, KX132ACR-LBZ and KX134ACR-LBZ.
|
||||
*
|
||||
* https://fscdn.rohm.com/kionix/en/document/AN010_KX022ACR-Z_Power-on_Procedure_E.pdf
|
||||
* https://fscdn.rohm.com/kionix/en/document/TN027-Power-On-Procedure.pdf
|
||||
* https://fscdn.rohm.com/kionix/en/document/AN011_KX134ACR-LBZ_Power-on_Procedure_E.pdf
|
||||
*/
|
||||
msleep(1);
|
||||
msleep(2);
|
||||
|
||||
ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val,
|
||||
!(val & KX022A_MASK_SRST),
|
||||
|
@ -1158,6 +1157,9 @@ const struct kx022a_chip_info kx022a_chip_info = {
|
|||
.regmap_config = &kx022a_regmap_config,
|
||||
.channels = kx022a_channels,
|
||||
.num_channels = ARRAY_SIZE(kx022a_channels),
|
||||
.scale_table = kx022a_scale_table,
|
||||
.scale_table_size = ARRAY_SIZE(kx022a_scale_table) *
|
||||
ARRAY_SIZE(kx022a_scale_table[0]),
|
||||
.fifo_length = KX022A_FIFO_LENGTH,
|
||||
.who = KX022A_REG_WHO,
|
||||
.id = KX022A_ID,
|
||||
|
@ -1183,6 +1185,9 @@ const struct kx022a_chip_info kx132_chip_info = {
|
|||
.regmap_config = &kx132_regmap_config,
|
||||
.channels = kx132_channels,
|
||||
.num_channels = ARRAY_SIZE(kx132_channels),
|
||||
.scale_table = kx022a_scale_table,
|
||||
.scale_table_size = ARRAY_SIZE(kx022a_scale_table) *
|
||||
ARRAY_SIZE(kx022a_scale_table[0]),
|
||||
.fifo_length = KX132_FIFO_LENGTH,
|
||||
.who = KX132_REG_WHO,
|
||||
.id = KX132_ID,
|
||||
|
@ -1204,6 +1209,35 @@ const struct kx022a_chip_info kx132_chip_info = {
|
|||
};
|
||||
EXPORT_SYMBOL_NS_GPL(kx132_chip_info, "IIO_KX022A");
|
||||
|
||||
const struct kx022a_chip_info kx134_chip_info = {
|
||||
.name = "kx134-1211",
|
||||
.regmap_config = &kx132_regmap_config,
|
||||
.channels = kx132_channels,
|
||||
.num_channels = ARRAY_SIZE(kx132_channels),
|
||||
.scale_table = kx134acr_lbz_scale_table,
|
||||
.scale_table_size = ARRAY_SIZE(kx134acr_lbz_scale_table) *
|
||||
ARRAY_SIZE(kx134acr_lbz_scale_table[0]),
|
||||
.fifo_length = KX132_FIFO_LENGTH,
|
||||
.who = KX132_REG_WHO,
|
||||
.id = KX134_1211_ID,
|
||||
.cntl = KX132_REG_CNTL,
|
||||
.cntl2 = KX132_REG_CNTL2,
|
||||
.odcntl = KX132_REG_ODCNTL,
|
||||
.buf_cntl1 = KX132_REG_BUF_CNTL1,
|
||||
.buf_cntl2 = KX132_REG_BUF_CNTL2,
|
||||
.buf_clear = KX132_REG_BUF_CLEAR,
|
||||
.buf_status1 = KX132_REG_BUF_STATUS_1,
|
||||
.buf_smp_lvl_mask = KX132_MASK_BUF_SMP_LVL,
|
||||
.buf_read = KX132_REG_BUF_READ,
|
||||
.inc1 = KX132_REG_INC1,
|
||||
.inc4 = KX132_REG_INC4,
|
||||
.inc5 = KX132_REG_INC5,
|
||||
.inc6 = KX132_REG_INC6,
|
||||
.xout_l = KX132_REG_XOUT_L,
|
||||
.get_fifo_bytes_available = kx132_get_fifo_bytes_available,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(kx134_chip_info, "IIO_KX022A");
|
||||
|
||||
/*
|
||||
* Despite the naming, KX132ACR-LBZ is not similar to KX132-1211 but it is
|
||||
* exact subset of KX022A. KX132ACR-LBZ is meant to be used for industrial
|
||||
|
@ -1216,6 +1250,9 @@ const struct kx022a_chip_info kx132acr_chip_info = {
|
|||
.regmap_config = &kx022a_regmap_config,
|
||||
.channels = kx022a_channels,
|
||||
.num_channels = ARRAY_SIZE(kx022a_channels),
|
||||
.scale_table = kx022a_scale_table,
|
||||
.scale_table_size = ARRAY_SIZE(kx022a_scale_table) *
|
||||
ARRAY_SIZE(kx022a_scale_table[0]),
|
||||
.fifo_length = KX022A_FIFO_LENGTH,
|
||||
.who = KX022A_REG_WHO,
|
||||
.id = KX132ACR_LBZ_ID,
|
||||
|
@ -1236,6 +1273,34 @@ const struct kx022a_chip_info kx132acr_chip_info = {
|
|||
};
|
||||
EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, "IIO_KX022A");
|
||||
|
||||
const struct kx022a_chip_info kx134acr_chip_info = {
|
||||
.name = "kx134acr-lbz",
|
||||
.regmap_config = &kx022a_regmap_config,
|
||||
.channels = kx022a_channels,
|
||||
.num_channels = ARRAY_SIZE(kx022a_channels),
|
||||
.scale_table = kx134acr_lbz_scale_table,
|
||||
.scale_table_size = ARRAY_SIZE(kx134acr_lbz_scale_table) *
|
||||
ARRAY_SIZE(kx134acr_lbz_scale_table[0]),
|
||||
.fifo_length = KX022A_FIFO_LENGTH,
|
||||
.who = KX022A_REG_WHO,
|
||||
.id = KX134ACR_LBZ_ID,
|
||||
.cntl = KX022A_REG_CNTL,
|
||||
.cntl2 = KX022A_REG_CNTL2,
|
||||
.odcntl = KX022A_REG_ODCNTL,
|
||||
.buf_cntl1 = KX022A_REG_BUF_CNTL1,
|
||||
.buf_cntl2 = KX022A_REG_BUF_CNTL2,
|
||||
.buf_clear = KX022A_REG_BUF_CLEAR,
|
||||
.buf_status1 = KX022A_REG_BUF_STATUS_1,
|
||||
.buf_read = KX022A_REG_BUF_READ,
|
||||
.inc1 = KX022A_REG_INC1,
|
||||
.inc4 = KX022A_REG_INC4,
|
||||
.inc5 = KX022A_REG_INC5,
|
||||
.inc6 = KX022A_REG_INC6,
|
||||
.xout_l = KX022A_REG_XOUT_L,
|
||||
.get_fifo_bytes_available = kx022a_get_fifo_bytes_available,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(kx134acr_chip_info, "IIO_KX022A");
|
||||
|
||||
int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info)
|
||||
{
|
||||
static const char * const regulator_names[] = {"io-vdd", "vdd"};
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#define KX022A_REG_WHO 0x0f
|
||||
#define KX022A_ID 0xc8
|
||||
#define KX132ACR_LBZ_ID 0xd8
|
||||
#define KX134ACR_LBZ_ID 0xcc
|
||||
|
||||
#define KX022A_REG_CNTL2 0x19
|
||||
#define KX022A_MASK_SRST BIT(7)
|
||||
|
@ -77,6 +78,7 @@
|
|||
|
||||
#define KX132_REG_WHO 0x13
|
||||
#define KX132_ID 0x3d
|
||||
#define KX134_1211_ID 0x46
|
||||
|
||||
#define KX132_FIFO_LENGTH 86
|
||||
|
||||
|
@ -135,6 +137,14 @@ struct kx022a_data;
|
|||
*
|
||||
* @name: name of the device
|
||||
* @regmap_config: pointer to register map configuration
|
||||
* @scale_table: An array of tables of scaling factors for
|
||||
* a supported acceleration measurement range.
|
||||
* Each table containing a single scaling
|
||||
* factor consisting of two integers. The first
|
||||
* value in a table is the integer part, and
|
||||
* the second value is the fractional part as
|
||||
* parts per billion.
|
||||
* @scale_table_size: Amount of values in tables.
|
||||
* @channels: pointer to iio_chan_spec array
|
||||
* @num_channels: number of iio_chan_spec channels
|
||||
* @fifo_length: number of 16-bit samples in a full buffer
|
||||
|
@ -161,6 +171,8 @@ struct kx022a_data;
|
|||
struct kx022a_chip_info {
|
||||
const char *name;
|
||||
const struct regmap_config *regmap_config;
|
||||
const int (*scale_table)[2];
|
||||
const int scale_table_size;
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned int num_channels;
|
||||
unsigned int fifo_length;
|
||||
|
@ -187,6 +199,8 @@ int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chi
|
|||
|
||||
extern const struct kx022a_chip_info kx022a_chip_info;
|
||||
extern const struct kx022a_chip_info kx132_chip_info;
|
||||
extern const struct kx022a_chip_info kx134_chip_info;
|
||||
extern const struct kx022a_chip_info kx132acr_chip_info;
|
||||
extern const struct kx022a_chip_info kx134acr_chip_info;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,10 +35,6 @@
|
|||
|
||||
#define AD4000_SCALE_OPTIONS 2
|
||||
|
||||
#define AD4000_TQUIET1_NS 190
|
||||
#define AD4000_TQUIET2_NS 60
|
||||
#define AD4000_TCONV_NS 320
|
||||
|
||||
#define __AD4000_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
|
@ -49,6 +45,7 @@
|
|||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\
|
||||
.scan_index = 0, \
|
||||
.scan_type = { \
|
||||
.sign = _sign, \
|
||||
.realbits = _real_bits, \
|
||||
|
@ -62,6 +59,12 @@
|
|||
__AD4000_DIFF_CHANNEL((_sign), (_real_bits), \
|
||||
((_real_bits) > 16 ? 32 : 16), (_reg_access))
|
||||
|
||||
#define AD4000_DIFF_CHANNELS(_sign, _real_bits, _reg_access) \
|
||||
{ \
|
||||
AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access), \
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1), \
|
||||
}
|
||||
|
||||
#define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access)\
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
|
@ -71,6 +74,7 @@
|
|||
BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET), \
|
||||
.info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\
|
||||
.scan_index = 0, \
|
||||
.scan_type = { \
|
||||
.sign = _sign, \
|
||||
.realbits = _real_bits, \
|
||||
|
@ -84,6 +88,12 @@
|
|||
__AD4000_PSEUDO_DIFF_CHANNEL((_sign), (_real_bits), \
|
||||
((_real_bits) > 16 ? 32 : 16), (_reg_access))
|
||||
|
||||
#define AD4000_PSEUDO_DIFF_CHANNELS(_sign, _real_bits, _reg_access) \
|
||||
{ \
|
||||
AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access), \
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1), \
|
||||
}
|
||||
|
||||
static const char * const ad4000_power_supplies[] = {
|
||||
"vdd", "vio"
|
||||
};
|
||||
|
@ -108,111 +118,280 @@ static const int ad4000_gains[] = {
|
|||
454, 909, 1000, 1900,
|
||||
};
|
||||
|
||||
struct ad4000_time_spec {
|
||||
int t_conv_ns;
|
||||
int t_quiet2_ns;
|
||||
};
|
||||
|
||||
/*
|
||||
* Same timing specifications for all of AD4000, AD4001, ..., AD4008, AD4010,
|
||||
* ADAQ4001, and ADAQ4003.
|
||||
*/
|
||||
static const struct ad4000_time_spec ad4000_t_spec = {
|
||||
.t_conv_ns = 320,
|
||||
.t_quiet2_ns = 60,
|
||||
};
|
||||
|
||||
/* AD4020, AD4021, AD4022 */
|
||||
static const struct ad4000_time_spec ad4020_t_spec = {
|
||||
.t_conv_ns = 350,
|
||||
.t_quiet2_ns = 60,
|
||||
};
|
||||
|
||||
/* AD7983, AD7984 */
|
||||
static const struct ad4000_time_spec ad7983_t_spec = {
|
||||
.t_conv_ns = 500,
|
||||
.t_quiet2_ns = 0,
|
||||
};
|
||||
|
||||
/* AD7980, AD7982 */
|
||||
static const struct ad4000_time_spec ad7980_t_spec = {
|
||||
.t_conv_ns = 800,
|
||||
.t_quiet2_ns = 0,
|
||||
};
|
||||
|
||||
/* AD7946, AD7686, AD7688, AD7988-5, AD7693 */
|
||||
static const struct ad4000_time_spec ad7686_t_spec = {
|
||||
.t_conv_ns = 1600,
|
||||
.t_quiet2_ns = 0,
|
||||
};
|
||||
|
||||
/* AD7690 */
|
||||
static const struct ad4000_time_spec ad7690_t_spec = {
|
||||
.t_conv_ns = 2100,
|
||||
.t_quiet2_ns = 0,
|
||||
};
|
||||
|
||||
/* AD7942, AD7685, AD7687 */
|
||||
static const struct ad4000_time_spec ad7687_t_spec = {
|
||||
.t_conv_ns = 3200,
|
||||
.t_quiet2_ns = 0,
|
||||
};
|
||||
|
||||
/* AD7691 */
|
||||
static const struct ad4000_time_spec ad7691_t_spec = {
|
||||
.t_conv_ns = 3700,
|
||||
.t_quiet2_ns = 0,
|
||||
};
|
||||
|
||||
/* AD7988-1 */
|
||||
static const struct ad4000_time_spec ad7988_1_t_spec = {
|
||||
.t_conv_ns = 9500,
|
||||
.t_quiet2_ns = 0,
|
||||
};
|
||||
|
||||
struct ad4000_chip_info {
|
||||
const char *dev_name;
|
||||
struct iio_chan_spec chan_spec;
|
||||
struct iio_chan_spec reg_access_chan_spec;
|
||||
struct iio_chan_spec chan_spec[2];
|
||||
struct iio_chan_spec reg_access_chan_spec[2];
|
||||
const struct ad4000_time_spec *time_spec;
|
||||
bool has_hardware_gain;
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4000_chip_info = {
|
||||
.dev_name = "ad4000",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1),
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4001_chip_info = {
|
||||
.dev_name = "ad4001",
|
||||
.chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1),
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4002_chip_info = {
|
||||
.dev_name = "ad4002",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1),
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4003_chip_info = {
|
||||
.dev_name = "ad4003",
|
||||
.chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4004_chip_info = {
|
||||
.dev_name = "ad4004",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1),
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4005_chip_info = {
|
||||
.dev_name = "ad4005",
|
||||
.chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1),
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4006_chip_info = {
|
||||
.dev_name = "ad4006",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1),
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4007_chip_info = {
|
||||
.dev_name = "ad4007",
|
||||
.chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4008_chip_info = {
|
||||
.dev_name = "ad4008",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1),
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4010_chip_info = {
|
||||
.dev_name = "ad4010",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1),
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4011_chip_info = {
|
||||
.dev_name = "ad4011",
|
||||
.chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4020_chip_info = {
|
||||
.dev_name = "ad4020",
|
||||
.chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1),
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1),
|
||||
.time_spec = &ad4020_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4021_chip_info = {
|
||||
.dev_name = "ad4021",
|
||||
.chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1),
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1),
|
||||
.time_spec = &ad4020_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad4022_chip_info = {
|
||||
.dev_name = "ad4022",
|
||||
.chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1),
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1),
|
||||
.time_spec = &ad4020_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info adaq4001_chip_info = {
|
||||
.dev_name = "adaq4001",
|
||||
.chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1),
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
.has_hardware_gain = true,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info adaq4003_chip_info = {
|
||||
.dev_name = "adaq4003",
|
||||
.chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
|
||||
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
|
||||
.time_spec = &ad4000_t_spec,
|
||||
.has_hardware_gain = true,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7685_chip_info = {
|
||||
.dev_name = "ad7685",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
|
||||
.time_spec = &ad7687_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7686_chip_info = {
|
||||
.dev_name = "ad7686",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
|
||||
.time_spec = &ad7686_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7687_chip_info = {
|
||||
.dev_name = "ad7687",
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
|
||||
.time_spec = &ad7687_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7688_chip_info = {
|
||||
.dev_name = "ad7688",
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
|
||||
.time_spec = &ad7686_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7690_chip_info = {
|
||||
.dev_name = "ad7690",
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
|
||||
.time_spec = &ad7690_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7691_chip_info = {
|
||||
.dev_name = "ad7691",
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
|
||||
.time_spec = &ad7691_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7693_chip_info = {
|
||||
.dev_name = "ad7693",
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
|
||||
.time_spec = &ad7686_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7942_chip_info = {
|
||||
.dev_name = "ad7942",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 14, 0),
|
||||
.time_spec = &ad7687_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7946_chip_info = {
|
||||
.dev_name = "ad7946",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 14, 0),
|
||||
.time_spec = &ad7686_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7980_chip_info = {
|
||||
.dev_name = "ad7980",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
|
||||
.time_spec = &ad7980_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7982_chip_info = {
|
||||
.dev_name = "ad7982",
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
|
||||
.time_spec = &ad7980_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7983_chip_info = {
|
||||
.dev_name = "ad7983",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
|
||||
.time_spec = &ad7983_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7984_chip_info = {
|
||||
.dev_name = "ad7984",
|
||||
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
|
||||
.time_spec = &ad7983_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7988_1_chip_info = {
|
||||
.dev_name = "ad7988-1",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
|
||||
.time_spec = &ad7988_1_t_spec,
|
||||
};
|
||||
|
||||
static const struct ad4000_chip_info ad7988_5_chip_info = {
|
||||
.dev_name = "ad7988-5",
|
||||
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
|
||||
.time_spec = &ad7686_t_spec,
|
||||
};
|
||||
|
||||
struct ad4000_state {
|
||||
struct spi_device *spi;
|
||||
struct gpio_desc *cnv_gpio;
|
||||
|
@ -224,6 +403,7 @@ struct ad4000_state {
|
|||
bool span_comp;
|
||||
u16 gain_milli;
|
||||
int scale_tbl[AD4000_SCALE_OPTIONS][2];
|
||||
const struct ad4000_time_spec *time_spec;
|
||||
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires the transfer buffers
|
||||
|
@ -234,7 +414,7 @@ struct ad4000_state {
|
|||
__be16 sample_buf16;
|
||||
__be32 sample_buf32;
|
||||
} data;
|
||||
s64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} scan __aligned(IIO_DMA_MINALIGN);
|
||||
u8 tx_buf[2];
|
||||
u8 rx_buf[2];
|
||||
|
@ -488,16 +668,15 @@ static const struct iio_info ad4000_info = {
|
|||
static int ad4000_prepare_3wire_mode_message(struct ad4000_state *st,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
unsigned int cnv_pulse_time = AD4000_TCONV_NS;
|
||||
struct spi_transfer *xfers = st->xfers;
|
||||
|
||||
xfers[0].cs_change = 1;
|
||||
xfers[0].cs_change_delay.value = cnv_pulse_time;
|
||||
xfers[0].cs_change_delay.value = st->time_spec->t_conv_ns;
|
||||
xfers[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
|
||||
xfers[1].rx_buf = &st->scan.data;
|
||||
xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits);
|
||||
xfers[1].delay.value = AD4000_TQUIET2_NS;
|
||||
xfers[1].delay.value = st->time_spec->t_quiet2_ns;
|
||||
xfers[1].delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
|
||||
spi_message_init_with_transfers(&st->msg, st->xfers, 2);
|
||||
|
@ -515,7 +694,6 @@ static int ad4000_prepare_3wire_mode_message(struct ad4000_state *st,
|
|||
static int ad4000_prepare_4wire_mode_message(struct ad4000_state *st,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
unsigned int cnv_to_sdi_time = AD4000_TCONV_NS;
|
||||
struct spi_transfer *xfers = st->xfers;
|
||||
|
||||
/*
|
||||
|
@ -523,7 +701,7 @@ static int ad4000_prepare_4wire_mode_message(struct ad4000_state *st,
|
|||
* going low.
|
||||
*/
|
||||
xfers[0].cs_off = 1;
|
||||
xfers[0].delay.value = cnv_to_sdi_time;
|
||||
xfers[0].delay.value = st->time_spec->t_conv_ns;
|
||||
xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
|
||||
xfers[1].rx_buf = &st->scan.data;
|
||||
|
@ -562,6 +740,7 @@ static int ad4000_probe(struct spi_device *spi)
|
|||
|
||||
st = iio_priv(indio_dev);
|
||||
st->spi = spi;
|
||||
st->time_spec = chip->time_spec;
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4000_power_supplies),
|
||||
ad4000_power_supplies);
|
||||
|
@ -591,7 +770,7 @@ static int ad4000_probe(struct spi_device *spi)
|
|||
switch (st->sdi_pin) {
|
||||
case AD4000_SDI_MOSI:
|
||||
indio_dev->info = &ad4000_reg_access_info;
|
||||
indio_dev->channels = &chip->reg_access_chan_spec;
|
||||
indio_dev->channels = chip->reg_access_chan_spec;
|
||||
|
||||
/*
|
||||
* In "3-wire mode", the ADC SDI line must be kept high when
|
||||
|
@ -603,7 +782,7 @@ static int ad4000_probe(struct spi_device *spi)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad4000_prepare_3wire_mode_message(st, indio_dev->channels);
|
||||
ret = ad4000_prepare_3wire_mode_message(st, &indio_dev->channels[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -614,16 +793,16 @@ static int ad4000_probe(struct spi_device *spi)
|
|||
break;
|
||||
case AD4000_SDI_VIO:
|
||||
indio_dev->info = &ad4000_info;
|
||||
indio_dev->channels = &chip->chan_spec;
|
||||
ret = ad4000_prepare_3wire_mode_message(st, indio_dev->channels);
|
||||
indio_dev->channels = chip->chan_spec;
|
||||
ret = ad4000_prepare_3wire_mode_message(st, &indio_dev->channels[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
case AD4000_SDI_CS:
|
||||
indio_dev->info = &ad4000_info;
|
||||
indio_dev->channels = &chip->chan_spec;
|
||||
ret = ad4000_prepare_4wire_mode_message(st, indio_dev->channels);
|
||||
indio_dev->channels = chip->chan_spec;
|
||||
ret = ad4000_prepare_4wire_mode_message(st, &indio_dev->channels[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -637,7 +816,7 @@ static int ad4000_probe(struct spi_device *spi)
|
|||
}
|
||||
|
||||
indio_dev->name = chip->dev_name;
|
||||
indio_dev->num_channels = 1;
|
||||
indio_dev->num_channels = 2;
|
||||
|
||||
ret = devm_mutex_init(dev, &st->lock);
|
||||
if (ret)
|
||||
|
@ -658,7 +837,7 @@ static int ad4000_probe(struct spi_device *spi)
|
|||
}
|
||||
}
|
||||
|
||||
ad4000_fill_scale_tbl(st, indio_dev->channels);
|
||||
ad4000_fill_scale_tbl(st, &indio_dev->channels[0]);
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
|
@ -686,6 +865,21 @@ static const struct spi_device_id ad4000_id[] = {
|
|||
{ "ad4022", (kernel_ulong_t)&ad4022_chip_info },
|
||||
{ "adaq4001", (kernel_ulong_t)&adaq4001_chip_info },
|
||||
{ "adaq4003", (kernel_ulong_t)&adaq4003_chip_info },
|
||||
{ "ad7685", (kernel_ulong_t)&ad7685_chip_info },
|
||||
{ "ad7686", (kernel_ulong_t)&ad7686_chip_info },
|
||||
{ "ad7687", (kernel_ulong_t)&ad7687_chip_info },
|
||||
{ "ad7688", (kernel_ulong_t)&ad7688_chip_info },
|
||||
{ "ad7690", (kernel_ulong_t)&ad7690_chip_info },
|
||||
{ "ad7691", (kernel_ulong_t)&ad7691_chip_info },
|
||||
{ "ad7693", (kernel_ulong_t)&ad7693_chip_info },
|
||||
{ "ad7942", (kernel_ulong_t)&ad7942_chip_info },
|
||||
{ "ad7946", (kernel_ulong_t)&ad7946_chip_info },
|
||||
{ "ad7980", (kernel_ulong_t)&ad7980_chip_info },
|
||||
{ "ad7982", (kernel_ulong_t)&ad7982_chip_info },
|
||||
{ "ad7983", (kernel_ulong_t)&ad7983_chip_info },
|
||||
{ "ad7984", (kernel_ulong_t)&ad7984_chip_info },
|
||||
{ "ad7988-1", (kernel_ulong_t)&ad7988_1_chip_info },
|
||||
{ "ad7988-5", (kernel_ulong_t)&ad7988_5_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad4000_id);
|
||||
|
@ -707,6 +901,21 @@ static const struct of_device_id ad4000_of_match[] = {
|
|||
{ .compatible = "adi,ad4022", .data = &ad4022_chip_info },
|
||||
{ .compatible = "adi,adaq4001", .data = &adaq4001_chip_info },
|
||||
{ .compatible = "adi,adaq4003", .data = &adaq4003_chip_info },
|
||||
{ .compatible = "adi,ad7685", .data = &ad7685_chip_info },
|
||||
{ .compatible = "adi,ad7686", .data = &ad7686_chip_info },
|
||||
{ .compatible = "adi,ad7687", .data = &ad7687_chip_info },
|
||||
{ .compatible = "adi,ad7688", .data = &ad7688_chip_info },
|
||||
{ .compatible = "adi,ad7690", .data = &ad7690_chip_info },
|
||||
{ .compatible = "adi,ad7691", .data = &ad7691_chip_info },
|
||||
{ .compatible = "adi,ad7693", .data = &ad7693_chip_info },
|
||||
{ .compatible = "adi,ad7942", .data = &ad7942_chip_info },
|
||||
{ .compatible = "adi,ad7946", .data = &ad7946_chip_info },
|
||||
{ .compatible = "adi,ad7980", .data = &ad7980_chip_info },
|
||||
{ .compatible = "adi,ad7982", .data = &ad7982_chip_info },
|
||||
{ .compatible = "adi,ad7983", .data = &ad7983_chip_info },
|
||||
{ .compatible = "adi,ad7984", .data = &ad7984_chip_info },
|
||||
{ .compatible = "adi,ad7988-1", .data = &ad7988_1_chip_info },
|
||||
{ .compatible = "adi,ad7988-5", .data = &ad7988_5_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad4000_of_match);
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include <dt-bindings/iio/adi,ad4695.h>
|
||||
#include <dt-bindings/iio/adc/adi,ad4695.h>
|
||||
|
||||
/* AD4695 registers */
|
||||
#define AD4695_REG_SPI_CONFIG_A 0x0000
|
||||
|
|
|
@ -95,6 +95,10 @@
|
|||
#define AD7124_MAX_CONFIGS 8
|
||||
#define AD7124_MAX_CHANNELS 16
|
||||
|
||||
/* AD7124 input sources */
|
||||
#define AD7124_INPUT_TEMPSENSOR 16
|
||||
#define AD7124_INPUT_AVSS 17
|
||||
|
||||
enum ad7124_ids {
|
||||
ID_AD7124_4,
|
||||
ID_AD7124_8,
|
||||
|
@ -360,20 +364,21 @@ static int ad7124_find_free_config_slot(struct ad7124_state *st)
|
|||
return free_cfg_slot;
|
||||
}
|
||||
|
||||
/* Only called during probe, so dev_err_probe() can be used */
|
||||
static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channel_config *cfg)
|
||||
{
|
||||
struct device *dev = &st->sd.spi->dev;
|
||||
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]);
|
||||
}
|
||||
if (IS_ERR(st->vref[refsel]))
|
||||
return dev_err_probe(dev, PTR_ERR(st->vref[refsel]),
|
||||
"Error, trying to use external voltage reference without a %s regulator.\n",
|
||||
ad7124_ref_names[refsel]);
|
||||
|
||||
cfg->vref_mv = regulator_get_voltage(st->vref[refsel]);
|
||||
/* Conversion from uV to mV */
|
||||
cfg->vref_mv /= 1000;
|
||||
|
@ -384,8 +389,7 @@ static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channe
|
|||
st->adc_control |= AD7124_ADC_CTRL_REF_EN(1);
|
||||
return 0;
|
||||
default:
|
||||
dev_err(&st->sd.spi->dev, "Invalid reference %d\n", refsel);
|
||||
return -EINVAL;
|
||||
return dev_err_probe(dev, -EINVAL, "Invalid reference %d\n", refsel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,6 +575,7 @@ static const struct ad_sigma_delta_info ad7124_sigma_delta_info = {
|
|||
.data_reg = AD7124_DATA,
|
||||
.num_slots = 8,
|
||||
.irq_flags = IRQF_TRIGGER_FALLING,
|
||||
.num_resetclks = 64,
|
||||
};
|
||||
|
||||
static int ad7124_read_raw(struct iio_dev *indio_dev,
|
||||
|
@ -588,26 +593,59 @@ static int ad7124_read_raw(struct iio_dev *indio_dev,
|
|||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
mutex_lock(&st->cfgs_lock);
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
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;
|
||||
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_TEMP:
|
||||
/*
|
||||
* According to the data sheet
|
||||
* Temperature (°C)
|
||||
* = ((Conversion − 0x800000)/13584) − 272.5
|
||||
* = (Conversion − 0x800000 - 13584 * 272.5) / 13584
|
||||
* = (Conversion − 12090248) / 13584
|
||||
* So scale with 1000/13584 to yield °mC. Reduce by 8 to
|
||||
* 125/1698.
|
||||
*/
|
||||
*val = 125;
|
||||
*val2 = 1698;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&st->cfgs_lock);
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
mutex_lock(&st->cfgs_lock);
|
||||
if (st->channels[chan->address].cfg.bipolar)
|
||||
*val = -(1 << (chan->scan_type.realbits - 1));
|
||||
else
|
||||
*val = 0;
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
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_TEMP:
|
||||
/* see calculation above */
|
||||
*val = -12090248;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&st->cfgs_lock);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
mutex_lock(&st->cfgs_lock);
|
||||
*val = st->channels[chan->address].cfg.odr;
|
||||
|
@ -751,12 +789,14 @@ static const struct iio_info ad7124_info = {
|
|||
.attrs = &ad7124_attrs_group,
|
||||
};
|
||||
|
||||
/* Only called during probe, so dev_err_probe() can be used */
|
||||
static int ad7124_soft_reset(struct ad7124_state *st)
|
||||
{
|
||||
struct device *dev = &st->sd.spi->dev;
|
||||
unsigned int readval, timeout;
|
||||
int ret;
|
||||
|
||||
ret = ad_sd_reset(&st->sd, 64);
|
||||
ret = ad_sd_reset(&st->sd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -765,7 +805,7 @@ static int ad7124_soft_reset(struct ad7124_state *st)
|
|||
do {
|
||||
ret = ad_sd_read_reg(&st->sd, AD7124_STATUS, 1, &readval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return dev_err_probe(dev, ret, "Error reading status register\n");
|
||||
|
||||
if (!(readval & AD7124_STATUS_POR_FLAG_MSK))
|
||||
return 0;
|
||||
|
@ -774,39 +814,47 @@ static int ad7124_soft_reset(struct ad7124_state *st)
|
|||
usleep_range(100, 2000);
|
||||
} while (--timeout);
|
||||
|
||||
dev_err(&st->sd.spi->dev, "Soft reset failed\n");
|
||||
|
||||
return -EIO;
|
||||
return dev_err_probe(dev, -EIO, "Soft reset failed\n");
|
||||
}
|
||||
|
||||
static int ad7124_check_chip_id(struct ad7124_state *st)
|
||||
{
|
||||
struct device *dev = &st->sd.spi->dev;
|
||||
unsigned int readval, chip_id, silicon_rev;
|
||||
int ret;
|
||||
|
||||
ret = ad_sd_read_reg(&st->sd, AD7124_ID, 1, &readval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return dev_err_probe(dev, ret, "Failure to read ID register\n");
|
||||
|
||||
chip_id = AD7124_DEVICE_ID_GET(readval);
|
||||
silicon_rev = AD7124_SILICON_REV_GET(readval);
|
||||
|
||||
if (chip_id != st->chip_info->chip_id) {
|
||||
dev_err(&st->sd.spi->dev,
|
||||
"Chip ID mismatch: expected %u, got %u\n",
|
||||
st->chip_info->chip_id, chip_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (chip_id != st->chip_info->chip_id)
|
||||
return dev_err_probe(dev, -ENODEV,
|
||||
"Chip ID mismatch: expected %u, got %u\n",
|
||||
st->chip_info->chip_id, chip_id);
|
||||
|
||||
if (silicon_rev == 0) {
|
||||
dev_err(&st->sd.spi->dev,
|
||||
"Silicon revision empty. Chip may not be present\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (silicon_rev == 0)
|
||||
return dev_err_probe(dev, -ENODEV,
|
||||
"Silicon revision empty. Chip may not be present\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Input specifiers 8 - 15 are explicitly reserved for ad7124-4
|
||||
* while they are fine for ad7124-8. Values above 31 don't fit
|
||||
* into the register field and so are invalid for sure.
|
||||
*/
|
||||
static bool ad7124_valid_input_select(unsigned int ain, const struct ad7124_chip_info *info)
|
||||
{
|
||||
if (ain >= info->num_inputs && ain < 16)
|
||||
return false;
|
||||
|
||||
return ain <= FIELD_MAX(AD7124_CHANNEL_AINM_MSK);
|
||||
}
|
||||
|
||||
static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
|
||||
struct device *dev)
|
||||
{
|
||||
|
@ -815,11 +863,23 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
|
|||
struct ad7124_channel *channels;
|
||||
struct iio_chan_spec *chan;
|
||||
unsigned int ain[2], channel = 0, tmp;
|
||||
unsigned int num_channels;
|
||||
int ret;
|
||||
|
||||
st->num_channels = device_get_child_node_count(dev);
|
||||
if (!st->num_channels)
|
||||
return dev_err_probe(dev, -ENODEV, "no channel children\n");
|
||||
num_channels = device_get_child_node_count(dev);
|
||||
|
||||
/*
|
||||
* The driver assigns each logical channel defined in the device tree
|
||||
* statically one channel register. So only accept 16 such logical
|
||||
* channels to not treat CONFIG_0 (i.e. the register following
|
||||
* CHANNEL_15) as an additional channel register. The driver could be
|
||||
* improved to lift this limitation.
|
||||
*/
|
||||
if (num_channels > AD7124_MAX_CHANNELS)
|
||||
return dev_err_probe(dev, -EINVAL, "Too many channels defined\n");
|
||||
|
||||
/* Add one for temperature */
|
||||
st->num_channels = min(num_channels + 1, AD7124_MAX_CHANNELS);
|
||||
|
||||
chan = devm_kcalloc(indio_dev->dev.parent, st->num_channels,
|
||||
sizeof(*chan), GFP_KERNEL);
|
||||
|
@ -838,16 +898,23 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
|
|||
device_for_each_child_node_scoped(dev, child) {
|
||||
ret = fwnode_property_read_u32(child, "reg", &channel);
|
||||
if (ret)
|
||||
return ret;
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to parse reg property of %pfwP\n", child);
|
||||
|
||||
if (channel >= indio_dev->num_channels)
|
||||
if (channel >= num_channels)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Channel index >= number of channels\n");
|
||||
"Channel index >= number of channels in %pfwP\n", child);
|
||||
|
||||
ret = fwnode_property_read_u32_array(child, "diff-channels",
|
||||
ain, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to parse diff-channels property of %pfwP\n", child);
|
||||
|
||||
if (!ad7124_valid_input_select(ain[0], st->chip_info) ||
|
||||
!ad7124_valid_input_select(ain[1], st->chip_info))
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"diff-channels property of %pfwP contains invalid data\n", child);
|
||||
|
||||
st->channels[channel].nr = channel;
|
||||
st->channels[channel].ain = AD7124_CHANNEL_AINP(ain[0]) |
|
||||
|
@ -874,17 +941,49 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
|
|||
chan[channel].channel2 = ain[1];
|
||||
}
|
||||
|
||||
if (num_channels < AD7124_MAX_CHANNELS) {
|
||||
st->channels[num_channels] = (struct ad7124_channel) {
|
||||
.nr = num_channels,
|
||||
.ain = AD7124_CHANNEL_AINP(AD7124_INPUT_TEMPSENSOR) |
|
||||
AD7124_CHANNEL_AINM(AD7124_INPUT_AVSS),
|
||||
.cfg = {
|
||||
.bipolar = true,
|
||||
},
|
||||
};
|
||||
|
||||
chan[num_channels] = (struct iio_chan_spec) {
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.scan_type = {
|
||||
/*
|
||||
* You might find it strange that a bipolar
|
||||
* measurement yields an unsigned value, but
|
||||
* this matches the device's manual.
|
||||
*/
|
||||
.sign = 'u',
|
||||
.realbits = 24,
|
||||
.storagebits = 32,
|
||||
.endianness = IIO_BE,
|
||||
},
|
||||
.address = num_channels,
|
||||
.scan_index = num_channels,
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7124_setup(struct ad7124_state *st)
|
||||
{
|
||||
struct device *dev = &st->sd.spi->dev;
|
||||
unsigned int fclk, power_mode;
|
||||
int i, ret;
|
||||
|
||||
fclk = clk_get_rate(st->mclk);
|
||||
if (!fclk)
|
||||
return -EINVAL;
|
||||
return dev_err_probe(dev, -EINVAL, "Failed to get mclk rate\n");
|
||||
|
||||
/* The power mode changes the master clock frequency */
|
||||
power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz,
|
||||
|
@ -893,7 +992,7 @@ static int ad7124_setup(struct ad7124_state *st)
|
|||
if (fclk != ad7124_master_clk_freq_hz[power_mode]) {
|
||||
ret = clk_set_rate(st->mclk, fclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
return dev_err_probe(dev, ret, "Failed to set mclk rate\n");
|
||||
}
|
||||
|
||||
/* Set the power mode */
|
||||
|
@ -921,7 +1020,7 @@ static int ad7124_setup(struct ad7124_state *st)
|
|||
|
||||
ret = ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return dev_err_probe(dev, ret, "Failed to setup CONTROL register\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -934,13 +1033,14 @@ static void ad7124_reg_disable(void *r)
|
|||
static int ad7124_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct ad7124_chip_info *info;
|
||||
struct device *dev = &spi->dev;
|
||||
struct ad7124_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
int i, ret;
|
||||
|
||||
info = spi_get_device_match_data(spi);
|
||||
if (!info)
|
||||
return -ENODEV;
|
||||
return dev_err_probe(dev, -ENODEV, "Failed to get match data\n");
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
|
@ -975,17 +1075,17 @@ static int ad7124_probe(struct spi_device *spi)
|
|||
|
||||
ret = regulator_enable(st->vref[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
return dev_err_probe(dev, ret, "Failed to enable regulator #%d\n", i);
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7124_reg_disable,
|
||||
st->vref[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
return dev_err_probe(dev, ret, "Failed to register disable handler for regulator #%d\n", i);
|
||||
}
|
||||
|
||||
st->mclk = devm_clk_get_enabled(&spi->dev, "mclk");
|
||||
if (IS_ERR(st->mclk))
|
||||
return PTR_ERR(st->mclk);
|
||||
return dev_err_probe(dev, PTR_ERR(st->mclk), "Failed to get mclk\n");
|
||||
|
||||
ret = ad7124_soft_reset(st);
|
||||
if (ret < 0)
|
||||
|
@ -1001,10 +1101,13 @@ static int ad7124_probe(struct spi_device *spi)
|
|||
|
||||
ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return dev_err_probe(dev, ret, "Failed to setup triggers\n");
|
||||
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
ret = devm_iio_device_register(&spi->dev, indio_dev);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to register iio device\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ad7124_of_match[] = {
|
||||
|
|
|
@ -150,6 +150,11 @@
|
|||
#define AD7173_FILTER_ODR0_MASK GENMASK(5, 0)
|
||||
#define AD7173_MAX_CONFIGS 8
|
||||
|
||||
#define AD7173_MODE_CAL_INT_ZERO 0x4 /* Internal Zero-Scale Calibration */
|
||||
#define AD7173_MODE_CAL_INT_FULL 0x5 /* Internal Full-Scale Calibration */
|
||||
#define AD7173_MODE_CAL_SYS_ZERO 0x6 /* System Zero-Scale Calibration */
|
||||
#define AD7173_MODE_CAL_SYS_FULL 0x7 /* System Full-Scale Calibration */
|
||||
|
||||
struct ad7173_device_info {
|
||||
const unsigned int *sinc5_data_rates;
|
||||
unsigned int num_sinc5_data_rates;
|
||||
|
@ -175,6 +180,7 @@ struct ad7173_device_info {
|
|||
bool has_input_buf;
|
||||
bool has_int_ref;
|
||||
bool has_ref2;
|
||||
bool has_internal_fs_calibration;
|
||||
bool higher_gpio_bits;
|
||||
u8 num_gpios;
|
||||
};
|
||||
|
@ -193,9 +199,9 @@ struct ad7173_channel_config {
|
|||
};
|
||||
|
||||
struct ad7173_channel {
|
||||
unsigned int chan_reg;
|
||||
unsigned int ain;
|
||||
struct ad7173_channel_config cfg;
|
||||
u8 syscalib_mode;
|
||||
};
|
||||
|
||||
struct ad7173_state {
|
||||
|
@ -272,6 +278,7 @@ static const struct ad7173_device_info ad4111_device_info = {
|
|||
.has_input_buf = true,
|
||||
.has_current_inputs = true,
|
||||
.has_int_ref = true,
|
||||
.has_internal_fs_calibration = true,
|
||||
.clock = 2 * HZ_PER_MHZ,
|
||||
.sinc5_data_rates = ad7173_sinc5_data_rates,
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
|
||||
|
@ -291,6 +298,7 @@ static const struct ad7173_device_info ad4112_device_info = {
|
|||
.has_input_buf = true,
|
||||
.has_current_inputs = true,
|
||||
.has_int_ref = true,
|
||||
.has_internal_fs_calibration = true,
|
||||
.clock = 2 * HZ_PER_MHZ,
|
||||
.sinc5_data_rates = ad7173_sinc5_data_rates,
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
|
||||
|
@ -326,6 +334,7 @@ static const struct ad7173_device_info ad4114_device_info = {
|
|||
.has_temp = true,
|
||||
.has_input_buf = true,
|
||||
.has_int_ref = true,
|
||||
.has_internal_fs_calibration = true,
|
||||
.clock = 2 * HZ_PER_MHZ,
|
||||
.sinc5_data_rates = ad7173_sinc5_data_rates,
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
|
||||
|
@ -343,6 +352,7 @@ static const struct ad7173_device_info ad4115_device_info = {
|
|||
.has_temp = true,
|
||||
.has_input_buf = true,
|
||||
.has_int_ref = true,
|
||||
.has_internal_fs_calibration = true,
|
||||
.clock = 8 * HZ_PER_MHZ,
|
||||
.sinc5_data_rates = ad4115_sinc5_data_rates,
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad4115_sinc5_data_rates),
|
||||
|
@ -360,6 +370,7 @@ static const struct ad7173_device_info ad4116_device_info = {
|
|||
.has_temp = true,
|
||||
.has_input_buf = true,
|
||||
.has_int_ref = true,
|
||||
.has_internal_fs_calibration = true,
|
||||
.clock = 4 * HZ_PER_MHZ,
|
||||
.sinc5_data_rates = ad4116_sinc5_data_rates,
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad4116_sinc5_data_rates),
|
||||
|
@ -505,6 +516,105 @@ static const struct regmap_config ad7173_regmap_config = {
|
|||
.read_flag_mask = BIT(6),
|
||||
};
|
||||
|
||||
enum {
|
||||
AD7173_SYSCALIB_ZERO_SCALE,
|
||||
AD7173_SYSCALIB_FULL_SCALE,
|
||||
};
|
||||
|
||||
static const char * const ad7173_syscalib_modes[] = {
|
||||
[AD7173_SYSCALIB_ZERO_SCALE] = "zero_scale",
|
||||
[AD7173_SYSCALIB_FULL_SCALE] = "full_scale",
|
||||
};
|
||||
|
||||
static int ad7173_set_syscalib_mode(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct ad7173_state *st = iio_priv(indio_dev);
|
||||
|
||||
st->channels[chan->channel].syscalib_mode = mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7173_get_syscalib_mode(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct ad7173_state *st = iio_priv(indio_dev);
|
||||
|
||||
return st->channels[chan->channel].syscalib_mode;
|
||||
}
|
||||
|
||||
static ssize_t ad7173_write_syscalib(struct iio_dev *indio_dev,
|
||||
uintptr_t private,
|
||||
const struct iio_chan_spec *chan,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct ad7173_state *st = iio_priv(indio_dev);
|
||||
bool sys_calib;
|
||||
int ret, mode;
|
||||
|
||||
ret = kstrtobool(buf, &sys_calib);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mode = st->channels[chan->channel].syscalib_mode;
|
||||
if (sys_calib) {
|
||||
if (mode == AD7173_SYSCALIB_ZERO_SCALE)
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_ZERO,
|
||||
chan->address);
|
||||
else
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_FULL,
|
||||
chan->address);
|
||||
}
|
||||
|
||||
return ret ? : len;
|
||||
}
|
||||
|
||||
static const struct iio_enum ad7173_syscalib_mode_enum = {
|
||||
.items = ad7173_syscalib_modes,
|
||||
.num_items = ARRAY_SIZE(ad7173_syscalib_modes),
|
||||
.set = ad7173_set_syscalib_mode,
|
||||
.get = ad7173_get_syscalib_mode
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info ad7173_calibsys_ext_info[] = {
|
||||
{
|
||||
.name = "sys_calibration",
|
||||
.write = ad7173_write_syscalib,
|
||||
.shared = IIO_SEPARATE,
|
||||
},
|
||||
IIO_ENUM("sys_calibration_mode", IIO_SEPARATE,
|
||||
&ad7173_syscalib_mode_enum),
|
||||
IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE,
|
||||
&ad7173_syscalib_mode_enum),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int ad7173_calibrate_all(struct ad7173_state *st, struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < st->num_channels; i++) {
|
||||
if (indio_dev->channels[i].type != IIO_VOLTAGE)
|
||||
continue;
|
||||
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_ZERO, st->channels[i].ain);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (st->info->has_internal_fs_calibration) {
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_FULL,
|
||||
st->channels[i].ain);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
|
||||
unsigned int offset, unsigned int *reg,
|
||||
unsigned int *mask)
|
||||
|
@ -764,6 +874,7 @@ static struct ad_sigma_delta_info ad7173_sigma_delta_info = {
|
|||
.read_mask = BIT(6),
|
||||
.status_ch_mask = GENMASK(3, 0),
|
||||
.data_reg = AD7173_REG_DATA,
|
||||
.num_resetclks = 64,
|
||||
};
|
||||
|
||||
static int ad7173_setup(struct iio_dev *indio_dev)
|
||||
|
@ -801,6 +912,10 @@ static int ad7173_setup(struct iio_dev *indio_dev)
|
|||
if (!st->config_cnts)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ad7173_calibrate_all(st, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* All channels are enabled by default after a reset */
|
||||
return ad7173_disable_all(&st->sd);
|
||||
}
|
||||
|
@ -1023,6 +1138,7 @@ static const struct iio_chan_spec ad7173_channel_template = {
|
|||
.storagebits = 32,
|
||||
.endianness = IIO_BE,
|
||||
},
|
||||
.ext_info = ad7173_calibsys_ext_info,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7173_temp_iio_channel_template = {
|
||||
|
@ -1316,7 +1432,6 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
|
|||
chan->address = chan_index;
|
||||
chan->scan_index = chan_index;
|
||||
chan->channel = ain[0];
|
||||
chan_st_priv->chan_reg = chan_index;
|
||||
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
|
||||
chan_st_priv->cfg.odr = 0;
|
||||
|
||||
|
|
|
@ -361,6 +361,7 @@ static const struct ad_sigma_delta_info ad7192_sigma_delta_info = {
|
|||
.status_ch_mask = GENMASK(3, 0),
|
||||
.num_slots = 4,
|
||||
.irq_flags = IRQF_TRIGGER_FALLING,
|
||||
.num_resetclks = 40,
|
||||
};
|
||||
|
||||
static const struct ad_sigma_delta_info ad7194_sigma_delta_info = {
|
||||
|
@ -373,6 +374,7 @@ static const struct ad_sigma_delta_info ad7194_sigma_delta_info = {
|
|||
.read_mask = BIT(6),
|
||||
.status_ch_mask = GENMASK(3, 0),
|
||||
.irq_flags = IRQF_TRIGGER_FALLING,
|
||||
.num_resetclks = 40,
|
||||
};
|
||||
|
||||
static const struct ad_sd_calib_data ad7192_calib_arr[8] = {
|
||||
|
@ -565,7 +567,7 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev)
|
|||
int i, ret, id;
|
||||
|
||||
/* reset the serial interface */
|
||||
ret = ad_sd_reset(&st->sd, 48);
|
||||
ret = ad_sd_reset(&st->sd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
usleep_range(500, 1000); /* Wait for at least 500us */
|
||||
|
|
|
@ -477,12 +477,12 @@ static int devm_ad7625_pwm_get(struct device *dev,
|
|||
ref_clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(ref_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(ref_clk),
|
||||
"failed to get ref_clk");
|
||||
"failed to get ref_clk\n");
|
||||
|
||||
ref_clk_rate_hz = clk_get_rate(ref_clk);
|
||||
if (!ref_clk_rate_hz)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"failed to get ref_clk rate");
|
||||
"failed to get ref_clk rate\n");
|
||||
|
||||
st->ref_clk_rate_hz = ref_clk_rate_hz;
|
||||
|
||||
|
@ -533,7 +533,7 @@ static int devm_ad7625_regulator_setup(struct device *dev,
|
|||
|
||||
if (!st->info->has_internal_vref && !st->have_refin && !ref_mv)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Need either REFIN or REF");
|
||||
"Need either REFIN or REF\n");
|
||||
|
||||
if (st->have_refin && ref_mv)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
|
@ -623,7 +623,7 @@ static int ad7625_probe(struct platform_device *pdev)
|
|||
st->back = devm_iio_backend_get(dev, NULL);
|
||||
if (IS_ERR(st->back))
|
||||
return dev_err_probe(dev, PTR_ERR(st->back),
|
||||
"failed to get IIO backend");
|
||||
"failed to get IIO backend\n");
|
||||
|
||||
ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
|
||||
if (ret)
|
||||
|
|
|
@ -254,6 +254,7 @@ static const struct ad_sigma_delta_info ad7791_sigma_delta_info = {
|
|||
.addr_shift = 4,
|
||||
.read_mask = BIT(3),
|
||||
.irq_flags = IRQF_TRIGGER_FALLING,
|
||||
.num_resetclks = 32,
|
||||
};
|
||||
|
||||
static int ad7791_read_raw(struct iio_dev *indio_dev,
|
||||
|
|
|
@ -206,6 +206,7 @@ static const struct ad_sigma_delta_info ad7793_sigma_delta_info = {
|
|||
.addr_shift = 3,
|
||||
.read_mask = BIT(6),
|
||||
.irq_flags = IRQF_TRIGGER_FALLING,
|
||||
.num_resetclks = 32,
|
||||
};
|
||||
|
||||
static const struct ad_sd_calib_data ad7793_calib_arr[6] = {
|
||||
|
@ -265,7 +266,7 @@ static int ad7793_setup(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
|
||||
/* reset the serial interface */
|
||||
ret = ad_sd_reset(&st->sd, 32);
|
||||
ret = ad_sd_reset(&st->sd);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
usleep_range(500, 2000); /* Wait for at least 500us */
|
||||
|
|
|
@ -75,7 +75,7 @@ struct ad7944_adc {
|
|||
u16 u16;
|
||||
u32 u32;
|
||||
} raw;
|
||||
u64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} sample __aligned(IIO_DMA_MINALIGN);
|
||||
};
|
||||
|
||||
|
|
|
@ -29,8 +29,11 @@
|
|||
#define AD_SD_COMM_CHAN_MASK 0x3
|
||||
|
||||
#define AD_SD_REG_COMM 0x00
|
||||
#define AD_SD_REG_STATUS 0x00
|
||||
#define AD_SD_REG_DATA 0x03
|
||||
|
||||
#define AD_SD_REG_STATUS_RDY 0x80
|
||||
|
||||
/**
|
||||
* ad_sd_set_comm() - Set communications register
|
||||
*
|
||||
|
@ -109,7 +112,7 @@ static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
|
|||
}, {
|
||||
.rx_buf = val,
|
||||
.len = size,
|
||||
.cs_change = sigma_delta->bus_locked,
|
||||
.cs_change = sigma_delta->keep_cs_asserted,
|
||||
},
|
||||
};
|
||||
struct spi_message m;
|
||||
|
@ -178,13 +181,12 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_read_reg, "IIO_AD_SIGMA_DELTA");
|
|||
* ad_sd_reset() - Reset the serial interface
|
||||
*
|
||||
* @sigma_delta: The sigma delta device
|
||||
* @reset_length: Number of SCLKs with DIN = 1
|
||||
*
|
||||
* Returns 0 on success, an error code otherwise.
|
||||
**/
|
||||
int ad_sd_reset(struct ad_sigma_delta *sigma_delta,
|
||||
unsigned int reset_length)
|
||||
int ad_sd_reset(struct ad_sigma_delta *sigma_delta)
|
||||
{
|
||||
unsigned int reset_length = sigma_delta->info->num_resetclks;
|
||||
uint8_t *buf;
|
||||
unsigned int size;
|
||||
int ret;
|
||||
|
@ -202,6 +204,107 @@ int ad_sd_reset(struct ad_sigma_delta *sigma_delta,
|
|||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ad_sd_reset, "IIO_AD_SIGMA_DELTA");
|
||||
|
||||
static bool ad_sd_disable_irq(struct ad_sigma_delta *sigma_delta)
|
||||
{
|
||||
guard(spinlock_irqsave)(&sigma_delta->irq_lock);
|
||||
|
||||
/* It's already off, return false to indicate nothing was changed */
|
||||
if (sigma_delta->irq_dis)
|
||||
return false;
|
||||
|
||||
sigma_delta->irq_dis = true;
|
||||
disable_irq_nosync(sigma_delta->irq_line);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ad_sd_enable_irq(struct ad_sigma_delta *sigma_delta)
|
||||
{
|
||||
guard(spinlock_irqsave)(&sigma_delta->irq_lock);
|
||||
|
||||
sigma_delta->irq_dis = false;
|
||||
enable_irq(sigma_delta->irq_line);
|
||||
}
|
||||
|
||||
#define AD_SD_CLEAR_DATA_BUFLEN 9
|
||||
|
||||
/* Called with `sigma_delta->bus_locked == true` only. */
|
||||
static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta)
|
||||
{
|
||||
bool pending_event;
|
||||
unsigned int data_read_len = BITS_TO_BYTES(sigma_delta->info->num_resetclks);
|
||||
u8 *data;
|
||||
struct spi_transfer t[] = {
|
||||
{
|
||||
.len = 1,
|
||||
}, {
|
||||
.len = data_read_len,
|
||||
}
|
||||
};
|
||||
struct spi_message m;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Read R̅D̅Y̅ pin (if possible) or status register to check if there is an
|
||||
* old event.
|
||||
*/
|
||||
if (sigma_delta->rdy_gpiod) {
|
||||
pending_event = gpiod_get_value(sigma_delta->rdy_gpiod);
|
||||
} else {
|
||||
unsigned int status_reg;
|
||||
|
||||
ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_STATUS, 1, &status_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pending_event = !(status_reg & AD_SD_REG_STATUS_RDY);
|
||||
}
|
||||
|
||||
if (!pending_event)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* In general the size of the data register is unknown. It varies from
|
||||
* device to device, might be one byte longer if CONTROL.DATA_STATUS is
|
||||
* set and even varies on some devices depending on which input is
|
||||
* selected. So send one byte to start reading the data register and
|
||||
* then just clock for some bytes with DIN (aka MOSI) high to not
|
||||
* confuse the register access state machine after the data register was
|
||||
* completely read. Note however that the sequence length must be
|
||||
* shorter than the reset procedure.
|
||||
*/
|
||||
|
||||
data = kzalloc(data_read_len + 1, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
spi_message_init(&m);
|
||||
if (sigma_delta->info->has_registers) {
|
||||
unsigned int data_reg = sigma_delta->info->data_reg ?: AD_SD_REG_DATA;
|
||||
|
||||
data[0] = data_reg << sigma_delta->info->addr_shift;
|
||||
data[0] |= sigma_delta->info->read_mask;
|
||||
data[0] |= sigma_delta->comm;
|
||||
t[0].tx_buf = data;
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
}
|
||||
|
||||
/*
|
||||
* The first transferred byte is part of the real data register,
|
||||
* so this doesn't need to be 0xff. In the remaining
|
||||
* `data_read_len - 1` bytes are less than $num_resetclks ones.
|
||||
*/
|
||||
t[1].tx_buf = data + 1;
|
||||
data[1] = 0x00;
|
||||
memset(data + 2, 0xff, data_read_len - 1);
|
||||
spi_message_add_tail(&t[1], &m);
|
||||
|
||||
ret = spi_sync_locked(sigma_delta->spi, &m);
|
||||
|
||||
kfree(data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
|
||||
unsigned int mode, unsigned int channel)
|
||||
{
|
||||
|
@ -217,16 +320,18 @@ int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
|
|||
sigma_delta->keep_cs_asserted = true;
|
||||
reinit_completion(&sigma_delta->completion);
|
||||
|
||||
ret = ad_sigma_delta_clear_pending_event(sigma_delta);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = ad_sigma_delta_set_mode(sigma_delta, mode);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
sigma_delta->irq_dis = false;
|
||||
enable_irq(sigma_delta->irq_line);
|
||||
ad_sd_enable_irq(sigma_delta);
|
||||
time_left = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ);
|
||||
if (time_left == 0) {
|
||||
sigma_delta->irq_dis = true;
|
||||
disable_irq_nosync(sigma_delta->irq_line);
|
||||
ad_sd_disable_irq(sigma_delta);
|
||||
ret = -EIO;
|
||||
} else {
|
||||
ret = 0;
|
||||
|
@ -292,10 +397,13 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
|
|||
sigma_delta->keep_cs_asserted = true;
|
||||
reinit_completion(&sigma_delta->completion);
|
||||
|
||||
ret = ad_sigma_delta_clear_pending_event(sigma_delta);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
|
||||
|
||||
sigma_delta->irq_dis = false;
|
||||
enable_irq(sigma_delta->irq_line);
|
||||
ad_sd_enable_irq(sigma_delta);
|
||||
ret = wait_for_completion_interruptible_timeout(
|
||||
&sigma_delta->completion, HZ);
|
||||
|
||||
|
@ -314,14 +422,13 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
|
|||
&raw_sample);
|
||||
|
||||
out:
|
||||
if (!sigma_delta->irq_dis) {
|
||||
disable_irq_nosync(sigma_delta->irq_line);
|
||||
sigma_delta->irq_dis = true;
|
||||
}
|
||||
ad_sd_disable_irq(sigma_delta);
|
||||
|
||||
sigma_delta->keep_cs_asserted = false;
|
||||
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
|
||||
ad_sigma_delta_disable_one(sigma_delta, chan->address);
|
||||
|
||||
out_unlock:
|
||||
sigma_delta->keep_cs_asserted = false;
|
||||
sigma_delta->bus_locked = false;
|
||||
spi_bus_unlock(sigma_delta->spi->controller);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
|
@ -392,12 +499,15 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
|
|||
sigma_delta->bus_locked = true;
|
||||
sigma_delta->keep_cs_asserted = true;
|
||||
|
||||
ret = ad_sigma_delta_clear_pending_event(sigma_delta);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
|
||||
ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
|
||||
sigma_delta->irq_dis = false;
|
||||
enable_irq(sigma_delta->irq_line);
|
||||
ad_sd_enable_irq(sigma_delta);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -414,10 +524,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
|
|||
reinit_completion(&sigma_delta->completion);
|
||||
wait_for_completion_timeout(&sigma_delta->completion, HZ);
|
||||
|
||||
if (!sigma_delta->irq_dis) {
|
||||
disable_irq_nosync(sigma_delta->irq_line);
|
||||
sigma_delta->irq_dis = true;
|
||||
}
|
||||
ad_sd_disable_irq(sigma_delta);
|
||||
|
||||
sigma_delta->keep_cs_asserted = false;
|
||||
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
|
||||
|
@ -516,8 +623,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
|
|||
|
||||
irq_handled:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
sigma_delta->irq_dis = false;
|
||||
enable_irq(sigma_delta->irq_line);
|
||||
ad_sd_enable_irq(sigma_delta);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -539,12 +645,31 @@ static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private)
|
|||
{
|
||||
struct ad_sigma_delta *sigma_delta = private;
|
||||
|
||||
complete(&sigma_delta->completion);
|
||||
disable_irq_nosync(irq);
|
||||
sigma_delta->irq_dis = true;
|
||||
iio_trigger_poll(sigma_delta->trig);
|
||||
/*
|
||||
* AD7124 and a few others use the same physical line for interrupt
|
||||
* reporting (R̅D̅Y̅) and MISO.
|
||||
* As MISO toggles when reading a register, this likely results in a
|
||||
* pending interrupt. This has two consequences: a) The irq might
|
||||
* trigger immediately after it's enabled even though the conversion
|
||||
* isn't done yet; and b) checking the STATUS register's R̅D̅Y̅ flag is
|
||||
* off-limits as reading that would trigger another irq event.
|
||||
*
|
||||
* So read the MOSI line as GPIO (if available) and only trigger the irq
|
||||
* if the line is active. Without such a GPIO assume this is a valid
|
||||
* interrupt.
|
||||
*
|
||||
* Also as disable_irq_nosync() is used to disable the irq, only act if
|
||||
* the irq wasn't disabled before.
|
||||
*/
|
||||
if ((!sigma_delta->rdy_gpiod || gpiod_get_value(sigma_delta->rdy_gpiod)) &&
|
||||
ad_sd_disable_irq(sigma_delta)) {
|
||||
complete(&sigma_delta->completion);
|
||||
iio_trigger_poll(sigma_delta->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -674,11 +799,24 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
spin_lock_init(&sigma_delta->irq_lock);
|
||||
|
||||
if (info->irq_line)
|
||||
sigma_delta->irq_line = info->irq_line;
|
||||
else
|
||||
sigma_delta->irq_line = spi->irq;
|
||||
|
||||
sigma_delta->rdy_gpiod = devm_gpiod_get_optional(&spi->dev, "rdy", GPIOD_IN);
|
||||
if (IS_ERR(sigma_delta->rdy_gpiod))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(sigma_delta->rdy_gpiod),
|
||||
"Failed to find rdy gpio\n");
|
||||
|
||||
if (sigma_delta->rdy_gpiod && !sigma_delta->irq_line) {
|
||||
sigma_delta->irq_line = gpiod_to_irq(sigma_delta->rdy_gpiod);
|
||||
if (sigma_delta->irq_line < 0)
|
||||
return sigma_delta->irq_line;
|
||||
}
|
||||
|
||||
iio_device_set_drvdata(indio_dev, sigma_delta);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -66,8 +66,6 @@ struct dln2_adc {
|
|||
/* Demux table */
|
||||
unsigned int demux_count;
|
||||
struct dln2_adc_demux_table demux[DLN2_ADC_MAX_CHANNELS];
|
||||
/* Precomputed timestamp padding offset and length */
|
||||
unsigned int ts_pad_offset, ts_pad_length;
|
||||
};
|
||||
|
||||
struct dln2_adc_port_chan {
|
||||
|
@ -111,8 +109,6 @@ static void dln2_adc_update_demux(struct dln2_adc *dln2)
|
|||
if (iio_get_masklength(indio_dev) &&
|
||||
(*indio_dev->active_scan_mask & 0xff) == 0xff) {
|
||||
dln2_adc_add_demux(dln2, 0, 0, 16);
|
||||
dln2->ts_pad_offset = 0;
|
||||
dln2->ts_pad_length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -127,16 +123,6 @@ static void dln2_adc_update_demux(struct dln2_adc *dln2)
|
|||
out_loc += 2;
|
||||
in_loc += 2;
|
||||
}
|
||||
|
||||
if (indio_dev->scan_timestamp) {
|
||||
size_t ts_offset = indio_dev->scan_bytes / sizeof(int64_t) - 1;
|
||||
|
||||
dln2->ts_pad_offset = out_loc;
|
||||
dln2->ts_pad_length = ts_offset * sizeof(int64_t) - out_loc;
|
||||
} else {
|
||||
dln2->ts_pad_offset = 0;
|
||||
dln2->ts_pad_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int dln2_adc_get_chan_count(struct dln2_adc *dln2)
|
||||
|
@ -494,6 +480,8 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p)
|
|||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
/* Demux operation */
|
||||
for (i = 0; i < dln2->demux_count; ++i) {
|
||||
t = &dln2->demux[i];
|
||||
|
@ -501,11 +489,6 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p)
|
|||
(void *)dev_data.values + t->from, t->length);
|
||||
}
|
||||
|
||||
/* Zero padding space between values and timestamp */
|
||||
if (dln2->ts_pad_length)
|
||||
memset((void *)data.values + dln2->ts_pad_offset,
|
||||
0, dln2->ts_pad_length);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ struct ina2xx_chip_info {
|
|||
/* data buffer needs space for channel data and timestamp */
|
||||
struct {
|
||||
u16 chan[4];
|
||||
u64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
};
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ struct max1118 {
|
|||
/* Ensure natural alignment of buffer elements */
|
||||
struct {
|
||||
u8 channels[2];
|
||||
s64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
|
||||
u8 data __aligned(IIO_DMA_MINALIGN);
|
||||
|
|
|
@ -143,7 +143,7 @@ struct max11410_state {
|
|||
int irq;
|
||||
struct {
|
||||
u32 data __aligned(IIO_DMA_MINALIGN);
|
||||
s64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
};
|
||||
|
||||
|
|
|
@ -161,6 +161,7 @@ struct max1363_chip_info {
|
|||
* @vref_uv: Actual (external or internal) reference voltage
|
||||
* @send: function used to send data to the chip
|
||||
* @recv: function used to receive data from the chip
|
||||
* @data: buffer to store channel data and timestamp
|
||||
*/
|
||||
struct max1363_state {
|
||||
struct i2c_client *client;
|
||||
|
@ -186,6 +187,10 @@ struct max1363_state {
|
|||
const char *buf, int count);
|
||||
int (*recv)(const struct i2c_client *client,
|
||||
char *buf, int count);
|
||||
struct {
|
||||
u8 buf[MAX1363_MAX_CHANNELS * 2];
|
||||
aligned_s64 ts;
|
||||
} data;
|
||||
};
|
||||
|
||||
#define MAX1363_MODE_SINGLE(_num, _mask) { \
|
||||
|
@ -1462,22 +1467,10 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
|
|||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct max1363_state *st = iio_priv(indio_dev);
|
||||
__u8 *rxbuf;
|
||||
int b_sent;
|
||||
size_t d_size;
|
||||
unsigned long numvals = bitmap_weight(st->current_mode->modemask,
|
||||
MAX1363_MAX_CHANNELS);
|
||||
|
||||
/* Ensure the timestamp is 8 byte aligned */
|
||||
if (st->chip_info->bits != 8)
|
||||
d_size = numvals*2;
|
||||
else
|
||||
d_size = numvals;
|
||||
if (indio_dev->scan_timestamp) {
|
||||
d_size += sizeof(s64);
|
||||
if (d_size % sizeof(s64))
|
||||
d_size += sizeof(s64) - (d_size % sizeof(s64));
|
||||
}
|
||||
/* Monitor mode prevents reading. Whilst not currently implemented
|
||||
* might as well have this test in here in the meantime as it does
|
||||
* no harm.
|
||||
|
@ -1485,21 +1478,16 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
|
|||
if (numvals == 0)
|
||||
goto done;
|
||||
|
||||
rxbuf = kmalloc(d_size, GFP_KERNEL);
|
||||
if (rxbuf == NULL)
|
||||
goto done;
|
||||
if (st->chip_info->bits != 8)
|
||||
b_sent = st->recv(st->client, rxbuf, numvals * 2);
|
||||
b_sent = st->recv(st->client, st->data.buf, numvals * 2);
|
||||
else
|
||||
b_sent = st->recv(st->client, rxbuf, numvals);
|
||||
b_sent = st->recv(st->client, st->data.buf, numvals);
|
||||
if (b_sent < 0)
|
||||
goto done_free;
|
||||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, rxbuf,
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &st->data,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done_free:
|
||||
kfree(rxbuf);
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ struct mcp3911 {
|
|||
const struct mcp3911_chip_info *chip;
|
||||
struct {
|
||||
u32 channels[MCP39XX_MAX_NUM_CHANNELS];
|
||||
s64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
|
||||
u8 tx_buf __aligned(IIO_DMA_MINALIGN);
|
||||
|
|
|
@ -155,10 +155,10 @@
|
|||
*/
|
||||
#define MESON_SAR_ADC_REG11 0x2c
|
||||
#define MESON_SAR_ADC_REG11_BANDGAP_EN BIT(13)
|
||||
#define MESON_SAR_ADC_REG11_CMV_SEL BIT(6)
|
||||
#define MESON_SAR_ADC_REG11_VREF_VOLTAGE BIT(5)
|
||||
#define MESON_SAR_ADC_REG11_EOC BIT(1)
|
||||
#define MESON_SAR_ADC_REG11_VREF_SEL BIT(0)
|
||||
#define MESON_SAR_ADC_REG11_CMV_SEL BIT(6)
|
||||
#define MESON_SAR_ADC_REG11_VREF_VOLTAGE BIT(5)
|
||||
#define MESON_SAR_ADC_REG11_EOC BIT(1)
|
||||
#define MESON_SAR_ADC_REG11_VREF_SEL BIT(0)
|
||||
|
||||
#define MESON_SAR_ADC_REG13 0x34
|
||||
#define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8)
|
||||
|
@ -315,19 +315,17 @@ static const struct iio_chan_spec meson_sar_adc_and_temp_iio_channels[] = {
|
|||
struct meson_sar_adc_param {
|
||||
bool has_bl30_integration;
|
||||
unsigned long clock_rate;
|
||||
u32 bandgap_reg;
|
||||
unsigned int resolution;
|
||||
const struct regmap_config *regmap_config;
|
||||
u8 temperature_trimming_bits;
|
||||
unsigned int temperature_multiplier;
|
||||
unsigned int temperature_divider;
|
||||
u8 disable_ring_counter;
|
||||
bool has_reg11;
|
||||
bool has_vref_select;
|
||||
u8 vref_select;
|
||||
u8 cmv_select;
|
||||
u8 adc_eoc;
|
||||
enum meson_sar_adc_vref_sel vref_volatge;
|
||||
enum meson_sar_adc_vref_sel vref_voltage;
|
||||
};
|
||||
|
||||
struct meson_sar_adc_data {
|
||||
|
@ -976,7 +974,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
|
|||
MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN,
|
||||
regval);
|
||||
|
||||
if (priv->param->has_reg11) {
|
||||
if (priv->param->regmap_config->max_register >= MESON_SAR_ADC_REG11) {
|
||||
regval = FIELD_PREP(MESON_SAR_ADC_REG11_EOC, priv->param->adc_eoc);
|
||||
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
|
||||
MESON_SAR_ADC_REG11_EOC, regval);
|
||||
|
@ -989,7 +987,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
|
|||
}
|
||||
|
||||
regval = FIELD_PREP(MESON_SAR_ADC_REG11_VREF_VOLTAGE,
|
||||
priv->param->vref_volatge);
|
||||
priv->param->vref_voltage);
|
||||
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
|
||||
MESON_SAR_ADC_REG11_VREF_VOLTAGE, regval);
|
||||
|
||||
|
@ -1013,16 +1011,15 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
|
|||
static void meson_sar_adc_set_bandgap(struct iio_dev *indio_dev, bool on_off)
|
||||
{
|
||||
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
|
||||
const struct meson_sar_adc_param *param = priv->param;
|
||||
u32 enable_mask;
|
||||
|
||||
if (param->bandgap_reg == MESON_SAR_ADC_REG11)
|
||||
enable_mask = MESON_SAR_ADC_REG11_BANDGAP_EN;
|
||||
if (priv->param->regmap_config->max_register >= MESON_SAR_ADC_REG11)
|
||||
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
|
||||
MESON_SAR_ADC_REG11_BANDGAP_EN,
|
||||
on_off ? MESON_SAR_ADC_REG11_BANDGAP_EN : 0);
|
||||
else
|
||||
enable_mask = MESON_SAR_ADC_DELTA_10_TS_VBG_EN;
|
||||
|
||||
regmap_update_bits(priv->regmap, param->bandgap_reg, enable_mask,
|
||||
on_off ? enable_mask : 0);
|
||||
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
|
||||
MESON_SAR_ADC_DELTA_10_TS_VBG_EN,
|
||||
on_off ? MESON_SAR_ADC_DELTA_10_TS_VBG_EN : 0);
|
||||
}
|
||||
|
||||
static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
|
||||
|
@ -1186,7 +1183,6 @@ static const struct iio_info meson_sar_adc_iio_info = {
|
|||
static const struct meson_sar_adc_param meson_sar_adc_meson8_param = {
|
||||
.has_bl30_integration = false,
|
||||
.clock_rate = 1150000,
|
||||
.bandgap_reg = MESON_SAR_ADC_DELTA_10,
|
||||
.regmap_config = &meson_sar_adc_regmap_config_meson8,
|
||||
.resolution = 10,
|
||||
.temperature_trimming_bits = 4,
|
||||
|
@ -1197,7 +1193,6 @@ static const struct meson_sar_adc_param meson_sar_adc_meson8_param = {
|
|||
static const struct meson_sar_adc_param meson_sar_adc_meson8b_param = {
|
||||
.has_bl30_integration = false,
|
||||
.clock_rate = 1150000,
|
||||
.bandgap_reg = MESON_SAR_ADC_DELTA_10,
|
||||
.regmap_config = &meson_sar_adc_regmap_config_meson8,
|
||||
.resolution = 10,
|
||||
.temperature_trimming_bits = 5,
|
||||
|
@ -1208,35 +1203,29 @@ static const struct meson_sar_adc_param meson_sar_adc_meson8b_param = {
|
|||
static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = {
|
||||
.has_bl30_integration = true,
|
||||
.clock_rate = 1200000,
|
||||
.bandgap_reg = MESON_SAR_ADC_REG11,
|
||||
.regmap_config = &meson_sar_adc_regmap_config_gxbb,
|
||||
.resolution = 10,
|
||||
.has_reg11 = true,
|
||||
.vref_volatge = 1,
|
||||
.vref_voltage = 1,
|
||||
.cmv_select = 1,
|
||||
};
|
||||
|
||||
static const struct meson_sar_adc_param meson_sar_adc_gxl_param = {
|
||||
.has_bl30_integration = true,
|
||||
.clock_rate = 1200000,
|
||||
.bandgap_reg = MESON_SAR_ADC_REG11,
|
||||
.regmap_config = &meson_sar_adc_regmap_config_gxbb,
|
||||
.resolution = 12,
|
||||
.disable_ring_counter = 1,
|
||||
.has_reg11 = true,
|
||||
.vref_volatge = 1,
|
||||
.vref_voltage = 1,
|
||||
.cmv_select = 1,
|
||||
};
|
||||
|
||||
static const struct meson_sar_adc_param meson_sar_adc_axg_param = {
|
||||
.has_bl30_integration = true,
|
||||
.clock_rate = 1200000,
|
||||
.bandgap_reg = MESON_SAR_ADC_REG11,
|
||||
.regmap_config = &meson_sar_adc_regmap_config_gxbb,
|
||||
.resolution = 12,
|
||||
.disable_ring_counter = 1,
|
||||
.has_reg11 = true,
|
||||
.vref_volatge = 1,
|
||||
.vref_voltage = 1,
|
||||
.has_vref_select = true,
|
||||
.vref_select = VREF_VDDA,
|
||||
.cmv_select = 1,
|
||||
|
@ -1245,11 +1234,9 @@ static const struct meson_sar_adc_param meson_sar_adc_axg_param = {
|
|||
static const struct meson_sar_adc_param meson_sar_adc_g12a_param = {
|
||||
.has_bl30_integration = false,
|
||||
.clock_rate = 1200000,
|
||||
.bandgap_reg = MESON_SAR_ADC_REG11,
|
||||
.regmap_config = &meson_sar_adc_regmap_config_gxbb,
|
||||
.resolution = 12,
|
||||
.disable_ring_counter = 1,
|
||||
.has_reg11 = true,
|
||||
.adc_eoc = 1,
|
||||
.has_vref_select = true,
|
||||
.vref_select = VREF_VDDA,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
|
@ -67,6 +68,14 @@ enum pac1921_mxsl {
|
|||
#define PAC1921_DEFAULT_DI_GAIN 0 /* 2^(value): 1x gain (HW default) */
|
||||
#define PAC1921_DEFAULT_NUM_SAMPLES 0 /* 2^(value): 1 sample (HW default) */
|
||||
|
||||
#define PAC1921_ACPI_GET_uOHMS_VALS 0
|
||||
#define PAC1921_ACPI_GET_LABEL 1
|
||||
|
||||
/* f7bb9932-86ee-4516-a236-7a7a742e55cb */
|
||||
static const guid_t pac1921_guid =
|
||||
GUID_INIT(0xf7bb9932, 0x86ee, 0x4516, 0xa2,
|
||||
0x36, 0x7a, 0x7a, 0x74, 0x2e, 0x55, 0xcb);
|
||||
|
||||
/*
|
||||
* Pre-computed scale factors for BUS voltage
|
||||
* format: IIO_VAL_INT_PLUS_NANO
|
||||
|
@ -200,7 +209,7 @@ struct pac1921_priv {
|
|||
|
||||
struct {
|
||||
u16 chan[PAC1921_NUM_MEAS_CHANS];
|
||||
s64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} scan;
|
||||
};
|
||||
|
||||
|
@ -782,7 +791,7 @@ static ssize_t pac1921_write_shunt_resistor(struct iio_dev *indio_dev,
|
|||
const char *buf, size_t len)
|
||||
{
|
||||
struct pac1921_priv *priv = iio_priv(indio_dev);
|
||||
u64 rshunt_uohm;
|
||||
u32 rshunt_uohm;
|
||||
int val, val_fract;
|
||||
int ret;
|
||||
|
||||
|
@ -793,10 +802,17 @@ static ssize_t pac1921_write_shunt_resistor(struct iio_dev *indio_dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
rshunt_uohm = val * MICRO + val_fract;
|
||||
if (rshunt_uohm == 0 || rshunt_uohm > INT_MAX)
|
||||
/*
|
||||
* This check validates the shunt is not zero and does not surpass
|
||||
* INT_MAX. The check is done before calculating in order to avoid
|
||||
* val * MICRO overflowing.
|
||||
*/
|
||||
if ((!val && !val_fract) || val > INT_MAX / MICRO ||
|
||||
(val == INT_MAX / MICRO && val_fract > INT_MAX % MICRO))
|
||||
return -EINVAL;
|
||||
|
||||
rshunt_uohm = val * MICRO + val_fract;
|
||||
|
||||
guard(mutex)(&priv->lock);
|
||||
|
||||
priv->rshunt_uohm = rshunt_uohm;
|
||||
|
@ -1151,6 +1167,61 @@ static void pac1921_regulator_disable(void *data)
|
|||
regulator_disable(regulator);
|
||||
}
|
||||
|
||||
/*
|
||||
* Documentation related to the ACPI device definition
|
||||
* https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC193X-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf
|
||||
*/
|
||||
static int pac1921_match_acpi_device(struct iio_dev *indio_dev)
|
||||
{
|
||||
acpi_handle handle;
|
||||
union acpi_object *status;
|
||||
char *label;
|
||||
struct pac1921_priv *priv = iio_priv(indio_dev);
|
||||
struct device *dev = &priv->client->dev;
|
||||
|
||||
handle = ACPI_HANDLE(dev);
|
||||
|
||||
status = acpi_evaluate_dsm(handle, &pac1921_guid, 1,
|
||||
PAC1921_ACPI_GET_uOHMS_VALS, NULL);
|
||||
if (!status)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Could not read shunt from ACPI table\n");
|
||||
|
||||
priv->rshunt_uohm = status->package.elements[0].integer.value;
|
||||
ACPI_FREE(status);
|
||||
|
||||
status = acpi_evaluate_dsm(handle, &pac1921_guid, 1,
|
||||
PAC1921_ACPI_GET_LABEL, NULL);
|
||||
if (!status)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Could not read label from ACPI table\n");
|
||||
|
||||
label = devm_kstrdup(dev, status->package.elements[0].string.pointer,
|
||||
GFP_KERNEL);
|
||||
if (!label)
|
||||
return -ENOMEM;
|
||||
|
||||
indio_dev->label = label;
|
||||
ACPI_FREE(status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pac1921_parse_of_fw(struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
struct pac1921_priv *priv = iio_priv(indio_dev);
|
||||
struct device *dev = &priv->client->dev;
|
||||
|
||||
ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms",
|
||||
&priv->rshunt_uohm);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Cannot read shunt resistor property\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pac1921_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
|
@ -1179,11 +1250,14 @@ static int pac1921_probe(struct i2c_client *client)
|
|||
priv->di_gain = PAC1921_DEFAULT_DI_GAIN;
|
||||
priv->n_samples = PAC1921_DEFAULT_NUM_SAMPLES;
|
||||
|
||||
ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms",
|
||||
&priv->rshunt_uohm);
|
||||
if (is_acpi_device_node(dev->fwnode))
|
||||
ret = pac1921_match_acpi_device(indio_dev);
|
||||
else
|
||||
ret = pac1921_parse_of_fw(indio_dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Cannot read shunt resistor property\n");
|
||||
"Parameter parsing error\n");
|
||||
|
||||
if (priv->rshunt_uohm == 0 || priv->rshunt_uohm > INT_MAX)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Invalid shunt resistor: %u\n",
|
||||
|
@ -1246,11 +1320,18 @@ static const struct of_device_id pac1921_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, pac1921_of_match);
|
||||
|
||||
static const struct acpi_device_id pac1921_acpi_match[] = {
|
||||
{ "MCHP1921" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, pac1921_acpi_match);
|
||||
|
||||
static struct i2c_driver pac1921_driver = {
|
||||
.driver = {
|
||||
.name = "pac1921",
|
||||
.pm = pm_sleep_ptr(&pac1921_pm_ops),
|
||||
.of_match_table = pac1921_of_match,
|
||||
.acpi_match_table = pac1921_acpi_match,
|
||||
},
|
||||
.probe = pac1921_probe,
|
||||
.id_table = pac1921_id,
|
||||
|
|
|
@ -363,7 +363,7 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
|
|||
*/
|
||||
struct {
|
||||
u16 values[SARADC_MAX_CHANNELS];
|
||||
int64_t timestamp;
|
||||
aligned_s64 timestamp;
|
||||
} data;
|
||||
int ret;
|
||||
int i, j = 0;
|
||||
|
|
|
@ -634,7 +634,7 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p)
|
|||
struct device *dev = priv->dev;
|
||||
struct {
|
||||
u16 vals[RTQ6056_MAX_CHANNEL];
|
||||
s64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} data;
|
||||
unsigned int raw;
|
||||
int i = 0, bit, ret;
|
||||
|
|
|
@ -8,12 +8,13 @@
|
|||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -32,20 +33,15 @@
|
|||
#define RZG2L_ADM1_MS BIT(2)
|
||||
#define RZG2L_ADM1_BS BIT(4)
|
||||
#define RZG2L_ADM1_EGA_MASK GENMASK(13, 12)
|
||||
#define RZG2L_ADM2_CHSEL_MASK GENMASK(7, 0)
|
||||
#define RZG2L_ADM3_ADIL_MASK GENMASK(31, 24)
|
||||
#define RZG2L_ADM3_ADCMP_MASK GENMASK(23, 16)
|
||||
#define RZG2L_ADM3_ADCMP_E FIELD_PREP(RZG2L_ADM3_ADCMP_MASK, 0xe)
|
||||
#define RZG2L_ADM3_ADSMP_MASK GENMASK(15, 0)
|
||||
|
||||
#define RZG2L_ADINT 0x20
|
||||
#define RZG2L_ADINT_INTEN_MASK GENMASK(7, 0)
|
||||
#define RZG2L_ADINT_CSEEN BIT(16)
|
||||
#define RZG2L_ADINT_INTS BIT(31)
|
||||
|
||||
#define RZG2L_ADSTS 0x24
|
||||
#define RZG2L_ADSTS_CSEST BIT(16)
|
||||
#define RZG2L_ADSTS_INTST_MASK GENMASK(7, 0)
|
||||
|
||||
#define RZG2L_ADIVC 0x28
|
||||
#define RZG2L_ADIVC_DIVADC_MASK GENMASK(8, 0)
|
||||
|
@ -56,12 +52,28 @@
|
|||
#define RZG2L_ADCR(n) (0x30 + ((n) * 0x4))
|
||||
#define RZG2L_ADCR_AD_MASK GENMASK(11, 0)
|
||||
|
||||
#define RZG2L_ADSMP_DEFAULT_SAMPLING 0x578
|
||||
|
||||
#define RZG2L_ADC_MAX_CHANNELS 8
|
||||
#define RZG2L_ADC_CHN_MASK 0x7
|
||||
#define RZG2L_ADC_MAX_CHANNELS 9
|
||||
#define RZG2L_ADC_TIMEOUT usecs_to_jiffies(1 * 4)
|
||||
|
||||
/**
|
||||
* struct rzg2l_adc_hw_params - ADC hardware specific parameters
|
||||
* @default_adsmp: default ADC sampling period (see ADM3 register); index 0 is
|
||||
* used for voltage channels, index 1 is used for temperature channel
|
||||
* @adsmp_mask: ADC sampling period mask (see ADM3 register)
|
||||
* @adint_inten_mask: conversion end interrupt mask (see ADINT register)
|
||||
* @default_adcmp: default ADC cmp (see ADM3 register)
|
||||
* @num_channels: number of supported channels
|
||||
* @adivc: specifies if ADVIC register is available
|
||||
*/
|
||||
struct rzg2l_adc_hw_params {
|
||||
u16 default_adsmp[2];
|
||||
u16 adsmp_mask;
|
||||
u16 adint_inten_mask;
|
||||
u8 default_adcmp;
|
||||
u8 num_channels;
|
||||
bool adivc;
|
||||
};
|
||||
|
||||
struct rzg2l_adc_data {
|
||||
const struct iio_chan_spec *channels;
|
||||
u8 num_channels;
|
||||
|
@ -69,25 +81,36 @@ struct rzg2l_adc_data {
|
|||
|
||||
struct rzg2l_adc {
|
||||
void __iomem *base;
|
||||
struct clk *pclk;
|
||||
struct clk *adclk;
|
||||
struct reset_control *presetn;
|
||||
struct reset_control *adrstn;
|
||||
struct completion completion;
|
||||
const struct rzg2l_adc_data *data;
|
||||
const struct rzg2l_adc_hw_params *hw_params;
|
||||
struct completion completion;
|
||||
struct mutex lock;
|
||||
u16 last_val[RZG2L_ADC_MAX_CHANNELS];
|
||||
bool was_rpm_active;
|
||||
};
|
||||
|
||||
static const char * const rzg2l_adc_channel_name[] = {
|
||||
"adc0",
|
||||
"adc1",
|
||||
"adc2",
|
||||
"adc3",
|
||||
"adc4",
|
||||
"adc5",
|
||||
"adc6",
|
||||
"adc7",
|
||||
/**
|
||||
* struct rzg2l_adc_channel - ADC channel descriptor
|
||||
* @name: ADC channel name
|
||||
* @type: ADC channel type
|
||||
*/
|
||||
struct rzg2l_adc_channel {
|
||||
const char * const name;
|
||||
enum iio_chan_type type;
|
||||
};
|
||||
|
||||
static const struct rzg2l_adc_channel rzg2l_adc_channels[] = {
|
||||
{ "adc0", IIO_VOLTAGE },
|
||||
{ "adc1", IIO_VOLTAGE },
|
||||
{ "adc2", IIO_VOLTAGE },
|
||||
{ "adc3", IIO_VOLTAGE },
|
||||
{ "adc4", IIO_VOLTAGE },
|
||||
{ "adc5", IIO_VOLTAGE },
|
||||
{ "adc6", IIO_VOLTAGE },
|
||||
{ "adc7", IIO_VOLTAGE },
|
||||
{ "adc8", IIO_TEMP },
|
||||
};
|
||||
|
||||
static unsigned int rzg2l_adc_readl(struct rzg2l_adc *adc, u32 reg)
|
||||
|
@ -115,7 +138,7 @@ static void rzg2l_adc_pwr(struct rzg2l_adc *adc, bool on)
|
|||
|
||||
static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start)
|
||||
{
|
||||
int timeout = 5;
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
|
||||
|
@ -128,15 +151,10 @@ static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start)
|
|||
if (start)
|
||||
return;
|
||||
|
||||
do {
|
||||
usleep_range(100, 200);
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
|
||||
timeout--;
|
||||
if (!timeout) {
|
||||
pr_err("%s stopping ADC timed out\n", __func__);
|
||||
break;
|
||||
}
|
||||
} while (((reg & RZG2L_ADM0_ADBSY) || (reg & RZG2L_ADM0_ADCE)));
|
||||
ret = read_poll_timeout(rzg2l_adc_readl, reg, !(reg & (RZG2L_ADM0_ADBSY | RZG2L_ADM0_ADCE)),
|
||||
200, 1000, true, adc, RZG2L_ADM(0));
|
||||
if (ret)
|
||||
pr_err("%s stopping ADC timed out\n", __func__);
|
||||
}
|
||||
|
||||
static void rzg2l_set_trigger(struct rzg2l_adc *adc)
|
||||
|
@ -158,8 +176,18 @@ static void rzg2l_set_trigger(struct rzg2l_adc *adc)
|
|||
rzg2l_adc_writel(adc, RZG2L_ADM(1), reg);
|
||||
}
|
||||
|
||||
static u8 rzg2l_adc_ch_to_adsmp_index(u8 ch)
|
||||
{
|
||||
if (rzg2l_adc_channels[ch].type == IIO_VOLTAGE)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch)
|
||||
{
|
||||
const struct rzg2l_adc_hw_params *hw_params = adc->hw_params;
|
||||
u8 index = rzg2l_adc_ch_to_adsmp_index(ch);
|
||||
u32 reg;
|
||||
|
||||
if (rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_ADBSY)
|
||||
|
@ -169,10 +197,15 @@ static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch)
|
|||
|
||||
/* Select analog input channel subjected to conversion. */
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(2));
|
||||
reg &= ~RZG2L_ADM2_CHSEL_MASK;
|
||||
reg &= ~GENMASK(hw_params->num_channels - 1, 0);
|
||||
reg |= BIT(ch);
|
||||
rzg2l_adc_writel(adc, RZG2L_ADM(2), reg);
|
||||
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(3));
|
||||
reg &= ~hw_params->adsmp_mask;
|
||||
reg |= hw_params->default_adsmp[index];
|
||||
rzg2l_adc_writel(adc, RZG2L_ADM(3), reg);
|
||||
|
||||
/*
|
||||
* Setup ADINT
|
||||
* INTS[31] - Select pulse signal
|
||||
|
@ -181,36 +214,26 @@ static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch)
|
|||
*/
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADINT);
|
||||
reg &= ~RZG2L_ADINT_INTS;
|
||||
reg &= ~RZG2L_ADINT_INTEN_MASK;
|
||||
reg &= ~hw_params->adint_inten_mask;
|
||||
reg |= (RZG2L_ADINT_CSEEN | BIT(ch));
|
||||
rzg2l_adc_writel(adc, RZG2L_ADINT, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzg2l_adc_set_power(struct iio_dev *indio_dev, bool on)
|
||||
{
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
|
||||
if (on)
|
||||
return pm_runtime_resume_and_get(dev);
|
||||
|
||||
return pm_runtime_put_sync(dev);
|
||||
}
|
||||
|
||||
static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc, u8 ch)
|
||||
{
|
||||
const struct rzg2l_adc_hw_params *hw_params = adc->hw_params;
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
int ret;
|
||||
|
||||
ret = rzg2l_adc_set_power(indio_dev, true);
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rzg2l_adc_conversion_setup(adc, ch);
|
||||
if (ret) {
|
||||
rzg2l_adc_set_power(indio_dev, false);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto rpm_put;
|
||||
|
||||
reinit_completion(&adc->completion);
|
||||
|
||||
|
@ -218,13 +241,16 @@ static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc
|
|||
|
||||
if (!wait_for_completion_timeout(&adc->completion, RZG2L_ADC_TIMEOUT)) {
|
||||
rzg2l_adc_writel(adc, RZG2L_ADINT,
|
||||
rzg2l_adc_readl(adc, RZG2L_ADINT) & ~RZG2L_ADINT_INTEN_MASK);
|
||||
rzg2l_adc_start_stop(adc, false);
|
||||
rzg2l_adc_set_power(indio_dev, false);
|
||||
return -ETIMEDOUT;
|
||||
rzg2l_adc_readl(adc, RZG2L_ADINT) & ~hw_params->adint_inten_mask);
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return rzg2l_adc_set_power(indio_dev, false);
|
||||
rzg2l_adc_start_stop(adc, false);
|
||||
|
||||
rpm_put:
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rzg2l_adc_read_raw(struct iio_dev *indio_dev,
|
||||
|
@ -233,24 +259,22 @@ static int rzg2l_adc_read_raw(struct iio_dev *indio_dev,
|
|||
{
|
||||
struct rzg2l_adc *adc = iio_priv(indio_dev);
|
||||
int ret;
|
||||
u8 ch;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (chan->type != IIO_VOLTAGE)
|
||||
case IIO_CHAN_INFO_RAW: {
|
||||
if (chan->type != IIO_VOLTAGE && chan->type != IIO_TEMP)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&adc->lock);
|
||||
ch = chan->channel & RZG2L_ADC_CHN_MASK;
|
||||
ret = rzg2l_adc_conversion(indio_dev, adc, ch);
|
||||
if (ret) {
|
||||
mutex_unlock(&adc->lock);
|
||||
guard(mutex)(&adc->lock);
|
||||
|
||||
ret = rzg2l_adc_conversion(indio_dev, adc, chan->channel);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
*val = adc->last_val[ch];
|
||||
mutex_unlock(&adc->lock);
|
||||
|
||||
*val = adc->last_val[chan->channel];
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -261,7 +285,7 @@ static int rzg2l_adc_read_label(struct iio_dev *iio_dev,
|
|||
const struct iio_chan_spec *chan,
|
||||
char *label)
|
||||
{
|
||||
return sysfs_emit(label, "%s\n", rzg2l_adc_channel_name[chan->channel]);
|
||||
return sysfs_emit(label, "%s\n", rzg2l_adc_channels[chan->channel].name);
|
||||
}
|
||||
|
||||
static const struct iio_info rzg2l_adc_iio_info = {
|
||||
|
@ -272,6 +296,7 @@ static const struct iio_info rzg2l_adc_iio_info = {
|
|||
static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct rzg2l_adc *adc = dev_id;
|
||||
const struct rzg2l_adc_hw_params *hw_params = adc->hw_params;
|
||||
unsigned long intst;
|
||||
u32 reg;
|
||||
int ch;
|
||||
|
@ -284,11 +309,11 @@ static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
intst = reg & RZG2L_ADSTS_INTST_MASK;
|
||||
intst = reg & GENMASK(hw_params->num_channels - 1, 0);
|
||||
if (!intst)
|
||||
return IRQ_NONE;
|
||||
|
||||
for_each_set_bit(ch, &intst, RZG2L_ADC_MAX_CHANNELS)
|
||||
for_each_set_bit(ch, &intst, hw_params->num_channels)
|
||||
adc->last_val[ch] = rzg2l_adc_readl(adc, RZG2L_ADCR(ch)) & RZG2L_ADCR_AD_MASK;
|
||||
|
||||
/* clear the channel interrupt */
|
||||
|
@ -301,6 +326,7 @@ static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id)
|
|||
|
||||
static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc)
|
||||
{
|
||||
const struct rzg2l_adc_hw_params *hw_params = adc->hw_params;
|
||||
struct iio_chan_spec *chan_array;
|
||||
struct rzg2l_adc_data *data;
|
||||
unsigned int channel;
|
||||
|
@ -313,15 +339,12 @@ static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l
|
|||
return -ENOMEM;
|
||||
|
||||
num_channels = device_get_child_node_count(&pdev->dev);
|
||||
if (!num_channels) {
|
||||
dev_err(&pdev->dev, "no channel children\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!num_channels)
|
||||
return dev_err_probe(&pdev->dev, -ENODEV, "no channel children\n");
|
||||
|
||||
if (num_channels > RZG2L_ADC_MAX_CHANNELS) {
|
||||
dev_err(&pdev->dev, "num of channel children out of range\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (num_channels > hw_params->num_channels)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"num of channel children out of range\n");
|
||||
|
||||
chan_array = devm_kcalloc(&pdev->dev, num_channels, sizeof(*chan_array),
|
||||
GFP_KERNEL);
|
||||
|
@ -334,14 +357,14 @@ static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (channel >= RZG2L_ADC_MAX_CHANNELS)
|
||||
if (channel >= hw_params->num_channels)
|
||||
return -EINVAL;
|
||||
|
||||
chan_array[i].type = IIO_VOLTAGE;
|
||||
chan_array[i].type = rzg2l_adc_channels[channel].type;
|
||||
chan_array[i].indexed = 1;
|
||||
chan_array[i].channel = channel;
|
||||
chan_array[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
|
||||
chan_array[i].datasheet_name = rzg2l_adc_channel_name[channel];
|
||||
chan_array[i].datasheet_name = rzg2l_adc_channels[channel].name;
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -352,13 +375,13 @@ static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rzg2l_adc_hw_init(struct rzg2l_adc *adc)
|
||||
static int rzg2l_adc_hw_init(struct device *dev, struct rzg2l_adc *adc)
|
||||
{
|
||||
int timeout = 5;
|
||||
const struct rzg2l_adc_hw_params *hw_params = adc->hw_params;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(adc->pclk);
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -367,20 +390,18 @@ static int rzg2l_adc_hw_init(struct rzg2l_adc *adc)
|
|||
reg |= RZG2L_ADM0_SRESB;
|
||||
rzg2l_adc_writel(adc, RZG2L_ADM(0), reg);
|
||||
|
||||
while (!(rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_SRESB)) {
|
||||
if (!timeout) {
|
||||
ret = -EBUSY;
|
||||
goto exit_hw_init;
|
||||
}
|
||||
timeout--;
|
||||
usleep_range(100, 200);
|
||||
}
|
||||
ret = read_poll_timeout(rzg2l_adc_readl, reg, reg & RZG2L_ADM0_SRESB,
|
||||
200, 1000, false, adc, RZG2L_ADM(0));
|
||||
if (ret)
|
||||
goto exit_hw_init;
|
||||
|
||||
/* Only division by 4 can be set */
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADIVC);
|
||||
reg &= ~RZG2L_ADIVC_DIVADC_MASK;
|
||||
reg |= RZG2L_ADIVC_DIVADC_4;
|
||||
rzg2l_adc_writel(adc, RZG2L_ADIVC, reg);
|
||||
if (hw_params->adivc) {
|
||||
/* Only division by 4 can be set */
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADIVC);
|
||||
reg &= ~RZG2L_ADIVC_DIVADC_MASK;
|
||||
reg |= RZG2L_ADIVC_DIVADC_4;
|
||||
rzg2l_adc_writel(adc, RZG2L_ADIVC, reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup AMD3
|
||||
|
@ -391,35 +412,18 @@ static int rzg2l_adc_hw_init(struct rzg2l_adc *adc)
|
|||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(3));
|
||||
reg &= ~RZG2L_ADM3_ADIL_MASK;
|
||||
reg &= ~RZG2L_ADM3_ADCMP_MASK;
|
||||
reg &= ~RZG2L_ADM3_ADSMP_MASK;
|
||||
reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFAULT_SAMPLING);
|
||||
reg &= ~hw_params->adsmp_mask;
|
||||
reg |= FIELD_PREP(RZG2L_ADM3_ADCMP_MASK, hw_params->default_adcmp) |
|
||||
hw_params->default_adsmp[0];
|
||||
|
||||
rzg2l_adc_writel(adc, RZG2L_ADM(3), reg);
|
||||
|
||||
exit_hw_init:
|
||||
clk_disable_unprepare(adc->pclk);
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rzg2l_adc_pm_runtime_disable(void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
|
||||
pm_runtime_disable(dev->parent);
|
||||
}
|
||||
|
||||
static void rzg2l_adc_pm_runtime_set_suspended(void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
|
||||
pm_runtime_set_suspended(dev->parent);
|
||||
}
|
||||
|
||||
static void rzg2l_adc_reset_assert(void *data)
|
||||
{
|
||||
reset_control_assert(data);
|
||||
}
|
||||
|
||||
static int rzg2l_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -434,6 +438,10 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
|
|||
|
||||
adc = iio_priv(indio_dev);
|
||||
|
||||
adc->hw_params = device_get_match_data(dev);
|
||||
if (!adc->hw_params || adc->hw_params->num_channels > RZG2L_ADC_MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
ret = rzg2l_adc_parse_properties(pdev, adc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -444,63 +452,28 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(adc->base))
|
||||
return PTR_ERR(adc->base);
|
||||
|
||||
adc->pclk = devm_clk_get(dev, "pclk");
|
||||
if (IS_ERR(adc->pclk)) {
|
||||
dev_err(dev, "Failed to get pclk");
|
||||
return PTR_ERR(adc->pclk);
|
||||
}
|
||||
adc->adrstn = devm_reset_control_get_exclusive_deasserted(dev, "adrst-n");
|
||||
if (IS_ERR(adc->adrstn))
|
||||
return dev_err_probe(dev, PTR_ERR(adc->adrstn),
|
||||
"failed to get/deassert adrst-n\n");
|
||||
|
||||
adc->adclk = devm_clk_get(dev, "adclk");
|
||||
if (IS_ERR(adc->adclk)) {
|
||||
dev_err(dev, "Failed to get adclk");
|
||||
return PTR_ERR(adc->adclk);
|
||||
}
|
||||
adc->presetn = devm_reset_control_get_exclusive_deasserted(dev, "presetn");
|
||||
if (IS_ERR(adc->presetn))
|
||||
return dev_err_probe(dev, PTR_ERR(adc->presetn),
|
||||
"failed to get/deassert presetn\n");
|
||||
|
||||
adc->adrstn = devm_reset_control_get_exclusive(dev, "adrst-n");
|
||||
if (IS_ERR(adc->adrstn)) {
|
||||
dev_err(dev, "failed to get adrstn\n");
|
||||
return PTR_ERR(adc->adrstn);
|
||||
}
|
||||
|
||||
adc->presetn = devm_reset_control_get_exclusive(dev, "presetn");
|
||||
if (IS_ERR(adc->presetn)) {
|
||||
dev_err(dev, "failed to get presetn\n");
|
||||
return PTR_ERR(adc->presetn);
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(adc->adrstn);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to deassert adrstn pin, %d\n", ret);
|
||||
pm_runtime_set_autosuspend_delay(dev, 300);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev,
|
||||
rzg2l_adc_reset_assert, adc->adrstn);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register adrstn assert devm action, %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
ret = reset_control_deassert(adc->presetn);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to deassert presetn pin, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev,
|
||||
rzg2l_adc_reset_assert, adc->presetn);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register presetn assert devm action, %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rzg2l_adc_hw_init(adc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize ADC HW, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = rzg2l_adc_hw_init(dev, adc);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"failed to initialize ADC HW\n");
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
|
@ -513,72 +486,130 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
|
|||
|
||||
init_completion(&adc->completion);
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
indio_dev->name = DRIVER_NAME;
|
||||
indio_dev->info = &rzg2l_adc_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = adc->data->channels;
|
||||
indio_dev->num_channels = adc->data->num_channels;
|
||||
|
||||
pm_runtime_set_suspended(dev);
|
||||
ret = devm_add_action_or_reset(&pdev->dev,
|
||||
rzg2l_adc_pm_runtime_set_suspended, &indio_dev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
ret = devm_add_action_or_reset(&pdev->dev,
|
||||
rzg2l_adc_pm_runtime_disable, &indio_dev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct rzg2l_adc_hw_params rzg2l_hw_params = {
|
||||
.num_channels = 8,
|
||||
.default_adcmp = 0xe,
|
||||
.default_adsmp = { 0x578 },
|
||||
.adsmp_mask = GENMASK(15, 0),
|
||||
.adint_inten_mask = GENMASK(7, 0),
|
||||
.adivc = true
|
||||
};
|
||||
|
||||
static const struct rzg2l_adc_hw_params rzg3s_hw_params = {
|
||||
.num_channels = 9,
|
||||
.default_adcmp = 0x1d,
|
||||
.default_adsmp = { 0x7f, 0xff },
|
||||
.adsmp_mask = GENMASK(7, 0),
|
||||
.adint_inten_mask = GENMASK(11, 0),
|
||||
};
|
||||
|
||||
static const struct of_device_id rzg2l_adc_match[] = {
|
||||
{ .compatible = "renesas,rzg2l-adc",},
|
||||
{ .compatible = "renesas,r9a08g045-adc", .data = &rzg3s_hw_params },
|
||||
{ .compatible = "renesas,rzg2l-adc", .data = &rzg2l_hw_params },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rzg2l_adc_match);
|
||||
|
||||
static int __maybe_unused rzg2l_adc_pm_runtime_suspend(struct device *dev)
|
||||
static int rzg2l_adc_pm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct rzg2l_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
rzg2l_adc_pwr(adc, false);
|
||||
clk_disable_unprepare(adc->adclk);
|
||||
clk_disable_unprepare(adc->pclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused rzg2l_adc_pm_runtime_resume(struct device *dev)
|
||||
static int rzg2l_adc_pm_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct rzg2l_adc *adc = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(adc->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(adc->adclk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(adc->pclk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rzg2l_adc_pwr(adc, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzg2l_adc_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct rzg2l_adc *adc = iio_priv(indio_dev);
|
||||
struct reset_control_bulk_data resets[] = {
|
||||
{ .rstc = adc->presetn },
|
||||
{ .rstc = adc->adrstn },
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (pm_runtime_suspended(dev)) {
|
||||
adc->was_rpm_active = false;
|
||||
} else {
|
||||
ret = pm_runtime_force_suspend(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
adc->was_rpm_active = true;
|
||||
}
|
||||
|
||||
ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
|
||||
if (ret)
|
||||
goto rpm_restore;
|
||||
|
||||
return 0;
|
||||
|
||||
rpm_restore:
|
||||
if (adc->was_rpm_active)
|
||||
pm_runtime_force_resume(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rzg2l_adc_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct rzg2l_adc *adc = iio_priv(indio_dev);
|
||||
struct reset_control_bulk_data resets[] = {
|
||||
{ .rstc = adc->adrstn },
|
||||
{ .rstc = adc->presetn },
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adc->was_rpm_active) {
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret)
|
||||
goto resets_restore;
|
||||
}
|
||||
|
||||
ret = rzg2l_adc_hw_init(dev, adc);
|
||||
if (ret)
|
||||
goto rpm_restore;
|
||||
|
||||
return 0;
|
||||
|
||||
rpm_restore:
|
||||
if (adc->was_rpm_active) {
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
resets_restore:
|
||||
reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rzg2l_adc_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend,
|
||||
rzg2l_adc_pm_runtime_resume,
|
||||
NULL)
|
||||
RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend, rzg2l_adc_pm_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(rzg2l_adc_suspend, rzg2l_adc_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver rzg2l_adc_driver = {
|
||||
|
@ -586,7 +617,7 @@ static struct platform_driver rzg2l_adc_driver = {
|
|||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = rzg2l_adc_match,
|
||||
.pm = &rzg2l_adc_pm_ops,
|
||||
.pm = pm_ptr(&rzg2l_adc_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ struct adc081c {
|
|||
/* Ensure natural alignment of buffer elements */
|
||||
struct {
|
||||
u16 channel;
|
||||
s64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
};
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ struct adc084s021 {
|
|||
/* Buffer used to align data */
|
||||
struct {
|
||||
__be16 channels[4];
|
||||
s64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) may require the
|
||||
|
|
|
@ -448,7 +448,7 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p)
|
|||
/* Ensure natural alignment of timestamp */
|
||||
struct {
|
||||
s16 chan;
|
||||
s64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} scan;
|
||||
int chan, ret, res;
|
||||
|
||||
|
|
|
@ -501,7 +501,7 @@ static irqreturn_t ads1119_trigger_handler(int irq, void *private)
|
|||
struct ads1119_state *st = iio_priv(indio_dev);
|
||||
struct {
|
||||
unsigned int sample;
|
||||
s64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} scan;
|
||||
unsigned int index;
|
||||
int ret;
|
||||
|
|
|
@ -102,7 +102,7 @@ struct ads131e08_state {
|
|||
struct completion completion;
|
||||
struct {
|
||||
u8 data[ADS131E08_NUM_DATA_BYTES_MAX];
|
||||
s64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} tmp_buf;
|
||||
|
||||
u8 tx_buf[3] __aligned(IIO_DMA_MINALIGN);
|
||||
|
|
|
@ -199,7 +199,7 @@ static irqreturn_t lmp92064_trigger_handler(int irq, void *p)
|
|||
struct lmp92064_adc_priv *priv = iio_priv(indio_dev);
|
||||
struct {
|
||||
u16 values[2];
|
||||
int64_t timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} data;
|
||||
int ret;
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ struct tsc2046_adc_priv {
|
|||
/* Scan data for each channel */
|
||||
u16 data[TI_TSC2046_MAX_CHAN];
|
||||
/* Timestamp */
|
||||
s64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} scan_buf;
|
||||
|
||||
/*
|
||||
|
|
|
@ -173,10 +173,14 @@ struct vf610_adc {
|
|||
/* Ensure the timestamp is naturally aligned */
|
||||
struct {
|
||||
u16 chan;
|
||||
s64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} scan;
|
||||
};
|
||||
|
||||
struct vf610_chip_info {
|
||||
u8 num_channels;
|
||||
};
|
||||
|
||||
static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
|
||||
static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 };
|
||||
|
||||
|
@ -808,14 +812,31 @@ static const struct iio_info vf610_adc_iio_info = {
|
|||
.attrs = &vf610_attribute_group,
|
||||
};
|
||||
|
||||
static const struct vf610_chip_info vf610_chip_info = {
|
||||
.num_channels = ARRAY_SIZE(vf610_adc_iio_channels),
|
||||
};
|
||||
|
||||
static const struct vf610_chip_info imx6sx_chip_info = {
|
||||
.num_channels = 4,
|
||||
};
|
||||
|
||||
static const struct of_device_id vf610_adc_match[] = {
|
||||
{ .compatible = "fsl,vf610-adc", },
|
||||
{ .compatible = "fsl,imx6sx-adc", .data = &imx6sx_chip_info},
|
||||
{ .compatible = "fsl,vf610-adc", .data = &vf610_chip_info},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, vf610_adc_match);
|
||||
|
||||
static void vf610_adc_action_remove(void *d)
|
||||
{
|
||||
struct vf610_adc *info = d;
|
||||
|
||||
regulator_disable(info->vref);
|
||||
}
|
||||
|
||||
static int vf610_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct vf610_chip_info *chip_info;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct vf610_adc *info;
|
||||
struct iio_dev *indio_dev;
|
||||
|
@ -823,10 +844,8 @@ static int vf610_adc_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc));
|
||||
if (!indio_dev) {
|
||||
dev_err(&pdev->dev, "Failed allocating iio device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!indio_dev)
|
||||
return dev_err_probe(&pdev->dev, -ENOMEM, "Failed allocating iio device\n");
|
||||
|
||||
info = iio_priv(indio_dev);
|
||||
info->dev = &pdev->dev;
|
||||
|
@ -835,6 +854,8 @@ static int vf610_adc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(info->regs))
|
||||
return PTR_ERR(info->regs);
|
||||
|
||||
chip_info = device_get_match_data(dev);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
@ -842,17 +863,12 @@ static int vf610_adc_probe(struct platform_device *pdev)
|
|||
ret = devm_request_irq(info->dev, irq,
|
||||
vf610_adc_isr, 0,
|
||||
dev_name(&pdev->dev), indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed requesting irq, irq = %d\n", irq);
|
||||
|
||||
info->clk = devm_clk_get(&pdev->dev, "adc");
|
||||
if (IS_ERR(info->clk)) {
|
||||
dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
|
||||
PTR_ERR(info->clk));
|
||||
return PTR_ERR(info->clk);
|
||||
}
|
||||
info->clk = devm_clk_get_enabled(&pdev->dev, "adc");
|
||||
if (IS_ERR(info->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(info->clk), "failed getting clock\n");
|
||||
|
||||
info->vref = devm_regulator_get(&pdev->dev, "vref");
|
||||
if (IS_ERR(info->vref))
|
||||
|
@ -862,6 +878,10 @@ static int vf610_adc_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev, vf610_adc_action_remove, info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
info->vref_uv = regulator_get_voltage(info->vref);
|
||||
|
||||
device_property_read_u32_array(dev, "fsl,adck-max-frequency", info->max_adck_rate, 3);
|
||||
|
@ -877,54 +897,23 @@ static int vf610_adc_probe(struct platform_device *pdev)
|
|||
indio_dev->info = &vf610_adc_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = vf610_adc_iio_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(vf610_adc_iio_channels);
|
||||
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Could not prepare or enable the clock.\n");
|
||||
goto error_adc_clk_enable;
|
||||
}
|
||||
indio_dev->num_channels = chip_info->num_channels;
|
||||
|
||||
vf610_adc_cfg_init(info);
|
||||
vf610_adc_hw_init(info);
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
|
||||
NULL, &iio_triggered_buffer_setup_ops);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Couldn't initialise the buffer\n");
|
||||
goto error_iio_device_register;
|
||||
}
|
||||
ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev, &iio_pollfunc_store_time,
|
||||
NULL, &iio_triggered_buffer_setup_ops);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "Couldn't initialise the buffer\n");
|
||||
|
||||
mutex_init(&info->lock);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Couldn't register the device.\n");
|
||||
goto error_adc_buffer_init;
|
||||
}
|
||||
ret = devm_iio_device_register(&pdev->dev, indio_dev);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "Couldn't register the device.\n");
|
||||
|
||||
return 0;
|
||||
|
||||
error_adc_buffer_init:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
error_iio_device_register:
|
||||
clk_disable_unprepare(info->clk);
|
||||
error_adc_clk_enable:
|
||||
regulator_disable(info->vref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vf610_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct vf610_adc *info = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
regulator_disable(info->vref);
|
||||
clk_disable_unprepare(info->clk);
|
||||
}
|
||||
|
||||
static int vf610_adc_suspend(struct device *dev)
|
||||
|
@ -972,7 +961,6 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend,
|
|||
|
||||
static struct platform_driver vf610_adc_driver = {
|
||||
.probe = vf610_adc_probe,
|
||||
.remove = vf610_adc_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = vf610_adc_match,
|
||||
|
|
|
@ -206,7 +206,7 @@ static const struct iio_dev_attr *iio_dmaengine_buffer_attrs[] = {
|
|||
|
||||
/**
|
||||
* iio_dmaengine_buffer_alloc() - Allocate new buffer which uses DMAengine
|
||||
* @dev: Parent device for the buffer
|
||||
* @dev: DMA channel consumer device
|
||||
* @channel: DMA channel name, typically "rx".
|
||||
*
|
||||
* This allocates a new IIO buffer which internally uses the DMAengine framework
|
||||
|
@ -288,6 +288,21 @@ void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
|
|||
}
|
||||
EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, "IIO_DMAENGINE_BUFFER");
|
||||
|
||||
/**
|
||||
* iio_dmaengine_buffer_setup_ext() - Setup a DMA buffer for an IIO device
|
||||
* @dev: DMA channel consumer device
|
||||
* @indio_dev: IIO device to which to attach this buffer.
|
||||
* @channel: DMA channel name, typically "rx".
|
||||
* @dir: Direction of buffer (in or out)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Once done using the buffer iio_dmaengine_buffer_free() should be used to
|
||||
* release it.
|
||||
*/
|
||||
struct iio_buffer *iio_dmaengine_buffer_setup_ext(struct device *dev,
|
||||
struct iio_dev *indio_dev,
|
||||
const char *channel,
|
||||
|
@ -321,7 +336,7 @@ static void __devm_iio_dmaengine_buffer_free(void *buffer)
|
|||
|
||||
/**
|
||||
* devm_iio_dmaengine_buffer_setup_ext() - Setup a DMA buffer for an IIO device
|
||||
* @dev: Parent device for the buffer
|
||||
* @dev: Device for devm ownership and DMA channel consumer device
|
||||
* @indio_dev: IIO device to which to attach this buffer.
|
||||
* @channel: DMA channel name, typically "rx".
|
||||
* @dir: Direction of buffer (in or out)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#ifndef BME680_H_
|
||||
#define BME680_H_
|
||||
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define BME680_REG_CHIP_ID 0xD0
|
||||
|
@ -80,6 +81,7 @@
|
|||
#define BME680_CALIB_RANGE_3_LEN 5
|
||||
|
||||
extern const struct regmap_config bme680_regmap_config;
|
||||
extern const struct dev_pm_ops bme680_dev_pm_ops;
|
||||
|
||||
int bme680_core_probe(struct device *dev, struct regmap *regmap,
|
||||
const char *name);
|
||||
|
|
|
@ -14,7 +14,10 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
@ -111,6 +114,8 @@ enum bme680_scan {
|
|||
BME680_GAS,
|
||||
};
|
||||
|
||||
static const char *const bme680_supply_names[] = { "vdd", "vddio" };
|
||||
|
||||
struct bme680_data {
|
||||
struct regmap *regmap;
|
||||
struct bme680_calib bme680;
|
||||
|
@ -817,9 +822,9 @@ static int bme680_read_gas(struct bme680_data *data, int *comp_gas_res)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bme680_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
static int __bme680_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct bme680_data *data = iio_priv(indio_dev);
|
||||
int chan_val, ret;
|
||||
|
@ -932,14 +937,33 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
static int bme680_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct bme680_data *data = iio_priv(indio_dev);
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __bme680_read_raw(indio_dev, chan, val, val2, mask);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool bme680_is_valid_oversampling(int rate)
|
||||
{
|
||||
return (rate > 0 && rate <= 16 && is_power_of_2(rate));
|
||||
}
|
||||
|
||||
static int bme680_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
static int __bme680_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct bme680_data *data = iio_priv(indio_dev);
|
||||
|
||||
|
@ -984,6 +1008,25 @@ static int bme680_write_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
static int bme680_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct bme680_data *data = iio_priv(indio_dev);
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __bme680_write_raw(indio_dev, chan, val, val2, mask);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char bme680_oversampling_ratio_show[] = "1 2 4 8 16";
|
||||
|
||||
static IIO_CONST_ATTR(oversampling_ratio_available,
|
||||
|
@ -1084,6 +1127,29 @@ out:
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int bme680_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct bme680_data *data = iio_priv(indio_dev);
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
|
||||
return pm_runtime_resume_and_get(dev);
|
||||
}
|
||||
|
||||
static int bme680_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct bme680_data *data = iio_priv(indio_dev);
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops bme680_buffer_setup_ops = {
|
||||
.preenable = bme680_buffer_preenable,
|
||||
.postdisable = bme680_buffer_postdisable,
|
||||
};
|
||||
|
||||
int bme680_core_probe(struct device *dev, struct regmap *regmap,
|
||||
const char *name)
|
||||
{
|
||||
|
@ -1114,6 +1180,14 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
|
|||
data->heater_dur = 150; /* milliseconds */
|
||||
data->preheat_curr_mA = 0;
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(bme680_supply_names),
|
||||
bme680_supply_names);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to get and enable supplies.\n");
|
||||
|
||||
fsleep(BME680_STARTUP_TIME_US);
|
||||
|
||||
ret = regmap_write(regmap, BME680_REG_SOFT_RESET, BME680_CMD_SOFTRESET);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to reset chip\n");
|
||||
|
@ -1149,15 +1223,47 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
|
|||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
bme680_trigger_handler,
|
||||
NULL);
|
||||
&bme680_buffer_setup_ops);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"iio triggered buffer setup failed\n");
|
||||
|
||||
/* Enable runtime PM */
|
||||
pm_runtime_set_autosuspend_delay(dev, BME680_STARTUP_TIME_US);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(bme680_core_probe, "IIO_BME680");
|
||||
|
||||
static int bme680_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct bme680_data *data = iio_priv(indio_dev);
|
||||
|
||||
return bme680_set_mode(data, BME680_MODE_SLEEP);
|
||||
}
|
||||
|
||||
static int bme680_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct bme680_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = bme680_chip_config(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return bme680_gas_config(data);
|
||||
}
|
||||
|
||||
EXPORT_RUNTIME_DEV_PM_OPS(bme680_dev_pm_ops, bme680_runtime_suspend,
|
||||
bme680_runtime_resume, NULL);
|
||||
|
||||
MODULE_AUTHOR("Himanshu Jha <himanshujha199640@gmail.com>");
|
||||
MODULE_DESCRIPTION("Bosch BME680 Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -51,6 +51,7 @@ static struct i2c_driver bme680_i2c_driver = {
|
|||
.driver = {
|
||||
.name = "bme680_i2c",
|
||||
.of_match_table = bme680_of_i2c_match,
|
||||
.pm = pm_ptr(&bme680_dev_pm_ops),
|
||||
},
|
||||
.probe = bme680_i2c_probe,
|
||||
.id_table = bme680_i2c_id,
|
||||
|
|
|
@ -154,6 +154,7 @@ static struct spi_driver bme680_spi_driver = {
|
|||
.driver = {
|
||||
.name = "bme680_spi",
|
||||
.of_match_table = bme680_of_spi_match,
|
||||
.pm = pm_ptr(&bme680_dev_pm_ops),
|
||||
},
|
||||
.probe = bme680_spi_probe,
|
||||
.id_table = bme680_spi_id,
|
||||
|
|
|
@ -81,7 +81,7 @@ struct ccs811_data {
|
|||
/* Ensures correct alignment of timestamp if present */
|
||||
struct {
|
||||
s16 channels[2];
|
||||
s64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
};
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ struct ens160_data {
|
|||
struct mutex mutex;
|
||||
struct {
|
||||
__le16 chans[2];
|
||||
s64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} scan __aligned(IIO_DMA_MINALIGN);
|
||||
u8 fw_version[3];
|
||||
__le16 buf;
|
||||
|
|
|
@ -594,7 +594,7 @@ static irqreturn_t scd30_trigger_handler(int irq, void *p)
|
|||
struct scd30_state *state = iio_priv(indio_dev);
|
||||
struct {
|
||||
int data[SCD30_MEAS_COUNT];
|
||||
s64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
int ret;
|
||||
|
||||
|
|
|
@ -665,7 +665,7 @@ static irqreturn_t scd4x_trigger_handler(int irq, void *p)
|
|||
struct scd4x_state *state = iio_priv(indio_dev);
|
||||
struct {
|
||||
uint16_t data[3];
|
||||
int64_t ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
int ret;
|
||||
|
||||
|
|
|
@ -109,8 +109,8 @@ static bool inv_update_chip_period(struct inv_sensors_timestamp *ts,
|
|||
|
||||
static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts)
|
||||
{
|
||||
const int64_t period_min = ts->min_period * ts->mult;
|
||||
const int64_t period_max = ts->max_period * ts->mult;
|
||||
const int64_t period_min = (int64_t)ts->min_period * ts->mult;
|
||||
const int64_t period_max = (int64_t)ts->max_period * ts->mult;
|
||||
int64_t add_max, sub_max;
|
||||
int64_t delta, jitter;
|
||||
int64_t adjust;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/units.h>
|
||||
#include "ssp_iio_sensor.h"
|
||||
|
||||
/**
|
||||
|
@ -70,8 +72,7 @@ EXPORT_SYMBOL_NS(ssp_common_buffer_postdisable, "IIO_SSP_SENSORS");
|
|||
int ssp_common_process_data(struct iio_dev *indio_dev, void *buf,
|
||||
unsigned int len, int64_t timestamp)
|
||||
{
|
||||
__le32 time;
|
||||
int64_t calculated_time = 0;
|
||||
int64_t calculated_time;
|
||||
struct ssp_sensor_data *spd = iio_priv(indio_dev);
|
||||
|
||||
if (indio_dev->scan_bytes == 0)
|
||||
|
@ -82,11 +83,8 @@ int ssp_common_process_data(struct iio_dev *indio_dev, void *buf,
|
|||
*/
|
||||
memcpy(spd->buffer, buf, len);
|
||||
|
||||
if (indio_dev->scan_timestamp) {
|
||||
memcpy(&time, &((char *)buf)[len], SSP_TIME_SIZE);
|
||||
calculated_time =
|
||||
timestamp + (int64_t)le32_to_cpu(time) * 1000000;
|
||||
}
|
||||
calculated_time = timestamp +
|
||||
(int64_t)get_unaligned_le32(buf + len) * MEGA;
|
||||
|
||||
return iio_push_to_buffers_with_timestamp(indio_dev, spd->buffer,
|
||||
calculated_time);
|
||||
|
|
|
@ -80,7 +80,7 @@ config AD5421
|
|||
depends on SPI
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD5421 loop-powered
|
||||
digital-to-analog convertors (DAC).
|
||||
digital-to-analog converters (DAC).
|
||||
|
||||
To compile this driver as module choose M here: the module will be called
|
||||
ad5421.
|
||||
|
@ -348,6 +348,14 @@ config AD8801
|
|||
To compile this driver as a module choose M here: the module will be called
|
||||
ad8801.
|
||||
|
||||
config BD79703
|
||||
tristate "ROHM Semiconductor BD79703 DAC driver"
|
||||
depends on SPI
|
||||
select REGMAP_SPI
|
||||
help
|
||||
Say yes here to build support for ROHM Semiconductor BD79703 Digital
|
||||
to Analog Converter (DAC).
|
||||
|
||||
config CIO_DAC
|
||||
tristate "Measurement Computing CIO-DAC IIO driver"
|
||||
depends on X86 && (ISA_BUS || PC104)
|
||||
|
|
|
@ -34,6 +34,7 @@ obj-$(CONFIG_AD8460) += ad8460.o
|
|||
obj-$(CONFIG_AD8801) += ad8801.o
|
||||
obj-$(CONFIG_AD9739A) += ad9739a.o
|
||||
obj-$(CONFIG_ADI_AXI_DAC) += adi-axi-dac.o
|
||||
obj-$(CONFIG_BD79703) += rohm-bd79703.o
|
||||
obj-$(CONFIG_CIO_DAC) += cio-dac.o
|
||||
obj-$(CONFIG_DPOT_DAC) += dpot-dac.o
|
||||
obj-$(CONFIG_DS4424) += ds4424.o
|
||||
|
|
|
@ -41,11 +41,9 @@ struct ad5624r_chip_info {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct ad5446_state - driver instance specific data
|
||||
* @indio_dev: the industrial I/O device
|
||||
* struct ad5624r_state - driver instance specific data
|
||||
* @us: spi_device
|
||||
* @chip_info: chip model specific constants, available modes etc
|
||||
* @reg: supply regulator
|
||||
* @vref_mv: actual reference voltage used
|
||||
* @pwr_down_mask power down mask
|
||||
* @pwr_down_mode current power down mode
|
||||
|
|
|
@ -95,11 +95,6 @@ static int ad5686_spi_probe(struct spi_device *spi)
|
|||
ad5686_spi_write, ad5686_spi_read);
|
||||
}
|
||||
|
||||
static void ad5686_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
ad5686_remove(&spi->dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad5686_spi_id[] = {
|
||||
{"ad5310r", ID_AD5310R},
|
||||
{"ad5672r", ID_AD5672R},
|
||||
|
@ -126,7 +121,6 @@ static struct spi_driver ad5686_spi_driver = {
|
|||
.name = "ad5686",
|
||||
},
|
||||
.probe = ad5686_spi_probe,
|
||||
.remove = ad5686_spi_remove,
|
||||
.id_table = ad5686_spi_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -455,39 +455,28 @@ int ad5686_probe(struct device *dev,
|
|||
struct ad5686_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
unsigned int val, ref_bit_msk;
|
||||
bool has_external_vref;
|
||||
u8 cmd;
|
||||
int ret, i, voltage_uv = 0;
|
||||
int ret, i;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
if (indio_dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
dev_set_drvdata(dev, indio_dev);
|
||||
|
||||
st->dev = dev;
|
||||
st->write = write;
|
||||
st->read = read;
|
||||
|
||||
st->reg = devm_regulator_get_optional(dev, "vcc");
|
||||
if (!IS_ERR(st->reg)) {
|
||||
ret = regulator_enable(st->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_get_voltage(st->reg);
|
||||
if (ret < 0)
|
||||
goto error_disable_reg;
|
||||
|
||||
voltage_uv = ret;
|
||||
}
|
||||
|
||||
st->chip_info = &ad5686_chip_info_tbl[chip_type];
|
||||
|
||||
if (voltage_uv)
|
||||
st->vref_mv = voltage_uv / 1000;
|
||||
else
|
||||
st->vref_mv = st->chip_info->int_vref_mv;
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, "vcc");
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
return ret;
|
||||
|
||||
has_external_vref = ret != -ENODEV;
|
||||
st->vref_mv = has_external_vref ? ret / 1000 : st->chip_info->int_vref_mv;
|
||||
|
||||
/* Set all the power down mode for all channels to 1K pulldown */
|
||||
for (i = 0; i < st->chip_info->num_channels; i++)
|
||||
|
@ -505,12 +494,12 @@ int ad5686_probe(struct device *dev,
|
|||
case AD5310_REGMAP:
|
||||
cmd = AD5686_CMD_CONTROL_REG;
|
||||
ref_bit_msk = AD5310_REF_BIT_MSK;
|
||||
st->use_internal_vref = !voltage_uv;
|
||||
st->use_internal_vref = !has_external_vref;
|
||||
break;
|
||||
case AD5683_REGMAP:
|
||||
cmd = AD5686_CMD_CONTROL_REG;
|
||||
ref_bit_msk = AD5683_REF_BIT_MSK;
|
||||
st->use_internal_vref = !voltage_uv;
|
||||
st->use_internal_vref = !has_external_vref;
|
||||
break;
|
||||
case AD5686_REGMAP:
|
||||
cmd = AD5686_CMD_INTERNAL_REFER_SETUP;
|
||||
|
@ -519,43 +508,22 @@ int ad5686_probe(struct device *dev,
|
|||
case AD5693_REGMAP:
|
||||
cmd = AD5686_CMD_CONTROL_REG;
|
||||
ref_bit_msk = AD5693_REF_BIT_MSK;
|
||||
st->use_internal_vref = !voltage_uv;
|
||||
st->use_internal_vref = !has_external_vref;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto error_disable_reg;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val = (voltage_uv | ref_bit_msk);
|
||||
val = (has_external_vref | ref_bit_msk);
|
||||
|
||||
ret = st->write(st, cmd, 0, !!val);
|
||||
if (ret)
|
||||
goto error_disable_reg;
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto error_disable_reg;
|
||||
|
||||
return 0;
|
||||
|
||||
error_disable_reg:
|
||||
if (!IS_ERR(st->reg))
|
||||
regulator_disable(st->reg);
|
||||
return ret;
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ad5686_probe, "IIO_AD5686");
|
||||
|
||||
void ad5686_remove(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct ad5686_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (!IS_ERR(st->reg))
|
||||
regulator_disable(st->reg);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ad5686_remove, "IIO_AD5686");
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -115,10 +115,9 @@ struct ad5686_chip_info {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct ad5446_state - driver instance specific data
|
||||
* struct ad5686_state - driver instance specific data
|
||||
* @spi: spi_device
|
||||
* @chip_info: chip model specific constants, available modes etc
|
||||
* @reg: supply regulator
|
||||
* @vref_mv: actual reference voltage used
|
||||
* @pwr_down_mask: power down mask
|
||||
* @pwr_down_mode: current power down mode
|
||||
|
@ -130,7 +129,6 @@ struct ad5686_chip_info {
|
|||
struct ad5686_state {
|
||||
struct device *dev;
|
||||
const struct ad5686_chip_info *chip_info;
|
||||
struct regulator *reg;
|
||||
unsigned short vref_mv;
|
||||
unsigned int pwr_down_mask;
|
||||
unsigned int pwr_down_mode;
|
||||
|
@ -157,7 +155,5 @@ int ad5686_probe(struct device *dev,
|
|||
const char *name, ad5686_write_func write,
|
||||
ad5686_read_func read);
|
||||
|
||||
void ad5686_remove(struct device *dev);
|
||||
|
||||
|
||||
#endif /* __DRIVERS_IIO_DAC_AD5686_H__ */
|
||||
|
|
|
@ -65,11 +65,6 @@ static int ad5686_i2c_probe(struct i2c_client *i2c)
|
|||
ad5686_i2c_write, ad5686_i2c_read);
|
||||
}
|
||||
|
||||
static void ad5686_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
ad5686_remove(&i2c->dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ad5686_i2c_id[] = {
|
||||
{"ad5311r", ID_AD5311R},
|
||||
{"ad5337r", ID_AD5337R},
|
||||
|
@ -116,7 +111,6 @@ static struct i2c_driver ad5686_i2c_driver = {
|
|||
.of_match_table = ad5686_of_match,
|
||||
},
|
||||
.probe = ad5686_i2c_probe,
|
||||
.remove = ad5686_i2c_remove,
|
||||
.id_table = ad5686_i2c_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -141,8 +141,6 @@ struct ad7293_state {
|
|||
/* Protect against concurrent accesses to the device, page selection and data content */
|
||||
struct mutex lock;
|
||||
struct gpio_desc *gpio_reset;
|
||||
struct regulator *reg_avdd;
|
||||
struct regulator *reg_vdrive;
|
||||
u8 page_select;
|
||||
u8 data[3] __aligned(IIO_DMA_MINALIGN);
|
||||
};
|
||||
|
@ -777,6 +775,15 @@ static int ad7293_reset(struct ad7293_state *st)
|
|||
static int ad7293_properties_parse(struct ad7293_state *st)
|
||||
{
|
||||
struct spi_device *spi = st->spi;
|
||||
int ret;
|
||||
|
||||
ret = devm_regulator_get_enable(&spi->dev, "avdd");
|
||||
if (ret)
|
||||
return dev_err_probe(&spi->dev, ret, "failed to enable AVDD\n");
|
||||
|
||||
ret = devm_regulator_get_enable(&spi->dev, "vdrive");
|
||||
if (ret)
|
||||
return dev_err_probe(&spi->dev, ret, "failed to enable VDRIVE\n");
|
||||
|
||||
st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
|
||||
GPIOD_OUT_HIGH);
|
||||
|
@ -784,24 +791,9 @@ static int ad7293_properties_parse(struct ad7293_state *st)
|
|||
return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_reset),
|
||||
"failed to get the reset GPIO\n");
|
||||
|
||||
st->reg_avdd = devm_regulator_get(&spi->dev, "avdd");
|
||||
if (IS_ERR(st->reg_avdd))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(st->reg_avdd),
|
||||
"failed to get the AVDD voltage\n");
|
||||
|
||||
st->reg_vdrive = devm_regulator_get(&spi->dev, "vdrive");
|
||||
if (IS_ERR(st->reg_vdrive))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(st->reg_vdrive),
|
||||
"failed to get the VDRIVE voltage\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ad7293_reg_disable(void *data)
|
||||
{
|
||||
regulator_disable(data);
|
||||
}
|
||||
|
||||
static int ad7293_init(struct ad7293_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
@ -816,48 +808,6 @@ static int ad7293_init(struct ad7293_state *st)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_enable(st->reg_avdd);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev,
|
||||
"Failed to enable specified AVDD Voltage!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7293_reg_disable,
|
||||
st->reg_avdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_enable(st->reg_vdrive);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev,
|
||||
"Failed to enable specified VDRIVE Voltage!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7293_reg_disable,
|
||||
st->reg_vdrive);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_get_voltage(st->reg_avdd);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Failed to read avdd regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret > 5500000 || ret < 4500000)
|
||||
return -EINVAL;
|
||||
|
||||
ret = regulator_get_voltage(st->reg_vdrive);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev,
|
||||
"Failed to read vdrive regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret > 5500000 || ret < 1700000)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check Chip ID */
|
||||
ret = __ad7293_spi_read(st, AD7293_REG_DEVICE_ID, &chip_id);
|
||||
if (ret)
|
||||
|
|
|
@ -23,8 +23,6 @@ struct ad8801_state {
|
|||
unsigned char dac_cache[8]; /* Value write on each channel */
|
||||
unsigned int vrefh_mv;
|
||||
unsigned int vrefl_mv;
|
||||
struct regulator *vrefh_reg;
|
||||
struct regulator *vrefl_reg;
|
||||
|
||||
__be16 data __aligned(IIO_DMA_MINALIGN);
|
||||
};
|
||||
|
@ -122,86 +120,34 @@ static int ad8801_probe(struct spi_device *spi)
|
|||
state->spi = spi;
|
||||
id = spi_get_device_id(spi);
|
||||
|
||||
state->vrefh_reg = devm_regulator_get(&spi->dev, "vrefh");
|
||||
if (IS_ERR(state->vrefh_reg))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(state->vrefh_reg),
|
||||
"Vrefh regulator not specified\n");
|
||||
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vrefh");
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&spi->dev, ret,
|
||||
"failed to get Vrefh voltage\n");
|
||||
|
||||
ret = regulator_enable(state->vrefh_reg);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to enable vrefh regulator: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_get_voltage(state->vrefh_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Failed to read vrefh regulator: %d\n",
|
||||
ret);
|
||||
goto error_disable_vrefh_reg;
|
||||
}
|
||||
state->vrefh_mv = ret / 1000;
|
||||
|
||||
if (id->driver_data == ID_AD8803) {
|
||||
state->vrefl_reg = devm_regulator_get(&spi->dev, "vrefl");
|
||||
if (IS_ERR(state->vrefl_reg)) {
|
||||
ret = dev_err_probe(&spi->dev, PTR_ERR(state->vrefl_reg),
|
||||
"Vrefl regulator not specified\n");
|
||||
goto error_disable_vrefh_reg;
|
||||
}
|
||||
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vrefl");
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&spi->dev, ret,
|
||||
"failed to get Vrefl voltage\n");
|
||||
|
||||
ret = regulator_enable(state->vrefl_reg);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to enable vrefl regulator: %d\n",
|
||||
ret);
|
||||
goto error_disable_vrefh_reg;
|
||||
}
|
||||
|
||||
ret = regulator_get_voltage(state->vrefl_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Failed to read vrefl regulator: %d\n",
|
||||
ret);
|
||||
goto error_disable_vrefl_reg;
|
||||
}
|
||||
state->vrefl_mv = ret / 1000;
|
||||
} else {
|
||||
state->vrefl_mv = 0;
|
||||
state->vrefl_reg = NULL;
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
indio_dev->info = &ad8801_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = ad8801_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ad8801_channels);
|
||||
indio_dev->name = id->name;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to register iio device: %d\n",
|
||||
ret);
|
||||
goto error_disable_vrefl_reg;
|
||||
}
|
||||
ret = devm_iio_device_register(&spi->dev, indio_dev);
|
||||
if (ret)
|
||||
return dev_err_probe(&spi->dev, ret,
|
||||
"Failed to register iio device\n");
|
||||
|
||||
return 0;
|
||||
|
||||
error_disable_vrefl_reg:
|
||||
if (state->vrefl_reg)
|
||||
regulator_disable(state->vrefl_reg);
|
||||
error_disable_vrefh_reg:
|
||||
regulator_disable(state->vrefh_reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ad8801_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ad8801_state *state = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (state->vrefl_reg)
|
||||
regulator_disable(state->vrefl_reg);
|
||||
regulator_disable(state->vrefh_reg);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad8801_ids[] = {
|
||||
|
@ -216,7 +162,6 @@ static struct spi_driver ad8801_driver = {
|
|||
.name = "ad8801",
|
||||
},
|
||||
.probe = ad8801_probe,
|
||||
.remove = ad8801_remove,
|
||||
.id_table = ad8801_ids,
|
||||
};
|
||||
module_spi_driver(ad8801_driver);
|
||||
|
|
|
@ -41,13 +41,11 @@ struct ltc2632_chip_info {
|
|||
* @spi_dev: pointer to the spi_device struct
|
||||
* @powerdown_cache_mask: used to show current channel powerdown state
|
||||
* @vref_mv: used reference voltage (internal or external)
|
||||
* @vref_reg: regulator for the reference voltage
|
||||
*/
|
||||
struct ltc2632_state {
|
||||
struct spi_device *spi_dev;
|
||||
unsigned int powerdown_cache_mask;
|
||||
int vref_mv;
|
||||
struct regulator *vref_reg;
|
||||
};
|
||||
|
||||
enum ltc2632_supported_device_ids {
|
||||
|
@ -310,6 +308,7 @@ static int ltc2632_probe(struct spi_device *spi)
|
|||
struct ltc2632_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
struct ltc2632_chip_info *chip_info;
|
||||
bool has_external_vref;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
|
@ -318,49 +317,31 @@ static int ltc2632_probe(struct spi_device *spi)
|
|||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
st->spi_dev = spi;
|
||||
|
||||
chip_info = (struct ltc2632_chip_info *)
|
||||
spi_get_device_id(spi)->driver_data;
|
||||
|
||||
st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref");
|
||||
if (PTR_ERR(st->vref_reg) == -ENODEV) {
|
||||
/* use internal reference voltage */
|
||||
st->vref_reg = NULL;
|
||||
st->vref_mv = chip_info->vref_mv;
|
||||
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
return dev_err_probe(&spi->dev, ret,
|
||||
"Failed to get vref regulator voltage\n");
|
||||
|
||||
ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER,
|
||||
0, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev,
|
||||
"Set internal reference command failed, %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
} else if (IS_ERR(st->vref_reg)) {
|
||||
dev_err(&spi->dev,
|
||||
"Error getting voltage reference regulator\n");
|
||||
return PTR_ERR(st->vref_reg);
|
||||
} else {
|
||||
/* use external reference voltage */
|
||||
ret = regulator_enable(st->vref_reg);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev,
|
||||
"enable reference regulator failed, %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
st->vref_mv = regulator_get_voltage(st->vref_reg) / 1000;
|
||||
has_external_vref = ret != -ENODEV;
|
||||
st->vref_mv = has_external_vref ? ret / 1000 : chip_info->vref_mv;
|
||||
|
||||
if (has_external_vref) {
|
||||
ret = ltc2632_spi_write(spi, LTC2632_CMD_EXTERNAL_REFER,
|
||||
0, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev,
|
||||
"Set external reference command failed, %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
0, 0, 0);
|
||||
if (ret)
|
||||
return dev_err_probe(&spi->dev, ret,
|
||||
"Set external reference command failed\n");
|
||||
} else {
|
||||
ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER,
|
||||
0, 0, 0);
|
||||
if (ret)
|
||||
return dev_err_probe(&spi->dev, ret,
|
||||
"Set internal reference command failed\n");
|
||||
}
|
||||
|
||||
indio_dev->name = fwnode_get_name(dev_fwnode(&spi->dev)) ?: spi_get_device_id(spi)->name;
|
||||
|
@ -369,18 +350,7 @@ static int ltc2632_probe(struct spi_device *spi)
|
|||
indio_dev->channels = chip_info->channels;
|
||||
indio_dev->num_channels = chip_info->num_channels;
|
||||
|
||||
return iio_device_register(indio_dev);
|
||||
}
|
||||
|
||||
static void ltc2632_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ltc2632_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
if (st->vref_reg)
|
||||
regulator_disable(st->vref_reg);
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ltc2632_id[] = {
|
||||
|
@ -472,7 +442,6 @@ static struct spi_driver ltc2632_driver = {
|
|||
.of_match_table = ltc2632_of_match,
|
||||
},
|
||||
.probe = ltc2632_probe,
|
||||
.remove = ltc2632_remove,
|
||||
.id_table = ltc2632_id,
|
||||
};
|
||||
module_spi_driver(ltc2632_driver);
|
||||
|
|
|
@ -842,7 +842,7 @@ static int ltc2688_channel_config(struct ltc2688_state *st)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref)
|
||||
static int ltc2688_setup(struct ltc2688_state *st, bool has_external_vref)
|
||||
{
|
||||
struct device *dev = &st->spi->dev;
|
||||
struct gpio_desc *gpio;
|
||||
|
@ -881,18 +881,13 @@ static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!vref)
|
||||
if (!has_external_vref)
|
||||
return 0;
|
||||
|
||||
return regmap_set_bits(st->regmap, LTC2688_CMD_CONFIG,
|
||||
LTC2688_CONFIG_EXT_REF);
|
||||
}
|
||||
|
||||
static void ltc2688_disable_regulator(void *regulator)
|
||||
{
|
||||
regulator_disable(regulator);
|
||||
}
|
||||
|
||||
static bool ltc2688_reg_readable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
|
@ -947,8 +942,8 @@ static int ltc2688_probe(struct spi_device *spi)
|
|||
static const char * const regulators[] = { "vcc", "iovcc" };
|
||||
struct ltc2688_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
struct regulator *vref_reg;
|
||||
struct device *dev = &spi->dev;
|
||||
bool has_external_vref;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
|
@ -973,34 +968,15 @@ static int ltc2688_probe(struct spi_device *spi)
|
|||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to enable regulators\n");
|
||||
|
||||
vref_reg = devm_regulator_get_optional(dev, "vref");
|
||||
if (IS_ERR(vref_reg)) {
|
||||
if (PTR_ERR(vref_reg) != -ENODEV)
|
||||
return dev_err_probe(dev, PTR_ERR(vref_reg),
|
||||
"Failed to get vref regulator");
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, "vref");
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to get vref regulator voltage\n");
|
||||
|
||||
vref_reg = NULL;
|
||||
/* internal reference */
|
||||
st->vref = 4096;
|
||||
} else {
|
||||
ret = regulator_enable(vref_reg);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to enable vref regulators\n");
|
||||
has_external_vref = ret != -ENODEV;
|
||||
st->vref = has_external_vref ? ret / 1000 : 0;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, ltc2688_disable_regulator,
|
||||
vref_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_get_voltage(vref_reg);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to get vref\n");
|
||||
|
||||
st->vref = ret / 1000;
|
||||
}
|
||||
|
||||
ret = ltc2688_setup(st, vref_reg);
|
||||
ret = ltc2688_setup(st, has_external_vref);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ enum max5821_device_ids {
|
|||
|
||||
struct max5821_data {
|
||||
struct i2c_client *client;
|
||||
struct regulator *vref_reg;
|
||||
unsigned short vref_mv;
|
||||
bool powerdown[MAX5821_MAX_DAC_CHANNELS];
|
||||
u8 powerdown_mode[MAX5821_MAX_DAC_CHANNELS];
|
||||
|
@ -295,11 +294,6 @@ static const struct iio_info max5821_info = {
|
|||
.write_raw = max5821_write_raw,
|
||||
};
|
||||
|
||||
static void max5821_regulator_disable(void *reg)
|
||||
{
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static int max5821_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct i2c_device_id *id = i2c_client_get_device_id(client);
|
||||
|
@ -321,32 +315,10 @@ static int max5821_probe(struct i2c_client *client)
|
|||
data->powerdown_mode[tmp] = MAX5821_100KOHM_TO_GND;
|
||||
}
|
||||
|
||||
data->vref_reg = devm_regulator_get(&client->dev, "vref");
|
||||
if (IS_ERR(data->vref_reg))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(data->vref_reg),
|
||||
"Failed to get vref regulator\n");
|
||||
|
||||
ret = regulator_enable(data->vref_reg);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to enable vref regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&client->dev, max5821_regulator_disable,
|
||||
data->vref_reg);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to add action to managed regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_get_voltage(data->vref_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to get voltage on regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref");
|
||||
if (ret)
|
||||
return dev_err_probe(&client->dev, ret,
|
||||
"Failed to get vref regulator voltage\n");
|
||||
|
||||
data->vref_mv = ret / 1000;
|
||||
|
||||
|
|
|
@ -379,7 +379,7 @@ static int mcp4725_probe_dt(struct device *dev,
|
|||
struct mcp4725_platform_data *pdata)
|
||||
{
|
||||
/* check if is the vref-supply defined */
|
||||
pdata->use_vref = device_property_read_bool(dev, "vref-supply");
|
||||
pdata->use_vref = device_property_present(dev, "vref-supply");
|
||||
pdata->vref_buffered =
|
||||
device_property_read_bool(dev, "microchip,vref-buffered");
|
||||
|
||||
|
|
162
drivers/iio/dac/rohm-bd79703.c
Normal file
162
drivers/iio/dac/rohm-bd79703.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* BD79703 ROHM Digital to Analog converter
|
||||
*
|
||||
* Copyright (c) 2024, ROHM Semiconductor.
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
#define BD79703_MAX_REGISTER 0xf
|
||||
#define BD79703_DAC_BITS 8
|
||||
#define BD79703_REG_OUT_ALL GENMASK(2, 0)
|
||||
|
||||
/*
|
||||
* The BD79703 uses 12-bit SPI commands. First four bits (high bits) define
|
||||
* channel(s) which are operated on, and also the mode. The mode can be to set
|
||||
* a DAC word only, or set DAC word and output. The data-sheet is not very
|
||||
* specific on how a previously set DAC word can be 'taken in to use'. Thus
|
||||
* this driver only uses the 'set DAC and output it' -mode.
|
||||
*
|
||||
* The BD79703 latches last 12-bits when the chip-select is toggled. Thus we
|
||||
* can use 16-bit transfers which should be widely supported. To simplify this
|
||||
* further, we treat the last 8 bits as a value, and first 8 bits as an
|
||||
* address. This allows us to separate channels/mode by address and treat the
|
||||
* 8-bit register value as DAC word. The highest 4 bits of address will be
|
||||
* discarded when the transfer is latched.
|
||||
*/
|
||||
static const struct regmap_config bd79703_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = BD79703_MAX_REGISTER,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
struct bd79703_data {
|
||||
struct regmap *regmap;
|
||||
int vfs;
|
||||
};
|
||||
|
||||
static int bd79703_read_raw(struct iio_dev *idev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct bd79703_data *data = iio_priv(idev);
|
||||
|
||||
if (mask != IIO_CHAN_INFO_SCALE)
|
||||
return -EINVAL;
|
||||
|
||||
*val = data->vfs / 1000;
|
||||
*val2 = BD79703_DAC_BITS;
|
||||
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
}
|
||||
|
||||
static int bd79703_write_raw(struct iio_dev *idev,
|
||||
struct iio_chan_spec const *chan, int val,
|
||||
int val2, long mask)
|
||||
{
|
||||
struct bd79703_data *data = iio_priv(idev);
|
||||
|
||||
if (val < 0 || val >= 1 << BD79703_DAC_BITS)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_write(data->regmap, chan->channel + 1, val);
|
||||
};
|
||||
|
||||
static const struct iio_info bd79703_info = {
|
||||
.read_raw = bd79703_read_raw,
|
||||
.write_raw = bd79703_write_raw,
|
||||
};
|
||||
|
||||
#define BD79703_CHAN(_chan) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.output = 1, \
|
||||
.channel = (_chan), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.address = (_chan), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec bd79703_channels[] = {
|
||||
BD79703_CHAN(0),
|
||||
BD79703_CHAN(1),
|
||||
BD79703_CHAN(2),
|
||||
BD79703_CHAN(3),
|
||||
BD79703_CHAN(4),
|
||||
BD79703_CHAN(5),
|
||||
};
|
||||
|
||||
static int bd79703_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct bd79703_data *data;
|
||||
struct iio_dev *idev;
|
||||
int ret;
|
||||
|
||||
idev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(idev);
|
||||
|
||||
data->regmap = devm_regmap_init_spi(spi, &bd79703_regmap_config);
|
||||
if (IS_ERR(data->regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(data->regmap),
|
||||
"Failed to initialize Regmap\n");
|
||||
|
||||
ret = devm_regulator_get_enable(dev, "vcc");
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to enable VCC\n");
|
||||
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, "vfs");
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to get Vfs\n");
|
||||
|
||||
data->vfs = ret;
|
||||
idev->channels = bd79703_channels;
|
||||
idev->num_channels = ARRAY_SIZE(bd79703_channels);
|
||||
idev->modes = INDIO_DIRECT_MODE;
|
||||
idev->info = &bd79703_info;
|
||||
idev->name = "bd79703";
|
||||
|
||||
/* Initialize all to output zero */
|
||||
ret = regmap_write(data->regmap, BD79703_REG_OUT_ALL, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, idev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id bd79703_id[] = {
|
||||
{ "bd79703", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, bd79703_id);
|
||||
|
||||
static const struct of_device_id bd79703_of_match[] = {
|
||||
{ .compatible = "rohm,bd79703", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bd79703_of_match);
|
||||
|
||||
static struct spi_driver bd79703_driver = {
|
||||
.driver = {
|
||||
.name = "bd79703",
|
||||
.of_match_table = bd79703_of_match,
|
||||
},
|
||||
.probe = bd79703_probe,
|
||||
.id_table = bd79703_id,
|
||||
};
|
||||
module_spi_driver(bd79703_driver);
|
||||
|
||||
MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>");
|
||||
MODULE_DESCRIPTION("ROHM BD79703 DAC driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -75,7 +75,7 @@ struct adxrs290_state {
|
|||
/* Ensure correct alignment of timestamp when present */
|
||||
struct {
|
||||
s16 channels[3];
|
||||
s64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} buffer;
|
||||
};
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ struct bmg160_data {
|
|||
/* Ensure naturally aligned timestamp */
|
||||
struct {
|
||||
s16 chans[3];
|
||||
s64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} scan;
|
||||
u32 dps_range;
|
||||
int ev_enable_state;
|
||||
|
|
|
@ -52,7 +52,7 @@ static irqreturn_t itg3200_trigger_handler(int irq, void *p)
|
|||
*/
|
||||
struct {
|
||||
__be16 buf[ITG3200_SCAN_ELEMENTS];
|
||||
s64 ts __aligned(8);
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
|
||||
int ret = itg3200_read_all_channels(st->i2c, scan.buf);
|
||||
|
|
|
@ -474,7 +474,7 @@ static irqreturn_t mpu3050_trigger_handler(int irq, void *p)
|
|||
int ret;
|
||||
struct {
|
||||
__be16 chans[4];
|
||||
s64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} scan;
|
||||
s64 timestamp;
|
||||
unsigned int datums_from_fifo = 0;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user