mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-19 11:43:40 +00:00
IIO: 1st set of new device support, features and cleanup for 6.12
Includes a merge of spi-mos-config branch from spi.git that brings support needed for the AD4000 driver. Lots of new device support this time including 9 new drivers and substantial changes to add new support to several more. New device support ------------------ Given we have a lot of new support, I've subcategorized them: Substantial changes, or new driver ********************************** adi,ad4000 - New driver for this high speed ADC. adi,ad4695 - New driver supporting AD4690, AD4696, AD4697 and AD4698 ADCs. - Follow up series added triggered buffer support. adi,ad7380 - Add support for single ended parts, AD7386, ADC7387, AD7388 and -4 variants. (driver previously only support differential parts). These variants have an additional front end MUX so only half the channels can be sampled efficiently. adi,ad9467 - Refactor and extend driver to support ad9643, ad9449 and ad9652 high speed ADCs. adi,adxl380 - New driver for this low power accelerometer. adi,ltc2664 - New driver supporting LTC2664 and LTC2672 DACs. microchip,pac1921 - New driver for this power/current monitor chip. rohm,bh1745 - New driver for this RGBC colour sensor. rohm,bu27034anuc - The original bu27034 was canceled before mass production, so the driver is modified to support the BU27034ANUC which had some significant differences. DT compatible changed to avoid chance of old driver ever binding to real hardware. sciosense,ens210 - New driver for ens210, ens210a, ens211, ens212, ens213a, and ens215 temperature and humidity sensors (all register compatible up to some conversion time differences) sensiron,sdp500 - New driver for this differential pressure sensor. tyhx,hx9023s - New driver to support this capacitive proximity sensor. Minor changes to support new devices ************************************ adi,adf4377 - Add support for the single output adf4378. kionix,kxcjk-1013 - Add support for KX022-1020 accelerometer (binding and ID table only) liteon,ltrf216a - Add support for ltr-308. A few minor differences in features set rockchip,saradc - Add ID for rk3576-saradc sensortek,stk3310 - Add ID for stk3013 proximity sensor which (despite documentation) has an ambient light sensor and is compatible with existing parts. Documentation updates --------------------- Generalize ABI docs for shunt resistor attribute Improve calibscale and calibbias related documentation. A couple of follow up patches to resolve duplicate documentation that resulted. New core features ----------------- backend - Add option for debugfs - useful for test pattern control - Use this for both adi-axi-adc and adi-axi-dac trigger suspend - Add functions to allow triggers to be suspended. This avoids problems when a device enters suspend to idle with a sysfs trigger. Use it for now in the bmi323 only. New driver features ------------------- adi,ad7192 - Add option to be a clock provider (+ additional clock config options) adi,ad7380 - Add documentation for this fairly new driver. adi,ad9461 - Provide control of test modes and backend validation blocks used to identify problems (via debugfs) adi,ad9739 - Add backend debugfs and docs for what is provided via adi-axi-dac avago,apds9960 - Add proximity and gesture calibration offset control bosch,bmp280 - Triggered buffer support including adding raw+scale output for sysfs. liteon,ltr390 - Add configuration of integration time and scale. stm,dfsdm - Convert this SD modulator driver to backend framework and add support for channel scaling + modern channel bindings. Treewide cleanup ---------------- iio_dev->masklength: Making it private. - Provide access function to read the core compute channel mask length and a macro to iterate over elements in the active_scan_mask. - Enables marking masklength __private preventing drivers from writing it without triggering a build warning whilst minimizing overhead in what are typically hot paths. - Convert all drivers and finally mark it private. Merge conflicts resolved in drivers applied after this point. Constify regmap_bus - These are never modified, so mark them const. Core cleanup ------------ backend - A few late breaking bits of feedback (unused variable, error messages) dma-buffer - Namespace exports. core - Drop unused assignment. Driver cleanup -------------- adi,ad4695 - Fixing binding to reflect that common-mode-channel is a scalar. adi,ad7280a - Use __free(kfree) to simplify freeing of receive buffer. adi,ad7606 - Various dt-binding cleanup and improvements. - Fix oversampling related gpio handling. - Make polarity of standby gpio match documentation. - use guard() to simplify lock handling. adi,ad7768 - Use device_for_each_child_node_scoped() instead of fwnode equivalent. adi,ad7124 - Reduce SPI transfers by avoiding separate writes to different fields in the same register. - Start the ADC in idle mode. adi,adis - Drop ifdefs in favor of IS_ENABLED. adi,admv8818 - Fix wrong ABI docs. asahi-kasei,ak8975 - Drop a prefix free compatible accidentally added recently. aspeed,adc - Use of_property_present() instead of of_find_property() to see if the property is there or not. atmel,at91, - Use __free(kfree) to simplify freeing of channel related array. bosch,bma400 - Use __free(kfree) to simplify freeing a locally allocated string. bosch,bmc150 - Add missing mount-matrix binding docs. bosch,bme680 - Fix read/write to ensure multiple necessary sequential reads without device configuration change. - Drop unnecessary type casts and use more appropriate data types. - Drop some left over ACPI code as ACPI support was removed due to invalid IDs (and no known users). - Sort headers consistently. - Avoid unnecessary duplicate read and redundant read of gas config. - Use bulk reads to get calibration data. - Reorder allocation of IIO device to be prior to device init. - Add remaining read/write buffers to the union used already for all others. - Tidy up error checks for consistency of style, including dev_err_probe() - Bring the device startup procedure inline with the vendor code. - Reorder code so mode forcing is more obvious occurring where needed. - Tidy up data locality in reading functions so no magic data is stored in state structures just to get it across function calls. - Make a local lookup table static to avoid placing it on the stack. bosch,bmp280 - Fix BME280 regmap to not include registers it doesn't have. - Wait a little longer after config to allow for maximum possible necessary wait. - Reorganize headers. - Make conversion_time_max array static to avoid placing it on the stack. maxim,max1363 - Use __free(kfree) to simplify freeing transmission buffer. microchip,mcp3964 - Use devm_regulator_get_enable_read_voltage() microchip,mcp3911 - Use devm_regulator_get_enable_read_voltage() microchip,mcp4728 - Use devm_regulator_get_enable_read_voltage() microchip,mcp4922 - Use devm_regulator_get_enable_read_voltage() and devm_* to allow dropping of explicit remove() callback. onnn,noa1305 - Various tidy up. - Provide available scale values. - Make integration time configurable. - Fix up integration time look up (/2 error) ti,dac7311 - Check if spi_setup() succeeded. ti,tsc2046 - Use __free(kfree) to simplify freeing rx and tx buffers. - Use devm_regulator_get_enable_read_voltage() Various minor fixes not called out explicitly. -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAmbHhnARHGppYzIzQGtl cm5lbC5vcmcACgkQVIU0mcT0FohpshAApFDoTkyYMa7x1r5WUZ/5j474319LvwDO /9UIDIgR8qSzR2fDYl+LR03ZWknsOXF4lfCrCf65zPaR/8bB7TsjD8A7uIPVAKDF Tu+nSgBworJcvokPzygtrjoor2u2LCXdZVurYrFggMZ833LY5HTotFDAB32wx3QM p7p7OU0LgAZ8VR+ykzkbwp9NjOSrgD2mD7emy7Enu4h/OzLzst0c15KkUaOpnSUZ 8R/+tz5lERrF+ACjWm+sWSe8ry2SkQppd8G8pSXyUM0uD2KO0I78FEpA3wUB2H++ wiki1cm1kOM/ljHbXn2tqp5s+A8p6d0/LOCZm9bUi9kmtP5J2ky2iZmpZPraO52d +jbnHh/GyvoyIzeZRJZtp9h4hWTPNV2pgvb5BHD7Fek5rxOXXBlulDd695Ygbfq5 vxiXYfN+ozVQk3/1mm0FwA34VZSoHADvzTxANQE9Vi99ywenpqJ5VYWQm/Bf0oHm HMH1sCcrmPHF9NOEUPV2uCanTQ20Q+OO89xOUBDGma1FKh6108wSont5c6GX/dKu sChUdllXSlNUR8VoiAYSFEP/U+gXnRE8Scxuk1Xx12RuKYpe0NNdRyRtj86kTU+1 e6gHY90NskQCSVvOiivvo/rNTO08EZND9V3pbD/2HxaFvM4zw/iJtNR49DLdTkpX DfiCl2BAbLw= =eXUA -----END PGP SIGNATURE----- Merge tag 'iio-for-6.12a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-testing Jonathan writes: IIO: 1st set of new device support, features and cleanup for 6.12 Includes a merge of spi-mos-config branch from spi.git that brings support needed for the AD4000 driver. Lots of new device support this time including 9 new drivers and substantial changes to add new support to several more. New device support ------------------ Given we have a lot of new support, I've subcategorized them: Substantial changes, or new driver ********************************** adi,ad4000 - New driver for this high speed ADC. adi,ad4695 - New driver supporting AD4690, AD4696, AD4697 and AD4698 ADCs. - Follow up series added triggered buffer support. adi,ad7380 - Add support for single ended parts, AD7386, ADC7387, AD7388 and -4 variants. (driver previously only support differential parts). These variants have an additional front end MUX so only half the channels can be sampled efficiently. adi,ad9467 - Refactor and extend driver to support ad9643, ad9449 and ad9652 high speed ADCs. adi,adxl380 - New driver for this low power accelerometer. adi,ltc2664 - New driver supporting LTC2664 and LTC2672 DACs. microchip,pac1921 - New driver for this power/current monitor chip. rohm,bh1745 - New driver for this RGBC colour sensor. rohm,bu27034anuc - The original bu27034 was canceled before mass production, so the driver is modified to support the BU27034ANUC which had some significant differences. DT compatible changed to avoid chance of old driver ever binding to real hardware. sciosense,ens210 - New driver for ens210, ens210a, ens211, ens212, ens213a, and ens215 temperature and humidity sensors (all register compatible up to some conversion time differences) sensiron,sdp500 - New driver for this differential pressure sensor. tyhx,hx9023s - New driver to support this capacitive proximity sensor. Minor changes to support new devices ************************************ adi,adf4377 - Add support for the single output adf4378. kionix,kxcjk-1013 - Add support for KX022-1020 accelerometer (binding and ID table only) liteon,ltrf216a - Add support for ltr-308. A few minor differences in features set rockchip,saradc - Add ID for rk3576-saradc sensortek,stk3310 - Add ID for stk3013 proximity sensor which (despite documentation) has an ambient light sensor and is compatible with existing parts. Documentation updates --------------------- Generalize ABI docs for shunt resistor attribute Improve calibscale and calibbias related documentation. A couple of follow up patches to resolve duplicate documentation that resulted. New core features ----------------- backend - Add option for debugfs - useful for test pattern control - Use this for both adi-axi-adc and adi-axi-dac trigger suspend - Add functions to allow triggers to be suspended. This avoids problems when a device enters suspend to idle with a sysfs trigger. Use it for now in the bmi323 only. New driver features ------------------- adi,ad7192 - Add option to be a clock provider (+ additional clock config options) adi,ad7380 - Add documentation for this fairly new driver. adi,ad9461 - Provide control of test modes and backend validation blocks used to identify problems (via debugfs) adi,ad9739 - Add backend debugfs and docs for what is provided via adi-axi-dac avago,apds9960 - Add proximity and gesture calibration offset control bosch,bmp280 - Triggered buffer support including adding raw+scale output for sysfs. liteon,ltr390 - Add configuration of integration time and scale. stm,dfsdm - Convert this SD modulator driver to backend framework and add support for channel scaling + modern channel bindings. Treewide cleanup ---------------- iio_dev->masklength: Making it private. - Provide access function to read the core compute channel mask length and a macro to iterate over elements in the active_scan_mask. - Enables marking masklength __private preventing drivers from writing it without triggering a build warning whilst minimizing overhead in what are typically hot paths. - Convert all drivers and finally mark it private. Merge conflicts resolved in drivers applied after this point. Constify regmap_bus - These are never modified, so mark them const. Core cleanup ------------ backend - A few late breaking bits of feedback (unused variable, error messages) dma-buffer - Namespace exports. core - Drop unused assignment. Driver cleanup -------------- adi,ad4695 - Fixing binding to reflect that common-mode-channel is a scalar. adi,ad7280a - Use __free(kfree) to simplify freeing of receive buffer. adi,ad7606 - Various dt-binding cleanup and improvements. - Fix oversampling related gpio handling. - Make polarity of standby gpio match documentation. - use guard() to simplify lock handling. adi,ad7768 - Use device_for_each_child_node_scoped() instead of fwnode equivalent. adi,ad7124 - Reduce SPI transfers by avoiding separate writes to different fields in the same register. - Start the ADC in idle mode. adi,adis - Drop ifdefs in favor of IS_ENABLED. adi,admv8818 - Fix wrong ABI docs. asahi-kasei,ak8975 - Drop a prefix free compatible accidentally added recently. aspeed,adc - Use of_property_present() instead of of_find_property() to see if the property is there or not. atmel,at91, - Use __free(kfree) to simplify freeing of channel related array. bosch,bma400 - Use __free(kfree) to simplify freeing a locally allocated string. bosch,bmc150 - Add missing mount-matrix binding docs. bosch,bme680 - Fix read/write to ensure multiple necessary sequential reads without device configuration change. - Drop unnecessary type casts and use more appropriate data types. - Drop some left over ACPI code as ACPI support was removed due to invalid IDs (and no known users). - Sort headers consistently. - Avoid unnecessary duplicate read and redundant read of gas config. - Use bulk reads to get calibration data. - Reorder allocation of IIO device to be prior to device init. - Add remaining read/write buffers to the union used already for all others. - Tidy up error checks for consistency of style, including dev_err_probe() - Bring the device startup procedure inline with the vendor code. - Reorder code so mode forcing is more obvious occurring where needed. - Tidy up data locality in reading functions so no magic data is stored in state structures just to get it across function calls. - Make a local lookup table static to avoid placing it on the stack. bosch,bmp280 - Fix BME280 regmap to not include registers it doesn't have. - Wait a little longer after config to allow for maximum possible necessary wait. - Reorganize headers. - Make conversion_time_max array static to avoid placing it on the stack. maxim,max1363 - Use __free(kfree) to simplify freeing transmission buffer. microchip,mcp3964 - Use devm_regulator_get_enable_read_voltage() microchip,mcp3911 - Use devm_regulator_get_enable_read_voltage() microchip,mcp4728 - Use devm_regulator_get_enable_read_voltage() microchip,mcp4922 - Use devm_regulator_get_enable_read_voltage() and devm_* to allow dropping of explicit remove() callback. onnn,noa1305 - Various tidy up. - Provide available scale values. - Make integration time configurable. - Fix up integration time look up (/2 error) ti,dac7311 - Check if spi_setup() succeeded. ti,tsc2046 - Use __free(kfree) to simplify freeing rx and tx buffers. - Use devm_regulator_get_enable_read_voltage() Various minor fixes not called out explicitly. * tag 'iio-for-6.12a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (250 commits) drivers:iio:Fix the NULL vs IS_ERR() bug for debugfs_create_dir() iio: sgp40: retain documentation in driver iio: ABI: remove duplicate in_resistance_calibbias dt-bindings: iio: st,stm32-adc: add top-level constraints iio: ABI: add missing calibbias attributes iio: ABI: add missing calibscale attributes iio: ABI: sort calibscale attributes iio: ABI: document calibscale_available attributes iio: light: ltr390: Calculate 'counts_per_uvi' dynamically iio: light: ltr390: Add ALS channel and support for gain and resolution doc: iio: ad4695: document buffered read iio: adc: ad4695: implement triggered buffer iio: proximity: hx9023s: Fix error code in hx9023s_property_get() iio: light: noa1305: Fix up integration time look up iio: humidity: Add support for ENS210 dt-bindings: iio: humidity: add ENS210 sensor family iio: imu: adis16460: drop ifdef around CONFIG_DEBUG_FS iio: imu: adis16400: drop ifdef around CONFIG_DEBUG_FS iio: imu: adis16480: drop ifdef around CONFIG_DEBUG_FS iio: imu: adis16475: drop ifdef around CONFIG_DEBUG_FS ...
This commit is contained in:
commit
f53835f110
39
Documentation/ABI/testing/debugfs-iio-ad9467
Normal file
39
Documentation/ABI/testing/debugfs-iio-ad9467
Normal file
@ -0,0 +1,39 @@
|
||||
What: /sys/kernel/debug/iio/iio:deviceX/calibration_table_dump
|
||||
KernelVersion: 6.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This dumps the calibration table that was filled during the
|
||||
digital interface tuning process.
|
||||
|
||||
What: /sys/kernel/debug/iio/iio:deviceX/in_voltage_test_mode_available
|
||||
KernelVersion: 6.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
List all the available test tones:
|
||||
- off
|
||||
- midscale_short
|
||||
- pos_fullscale
|
||||
- neg_fullscale
|
||||
- checkerboard
|
||||
- prbs23
|
||||
- prbs9
|
||||
- one_zero_toggle
|
||||
- user
|
||||
- bit_toggle
|
||||
- sync
|
||||
- one_bit_high
|
||||
- mixed_bit_frequency
|
||||
- ramp
|
||||
|
||||
Note that depending on the actual device being used, some of the
|
||||
above might not be available (and they won't be listed when
|
||||
reading the file).
|
||||
|
||||
What: /sys/kernel/debug/iio/iio:deviceX/in_voltageY_test_mode
|
||||
KernelVersion: 6.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Writing to this file will initiate one of available test tone on
|
||||
channel Y. Reading it, shows which test is running. In cases
|
||||
where an IIO backend is available and supports the test tone,
|
||||
additional information about the data correctness is given.
|
20
Documentation/ABI/testing/debugfs-iio-backend
Normal file
20
Documentation/ABI/testing/debugfs-iio-backend
Normal file
@ -0,0 +1,20 @@
|
||||
What: /sys/kernel/debug/iio/iio:deviceX/backendY/name
|
||||
KernelVersion: 6.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Name of Backend Y connected to device X.
|
||||
|
||||
What: /sys/kernel/debug/iio/iio:deviceX/backendY/direct_reg_access
|
||||
KernelVersion: 6.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Directly access the registers of backend Y. Typical usage is:
|
||||
|
||||
Reading address 0x50
|
||||
echo 0x50 > direct_reg_access
|
||||
cat direct_reg_access
|
||||
|
||||
Writing address 0x50
|
||||
echo 0x50 0x3 > direct_reg_access
|
||||
//readback address 0x50
|
||||
cat direct_reg_access
|
@ -523,13 +523,26 @@ Description:
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltageY_i_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltageY_q_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_capacitance_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_resistance_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_calibbias
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
@ -541,6 +554,9 @@ Description:
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_calibbias_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_calibbias_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_calibbias_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity_calibbias_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_calibbias_available
|
||||
KernelVersion: 5.8
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
@ -549,25 +565,34 @@ Description:
|
||||
- a small discrete set of values like "0 2 4 6 8"
|
||||
- a range specified as "[min step max]"
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_capacitance_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_both_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ir_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_calibscale
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
@ -575,6 +600,19 @@ Description:
|
||||
production inaccuracies). If shared across all channels,
|
||||
<type>_calibscale is used.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_illuminanceY_calibscale_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_calibscale_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximityY_calibscale_available
|
||||
KernelVersion: 4.8
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Available values of calibscale. Maybe expressed as either of:
|
||||
|
||||
- a small discrete set of values like "1 8 16"
|
||||
- a range specified as "[min step max]"
|
||||
|
||||
If shared across all channels, <type>_calibscale_available is used.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_activity_calibgender
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_energy_calibgender
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_distance_calibgender
|
||||
@ -708,6 +746,7 @@ Description:
|
||||
2.5kohm_to_gnd: connected to ground via a 2.5kOhm resistor,
|
||||
6kohm_to_gnd: connected to ground via a 6kOhm resistor,
|
||||
20kohm_to_gnd: connected to ground via a 20kOhm resistor,
|
||||
42kohm_to_gnd: connected to ground via a 42kOhm resistor,
|
||||
90kohm_to_gnd: connected to ground via a 90kOhm resistor,
|
||||
100kohm_to_gnd: connected to ground via an 100kOhm resistor,
|
||||
125kohm_to_gnd: connected to ground via an 125kOhm resistor,
|
||||
@ -2289,3 +2328,11 @@ KernelVersion: 6.7
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
List of available timeout value for tap gesture confirmation.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_shunt_resistor
|
||||
What: /sys/.../iio:deviceX/in_current_shunt_resistor
|
||||
What: /sys/.../iio:deviceX/in_power_shunt_resistor
|
||||
KernelVersion: 6.10
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
The value of current sense resistor in Ohms.
|
||||
|
@ -1,17 +0,0 @@
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_power_shunt_resistor
|
||||
Date: March 2017
|
||||
KernelVersion: 4.12
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description: The value of the shunt resistor used to compute power drain on
|
||||
common input voltage pin (RS+). In Ohms.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_current_shunt_resistor
|
||||
Date: March 2017
|
||||
KernelVersion: 4.12
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description: The value of the shunt resistor used to compute current flowing
|
||||
between RS+ and RS- voltage sense inputs. In Ohms.
|
||||
|
||||
These attributes describe a single physical component, exposed as two distinct
|
||||
attributes as it is used to calculate two different values: power load and
|
||||
current flowing between RS+ and RS- inputs.
|
@ -15,17 +15,3 @@ Description:
|
||||
Set the relative humidity. This value is sent to the sensor for
|
||||
humidity compensation.
|
||||
Default value: 50000 (50 % relative humidity)
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_resistance_calibbias
|
||||
Date: August 2021
|
||||
KernelVersion: 5.15
|
||||
Contact: Andreas Klinger <ak@it-klinger.de>
|
||||
Description:
|
||||
Set the bias value for the resistance which is used for
|
||||
calculation of in_concentration_input as follows:
|
||||
|
||||
x = (in_resistance_raw - in_resistance_calibbias) * 0.65
|
||||
|
||||
in_concentration_input = 500 / (1 + e^x)
|
||||
|
||||
Default value: 30000
|
||||
|
61
Documentation/ABI/testing/sysfs-bus-iio-dac
Normal file
61
Documentation/ABI/testing/sysfs-bus-iio-dac
Normal file
@ -0,0 +1,61 @@
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_toggle_en
|
||||
KernelVersion: 5.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Toggle enable. Write 1 to enable toggle or 0 to disable it. This
|
||||
is useful when one wants to change the DAC output codes. For
|
||||
autonomous toggling, the way it should be done is:
|
||||
|
||||
- disable toggle operation;
|
||||
- change out_currentY_rawN, where N is the integer value of the symbol;
|
||||
- enable toggle operation.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_rawN
|
||||
KernelVersion: 5.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This attribute has the same meaning as out_currentY_raw. It is
|
||||
specific to toggle enabled channels and refers to the DAC output
|
||||
code in INPUT_N (_rawN), where N is the integer value of the symbol.
|
||||
The same scale and offset as in out_currentY_raw applies.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_symbol
|
||||
KernelVersion: 5.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Performs a SW switch to a predefined output symbol. This attribute
|
||||
is specific to toggle enabled channels and allows switching between
|
||||
multiple predefined symbols. Each symbol corresponds to a different
|
||||
output, denoted as out_currentY_rawN, where N is the integer value
|
||||
of the symbol. Writing an integer value N will select out_currentY_rawN.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_toggle_en
|
||||
KernelVersion: 5.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Toggle enable. Write 1 to enable toggle or 0 to disable it. This
|
||||
is useful when one wants to change the DAC output codes. For
|
||||
autonomous toggling, the way it should be done is:
|
||||
|
||||
- disable toggle operation;
|
||||
- change out_voltageY_rawN, where N is the integer value of the symbol;
|
||||
- enable toggle operation.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_rawN
|
||||
KernelVersion: 5.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This attribute has the same meaning as out_currentY_raw. It is
|
||||
specific to toggle enabled channels and refers to the DAC output
|
||||
code in INPUT_N (_rawN), where N is the integer value of the symbol.
|
||||
The same scale and offset as in out_currentY_raw applies.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_symbol
|
||||
KernelVersion: 5.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Performs a SW switch to a predefined output symbol. This attribute
|
||||
is specific to toggle enabled channels and allows switching between
|
||||
multiple predefined symbols. Each symbol corresponds to a different
|
||||
output, denoted as out_voltageY_rawN, where N is the integer value
|
||||
of the symbol. Writing an integer value N will select out_voltageY_rawN.
|
@ -53,34 +53,3 @@ KernelVersion: 5.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Returns the available values for the dither phase.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_toggle_en
|
||||
KernelVersion: 5.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Toggle enable. Write 1 to enable toggle or 0 to disable it. This is
|
||||
useful when one wants to change the DAC output codes. The way it should
|
||||
be done is:
|
||||
|
||||
- disable toggle operation;
|
||||
- change out_voltageY_raw0 and out_voltageY_raw1;
|
||||
- enable toggle operation.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw0
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw1
|
||||
KernelVersion: 5.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
It has the same meaning as out_voltageY_raw. This attribute is
|
||||
specific to toggle enabled channels and refers to the DAC output
|
||||
code in INPUT_A (_raw0) and INPUT_B (_raw1). The same scale and offset
|
||||
as in out_voltageY_raw applies.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_symbol
|
||||
KernelVersion: 5.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Performs a SW toggle. This attribute is specific to toggle
|
||||
enabled channels and allows to toggle between out_voltageY_raw0
|
||||
and out_voltageY_raw1 through software. Writing 0 will select
|
||||
out_voltageY_raw0 while 1 selects out_voltageY_raw1.
|
||||
|
@ -3,7 +3,7 @@ KernelVersion:
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Reading this returns the valid values that can be written to the
|
||||
on_altvoltage0_mode attribute:
|
||||
filter_mode attribute:
|
||||
|
||||
- auto -> Adjust bandpass filter to track changes in input clock rate.
|
||||
- manual -> disable/unregister the clock rate notifier / input clock tracking.
|
||||
|
@ -13,12 +13,3 @@ Description:
|
||||
available for reading data. However, samples can be occasionally skipped
|
||||
or repeated, depending on the beat between the capture and conversion
|
||||
rates.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_shunt_resistor
|
||||
Date: December 2015
|
||||
KernelVersion: 4.4
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
The value of the shunt resistor may be known only at runtime fom an
|
||||
eeprom content read by a client application. This attribute allows to
|
||||
set its value in ohms.
|
||||
|
92
Documentation/devicetree/bindings/iio/accel/adi,adxl380.yaml
Normal file
92
Documentation/devicetree/bindings/iio/accel/adi,adxl380.yaml
Normal file
@ -0,0 +1,92 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/accel/adi,adxl380.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices ADXL380/382 3-Axis Digital Accelerometer
|
||||
|
||||
maintainers:
|
||||
- Ramona Gradinariu <ramona.gradinariu@analog.com>
|
||||
- Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
|
||||
description: |
|
||||
The ADXL380/ADXL382 is a low noise density, low power, 3-axis
|
||||
accelerometer with selectable measurement ranges. The ADXL380
|
||||
supports the ±4 g, ±8 g, and ±16 g ranges, and the ADXL382 supports
|
||||
±15 g, ±30 g, and ±60 g ranges.
|
||||
|
||||
https://www.analog.com/en/products/adxl380.html
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,adxl380
|
||||
- adi,adxl382
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
interrupt-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- enum: [INT0, INT1]
|
||||
- const: INT1
|
||||
|
||||
vddio-supply: true
|
||||
|
||||
vsupply-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- vddio-supply
|
||||
- vsupply-supply
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
accelerometer@54 {
|
||||
compatible = "adi,adxl380";
|
||||
reg = <0x54>;
|
||||
vddio-supply = <&vddio>;
|
||||
vsupply-supply = <&vsupply>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <25 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "INT0";
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
accelerometer@0 {
|
||||
compatible = "adi,adxl380";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <8000000>;
|
||||
vddio-supply = <&vddio>;
|
||||
vsupply-supply = <&vsupply>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <25 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "INT0";
|
||||
};
|
||||
};
|
@ -16,6 +16,7 @@ properties:
|
||||
- kionix,kxcj91008
|
||||
- kionix,kxtj21009
|
||||
- kionix,kxtf9
|
||||
- kionix,kx022-1020
|
||||
- kionix,kx023-1025
|
||||
|
||||
reg:
|
||||
|
197
Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml
Normal file
197
Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml
Normal file
@ -0,0 +1,197 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/adi,ad4000.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD4000 and similar Analog to Digital Converters
|
||||
|
||||
maintainers:
|
||||
- Marcelo Schmitt <marcelo.schmitt@analog.com>
|
||||
|
||||
description: |
|
||||
Analog Devices AD4000 family of Analog to Digital Converters with SPI support.
|
||||
Specifications can be found at:
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4000-4004-4008.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4001-4005.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4002-4006-4010.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4003-4007-4011.pdf
|
||||
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
|
||||
|
||||
$ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: adi,ad4000
|
||||
- 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
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 102040816 # for VIO > 2.7 V, 81300813 for VIO > 1.7 V
|
||||
|
||||
adi,sdi-pin:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
enum: [ high, low, cs, sdi ]
|
||||
default: sdi
|
||||
description:
|
||||
Describes how the ADC SDI pin is wired. A value of "sdi" indicates that
|
||||
the ADC SDI is connected to host SDO. "high" indicates that the ADC SDI
|
||||
pin is hard-wired to logic high (VIO). "low" indicates that it is
|
||||
hard-wired low (GND). "cs" indicates that the ADC SDI pin is connected to
|
||||
the host CS line.
|
||||
|
||||
'#daisy-chained-devices': true
|
||||
|
||||
vdd-supply:
|
||||
description: A 1.8V supply that powers the chip (VDD).
|
||||
|
||||
vio-supply:
|
||||
description:
|
||||
A 1.8V to 5.5V supply for the digital inputs and outputs (VIO).
|
||||
|
||||
ref-supply:
|
||||
description:
|
||||
A 2.5 to 5V supply for the external reference voltage (REF).
|
||||
|
||||
cnv-gpios:
|
||||
description:
|
||||
When provided, this property indicates the GPIO that is connected to the
|
||||
CNV pin.
|
||||
maxItems: 1
|
||||
|
||||
adi,high-z-input:
|
||||
type: boolean
|
||||
description:
|
||||
High-Z mode allows the amplifier and RC filter in front of the ADC to be
|
||||
chosen based on the signal bandwidth of interest, rather than the settling
|
||||
requirements of the switched capacitor SAR ADC inputs.
|
||||
|
||||
adi,gain-milli:
|
||||
description: |
|
||||
The hardware gain applied to the ADC input (in milli units).
|
||||
The gain provided by the ADC input scaler is defined by the hardware
|
||||
connections between chip pins OUT+, R1K-, R1K1-, R1K+, R1K1+, and OUT-.
|
||||
If not present, default to 1000 (no actual gain applied).
|
||||
$ref: /schemas/types.yaml#/definitions/uint16
|
||||
enum: [454, 909, 1000, 1900]
|
||||
default: 1000
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
The SDO pin can also function as a busy indicator. This node should be
|
||||
connected to an interrupt that is triggered when the SDO line goes low
|
||||
while the SDI line is high and the CNV line is low ("3-wire" mode) or the
|
||||
SDI line is low and the CNV line is high ("4-wire" mode); or when the SDO
|
||||
line goes high while the SDI and CNV lines are high (chain mode),
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
- vio-supply
|
||||
- ref-supply
|
||||
|
||||
allOf:
|
||||
# The configuration register can only be accessed if SDI is connected to MOSI
|
||||
- if:
|
||||
required:
|
||||
- adi,sdi-pin
|
||||
then:
|
||||
properties:
|
||||
adi,high-z-input: false
|
||||
# chain mode has lower SCLK max rate
|
||||
- if:
|
||||
required:
|
||||
- '#daisy-chained-devices'
|
||||
then:
|
||||
properties:
|
||||
spi-max-frequency:
|
||||
maximum: 50000000 # for VIO > 2.7 V, 40000000 for VIO > 1.7 V
|
||||
# Gain property only applies to ADAQ devices
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
not:
|
||||
contains:
|
||||
enum:
|
||||
- adi,adaq4001
|
||||
- adi,adaq4003
|
||||
then:
|
||||
properties:
|
||||
adi,gain-milli: false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
adc@0 {
|
||||
compatible = "adi,ad4020";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <71000000>;
|
||||
vdd-supply = <&supply_1_8V>;
|
||||
vio-supply = <&supply_1_8V>;
|
||||
ref-supply = <&supply_5V>;
|
||||
adi,sdi-pin = "cs";
|
||||
cnv-gpios = <&gpio0 88 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
adc@0 {
|
||||
compatible = "adi,adaq4003";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <80000000>;
|
||||
vdd-supply = <&supply_1_8V>;
|
||||
vio-supply = <&supply_1_8V>;
|
||||
ref-supply = <&supply_5V>;
|
||||
adi,high-z-input;
|
||||
adi,gain-milli = /bits/ 16 <454>;
|
||||
};
|
||||
};
|
254
Documentation/devicetree/bindings/iio/adc/adi,ad4695.yaml
Normal file
254
Documentation/devicetree/bindings/iio/adc/adi,ad4695.yaml
Normal file
@ -0,0 +1,254 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/adi,ad4695.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices Easy Drive Multiplexed SAR Analog to Digital Converters
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
- Nuno Sá <nuno.sa@analog.com>
|
||||
|
||||
description: |
|
||||
A family of similar multi-channel analog to digital converters with SPI bus.
|
||||
|
||||
* https://www.analog.com/en/products/ad4695.html
|
||||
* https://www.analog.com/en/products/ad4696.html
|
||||
* https://www.analog.com/en/products/ad4697.html
|
||||
* https://www.analog.com/en/products/ad4698.html
|
||||
|
||||
$ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad4695
|
||||
- adi,ad4696
|
||||
- adi,ad4697
|
||||
- adi,ad4698
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 80000000
|
||||
|
||||
spi-cpol: true
|
||||
spi-cpha: true
|
||||
|
||||
spi-rx-bus-width:
|
||||
minimum: 1
|
||||
maximum: 4
|
||||
|
||||
avdd-supply:
|
||||
description: Analog power supply.
|
||||
|
||||
vio-supply:
|
||||
description: I/O pin power supply.
|
||||
|
||||
ldo-in-supply:
|
||||
description: Internal LDO Input. Mutually exclusive with vdd-supply.
|
||||
|
||||
vdd-supply:
|
||||
description: Core power supply. Mutually exclusive with ldo-in-supply.
|
||||
|
||||
ref-supply:
|
||||
description:
|
||||
External reference voltage. Mutually exclusive with refin-supply.
|
||||
|
||||
refin-supply:
|
||||
description:
|
||||
Internal reference buffer input. Mutually exclusive with ref-supply.
|
||||
|
||||
com-supply:
|
||||
description: Common voltage supply for pseudo-differential analog inputs.
|
||||
|
||||
adi,no-ref-current-limit:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
When this flag is present, the REF Overvoltage Reduced Current protection
|
||||
is disabled.
|
||||
|
||||
adi,no-ref-high-z:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Enable this flag if the ref-supply requires Reference Input High-Z Mode
|
||||
to be disabled for proper operation.
|
||||
|
||||
cnv-gpios:
|
||||
description: The Convert Input (CNV). If omitted, CNV is tied to SPI CS.
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
description: The Reset Input (RESET). Should be configured GPIO_ACTIVE_LOW.
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: Signal coming from the BSY_ALT_GP0 pin (ALERT or BUSY).
|
||||
- description: Signal coming from the GP2 pin (ALERT).
|
||||
- description: Signal coming from the GP3 pin (BUSY).
|
||||
|
||||
interrupt-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: gp0
|
||||
- const: gp2
|
||||
- const: gp3
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
description: |
|
||||
The first cell is the GPn number: 0 to 3.
|
||||
The second cell takes standard GPIO flags.
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^in(?:[13579]|1[135])-supply$":
|
||||
description:
|
||||
Optional voltage supply for odd numbered channels when they are used as
|
||||
the negative input for a pseudo-differential channel.
|
||||
|
||||
"^channel@[0-9a-f]$":
|
||||
type: object
|
||||
$ref: adc.yaml
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Describes each individual channel. In addition the properties defined
|
||||
below, bipolar from adc.yaml is also supported.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
maximum: 15
|
||||
|
||||
common-mode-channel:
|
||||
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.
|
||||
enum: [1, 3, 5, 7, 9, 11, 13, 15, 0xFE, 0xFF]
|
||||
default: 0xFF
|
||||
|
||||
adi,no-high-z:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Enable this flag if the input pin requires the Analog Input High-Z
|
||||
Mode to be disabled for proper operation.
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
# bipolar mode can't be used with REFGND
|
||||
- if:
|
||||
properties:
|
||||
common-mode-channel:
|
||||
const: 0xFF
|
||||
then:
|
||||
properties:
|
||||
bipolar: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- avdd-supply
|
||||
- vio-supply
|
||||
|
||||
allOf:
|
||||
- oneOf:
|
||||
- required:
|
||||
- ldo-in-supply
|
||||
- required:
|
||||
- vdd-supply
|
||||
|
||||
- oneOf:
|
||||
- required:
|
||||
- ref-supply
|
||||
- required:
|
||||
- refin-supply
|
||||
|
||||
# the internal reference buffer always requires high-z mode
|
||||
- if:
|
||||
required:
|
||||
- refin-supply
|
||||
then:
|
||||
properties:
|
||||
adi,no-ref-high-z: false
|
||||
|
||||
# limit channels for 8-channel chips
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad4697
|
||||
- adi,ad4698
|
||||
then:
|
||||
patternProperties:
|
||||
"^in(?:9|1[135])-supply$": false
|
||||
"^channel@[0-7]$":
|
||||
properties:
|
||||
reg:
|
||||
maximum: 7
|
||||
common-mode-channel:
|
||||
enum: [1, 3, 5, 7, 0xFE, 0xFF]
|
||||
"^channel@[8-9a-f]$": false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/iio/adi,ad4695.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "adi,ad4695";
|
||||
reg = <0>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
spi-max-frequency = <80000000>;
|
||||
avdd-supply = <&power_supply>;
|
||||
ldo-in-supply = <&power_supply>;
|
||||
vio-supply = <&io_supply>;
|
||||
refin-supply = <&supply_5V>;
|
||||
com-supply = <&supply_2V5>;
|
||||
in3-supply = <&supply_2V5>;
|
||||
reset-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* Pseudo-differential channel between IN0 and REFGND. */
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
/* Pseudo-differential channel between IN1 and COM. */
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
common-mode-channel = <AD4695_COMMON_MODE_COM>;
|
||||
bipolar;
|
||||
};
|
||||
|
||||
/* Pseudo-differential channel between IN2 and IN3. */
|
||||
channel@2 {
|
||||
reg = <2>;
|
||||
common-mode-channel = <3>;
|
||||
bipolar;
|
||||
};
|
||||
};
|
||||
};
|
@ -39,11 +39,21 @@ properties:
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description: phandle to the master clock (mclk)
|
||||
description:
|
||||
Optionally, either a crystal can be attached externally between MCLK1 and
|
||||
MCLK2 pins, or an external CMOS-compatible clock can drive the MCLK2
|
||||
pin. If absent, internal 4.92MHz clock is used, which can be made
|
||||
available on MCLK2 pin.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: mclk
|
||||
enum:
|
||||
- xtal
|
||||
- mclk
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
description:
|
||||
If present when internal clock is used, configured as clock provider.
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
@ -134,8 +144,6 @@ patternProperties:
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- dvdd-supply
|
||||
- avdd-supply
|
||||
@ -156,6 +164,18 @@ allOf:
|
||||
then:
|
||||
patternProperties:
|
||||
"^channel@[0-9a-f]+$": false
|
||||
- if:
|
||||
anyOf:
|
||||
- required:
|
||||
- clocks
|
||||
- required:
|
||||
- clock-names
|
||||
then:
|
||||
properties:
|
||||
"#clock-cells": false
|
||||
required:
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
@ -201,8 +221,7 @@ examples:
|
||||
spi-max-frequency = <1000000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
clocks = <&ad7192_mclk>;
|
||||
clock-names = "mclk";
|
||||
#clock-cells = <0>;
|
||||
interrupts = <25 0x2>;
|
||||
interrupt-parent = <&gpio>;
|
||||
aincom-supply = <&aincom>;
|
||||
|
@ -15,10 +15,17 @@ description: |
|
||||
* https://www.analog.com/en/products/ad7381.html
|
||||
* https://www.analog.com/en/products/ad7383.html
|
||||
* https://www.analog.com/en/products/ad7384.html
|
||||
* https://www.analog.com/en/products/ad7386.html
|
||||
* https://www.analog.com/en/products/ad7387.html
|
||||
* https://www.analog.com/en/products/ad7388.html
|
||||
* https://www.analog.com/en/products/ad7380-4.html
|
||||
* https://www.analog.com/en/products/ad7381-4.html
|
||||
* https://www.analog.com/en/products/ad7383-4.html
|
||||
* https://www.analog.com/en/products/ad7384-4.html
|
||||
* https://www.analog.com/en/products/ad7386-4.html
|
||||
* https://www.analog.com/en/products/ad7387-4.html
|
||||
* https://www.analog.com/en/products/ad7388-4.html
|
||||
|
||||
|
||||
$ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
@ -29,10 +36,16 @@ properties:
|
||||
- adi,ad7381
|
||||
- adi,ad7383
|
||||
- adi,ad7384
|
||||
- adi,ad7386
|
||||
- adi,ad7387
|
||||
- adi,ad7388
|
||||
- adi,ad7380-4
|
||||
- adi,ad7381-4
|
||||
- adi,ad7383-4
|
||||
- adi,ad7384-4
|
||||
- adi,ad7386-4
|
||||
- adi,ad7387-4
|
||||
- adi,ad7388-4
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -35,65 +35,83 @@ properties:
|
||||
|
||||
avcc-supply: true
|
||||
|
||||
vdrive-supply:
|
||||
description:
|
||||
Determines the voltage level at which the interface logic pins will
|
||||
operate.
|
||||
|
||||
refin-supply:
|
||||
description:
|
||||
The voltage supply for optional external reference voltage.
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
The BUSY pin falling edge indicates that the conversion is over, and thus
|
||||
new data is available.
|
||||
maxItems: 1
|
||||
|
||||
adi,conversion-start-gpios:
|
||||
description:
|
||||
Must be the device tree identifier of the CONVST pin.
|
||||
This logic input is used to initiate conversions on the analog
|
||||
input channels. As the line is active high, it should be marked
|
||||
GPIO_ACTIVE_HIGH.
|
||||
maxItems: 1
|
||||
Must be the device tree identifier of the CONVST pin(s). This logic input
|
||||
is used to initiate conversions on the analog input channels. As the line
|
||||
is active high, it should be marked GPIO_ACTIVE_HIGH.
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
reset-gpios:
|
||||
description:
|
||||
Must be the device tree identifier of the RESET pin. If specified,
|
||||
it will be asserted during driver probe. As the line is active high,
|
||||
it should be marked GPIO_ACTIVE_HIGH.
|
||||
Must be the device tree identifier of the RESET pin. If specified, it will
|
||||
be asserted during driver probe. On the AD7606x, as the line is active
|
||||
high, it should be marked GPIO_ACTIVE_HIGH. On the AD7616, as the line is
|
||||
active low, it should be marked GPIO_ACTIVE_LOW.
|
||||
maxItems: 1
|
||||
|
||||
standby-gpios:
|
||||
description:
|
||||
Must be the device tree identifier of the STBY pin. This pin is used
|
||||
to place the AD7606 into one of two power-down modes, Standby mode or
|
||||
Must be the device tree identifier of the STBY pin. This pin is used to
|
||||
place the AD7606 into one of two power-down modes, Standby mode or
|
||||
Shutdown mode. As the line is active low, it should be marked
|
||||
GPIO_ACTIVE_LOW.
|
||||
maxItems: 1
|
||||
|
||||
adi,first-data-gpios:
|
||||
description:
|
||||
Must be the device tree identifier of the FRSTDATA pin.
|
||||
The FRSTDATA output indicates when the first channel, V1, is
|
||||
being read back on either the parallel, byte or serial interface.
|
||||
As the line is active high, it should be marked GPIO_ACTIVE_HIGH.
|
||||
Must be the device tree identifier of the FRSTDATA pin. The FRSTDATA
|
||||
output indicates when the first channel, V1, is being read back on either
|
||||
the parallel, byte or serial interface. As the line is active high, it
|
||||
should be marked GPIO_ACTIVE_HIGH.
|
||||
maxItems: 1
|
||||
|
||||
adi,range-gpios:
|
||||
description:
|
||||
Must be the device tree identifier of the RANGE pin. The polarity on
|
||||
this pin determines the input range of the analog input channels. If
|
||||
this pin is tied to a logic high, the analog input range is ±10V for
|
||||
all channels. If this pin is tied to a logic low, the analog input range
|
||||
Must be the device tree identifier of the RANGE pin. The state on this
|
||||
pin determines the input range of the analog input channels. If this pin
|
||||
is tied to a logic high, the analog input range is ±10V for all channels.
|
||||
On the AD760X, if this pin is tied to a logic low, the analog input range
|
||||
is ±5V for all channels. As the line is active high, it should be marked
|
||||
GPIO_ACTIVE_HIGH.
|
||||
maxItems: 1
|
||||
GPIO_ACTIVE_HIGH. On the AD7616, there are 2 pins, and if the 2 pins are
|
||||
tied to a logic high, software mode is enabled, otherwise one of the 3
|
||||
possible range values is selected.
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
adi,oversampling-ratio-gpios:
|
||||
description:
|
||||
Must be the device tree identifier of the over-sampling
|
||||
mode pins. As the line is active high, it should be marked
|
||||
GPIO_ACTIVE_HIGH.
|
||||
Must be the device tree identifier of the over-sampling mode pins. As the
|
||||
line is active high, it should be marked GPIO_ACTIVE_HIGH. On the AD7606X
|
||||
parts that support it, if all 3 pins are tied to a logic high, software
|
||||
mode is enabled.
|
||||
maxItems: 3
|
||||
|
||||
adi,sw-mode:
|
||||
description:
|
||||
Software mode of operation, so far available only for ad7616 and ad7606b.
|
||||
It is enabled when all three oversampling mode pins are connected to
|
||||
high level. The device is configured by the corresponding registers. If the
|
||||
adi,oversampling-ratio-gpios property is defined, then the driver will set the
|
||||
oversampling gpios to high. Otherwise, it is assumed that the pins are hardwired
|
||||
to VDD.
|
||||
Software mode of operation, so far available only for AD7616 and AD7606B.
|
||||
It is enabled when all three oversampling mode pins are connected to high
|
||||
level for the AD7606B, or both the range selection are connected to high
|
||||
level for the AD7616. The device is configured by the corresponding
|
||||
registers. If the adi,oversampling-ratio-gpios property is defined, then
|
||||
the driver will set the oversampling gpios to high. Otherwise, it is
|
||||
assumed that the pins are hardwired to VDD.
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
@ -101,12 +119,57 @@ required:
|
||||
- reg
|
||||
- spi-cpha
|
||||
- avcc-supply
|
||||
- vdrive-supply
|
||||
- interrupts
|
||||
- adi,conversion-start-gpios
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: adi,ad7616
|
||||
then:
|
||||
properties:
|
||||
adi,first-data-gpios: false
|
||||
standby-gpios: false
|
||||
adi,range-gpios:
|
||||
maxItems: 2
|
||||
else:
|
||||
properties:
|
||||
adi,range-gpios:
|
||||
maxItems: 1
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad7605-4
|
||||
- adi,ad7616
|
||||
then:
|
||||
properties:
|
||||
adi,oversampling-ratio-gpios: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad7605-4
|
||||
- adi,ad7606-4
|
||||
- adi,ad7606-6
|
||||
- adi,ad7606-8
|
||||
then:
|
||||
properties:
|
||||
adi,sw-mode: false
|
||||
else:
|
||||
properties:
|
||||
adi,conversion-start-gpios:
|
||||
maxItems: 1
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
@ -125,6 +188,7 @@ examples:
|
||||
spi-cpha;
|
||||
|
||||
avcc-supply = <&adc_vref>;
|
||||
vdrive-supply = <&vdd_supply>;
|
||||
|
||||
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-parent = <&gpio>;
|
||||
@ -136,7 +200,6 @@ examples:
|
||||
<&gpio 23 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio 26 GPIO_ACTIVE_HIGH>;
|
||||
standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
|
||||
adi,sw-mode;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
@ -28,6 +28,9 @@ properties:
|
||||
- adi,ad9265
|
||||
- adi,ad9434
|
||||
- adi,ad9467
|
||||
- adi,ad9643
|
||||
- adi,ad9649
|
||||
- adi,ad9652
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -0,0 +1,71 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/microchip,pac1921.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip PAC1921 High-Side Power/Current Monitor with Anaog Output
|
||||
|
||||
maintainers:
|
||||
- Matteo Martelli <matteomartelli3@gmail.com>
|
||||
|
||||
description: |
|
||||
The PAC1921 is a power/current monitoring device with an analog output
|
||||
and I2C/SMBus interface.
|
||||
|
||||
Datasheet can be found here:
|
||||
https://ww1.microchip.com/downloads/en/DeviceDoc/PAC1921-Data-Sheet-DS20005293E.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: microchip,pac1921
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
shunt-resistor-micro-ohms:
|
||||
description:
|
||||
Value in micro Ohms of the shunt resistor connected between
|
||||
the SENSE+ and SENSE- inputs, across which the current is measured.
|
||||
Value is needed to compute the scaling of the measured current.
|
||||
|
||||
label:
|
||||
description: Unique name to identify which device this is.
|
||||
|
||||
read-integrate-gpios:
|
||||
description:
|
||||
READ/INT input pin to control the current state of the device, either in
|
||||
the INTEGRATE state when driven high, or in the READ state when driven low.
|
||||
When not connected the pin is floating and it can be overridden by the
|
||||
INT_EN register bit after asserting the READ/INT_OVR register bit.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
- shunt-resistor-micro-ohms
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@4c {
|
||||
compatible = "microchip,pac1921";
|
||||
reg = <0x4c>;
|
||||
vdd-supply = <&vdd>;
|
||||
#io-channel-cells = <1>;
|
||||
label = "vbat";
|
||||
shunt-resistor-micro-ohms = <10000>;
|
||||
};
|
||||
};
|
||||
...
|
@ -16,6 +16,9 @@ properties:
|
||||
- const: rockchip,rk3066-tsadc
|
||||
- const: rockchip,rk3399-saradc
|
||||
- const: rockchip,rk3588-saradc
|
||||
- items:
|
||||
- const: rockchip,rk3576-saradc
|
||||
- const: rockchip,rk3588-saradc
|
||||
- items:
|
||||
- enum:
|
||||
- rockchip,px30-saradc
|
||||
|
@ -18,18 +18,39 @@ properties:
|
||||
- sd-modulator
|
||||
- ads1201
|
||||
|
||||
'#io-backend-cells':
|
||||
const: 0
|
||||
|
||||
'#io-channel-cells':
|
||||
const: 0
|
||||
|
||||
vref-supply:
|
||||
description: Phandle to the vref input analog reference voltage.
|
||||
|
||||
dependencies:
|
||||
vref-supply: [ '#io-backend-cells' ]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- '#io-channel-cells'
|
||||
|
||||
anyOf:
|
||||
- required: ['#io-backend-cells']
|
||||
- required: ['#io-channel-cells']
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
ads1202: adc {
|
||||
// Backend binding example. SD modulator configured as an IIO backend device
|
||||
ads1201_0: adc {
|
||||
compatible = "sd-modulator";
|
||||
vref-supply = <&vdd_adc>;
|
||||
#io-backend-cells = <0>;
|
||||
};
|
||||
|
||||
- |
|
||||
// Legacy binding example. SD modulator configured as an IIO channel provider
|
||||
ads1201_1: adc {
|
||||
compatible = "sd-modulator";
|
||||
#io-channel-cells = <0>;
|
||||
};
|
||||
|
@ -54,7 +54,9 @@ properties:
|
||||
It's not present on stm32f4.
|
||||
It's required on stm32h7 and stm32mp1.
|
||||
|
||||
clock-names: true
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
st,max-clk-rate-hz:
|
||||
description:
|
||||
|
@ -102,9 +102,11 @@ patternProperties:
|
||||
items:
|
||||
minimum: 0
|
||||
maximum: 7
|
||||
deprecated: true
|
||||
|
||||
st,adc-channel-names:
|
||||
description: List of single-ended channel names.
|
||||
deprecated: true
|
||||
|
||||
st,filter-order:
|
||||
description: |
|
||||
@ -118,6 +120,12 @@ patternProperties:
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
st,adc-channel-types:
|
||||
description: |
|
||||
Single-ended channel input type.
|
||||
@ -128,6 +136,7 @@ patternProperties:
|
||||
items:
|
||||
enum: [ SPI_R, SPI_F, MANCH_R, MANCH_F ]
|
||||
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
|
||||
deprecated: true
|
||||
|
||||
st,adc-channel-clk-src:
|
||||
description: |
|
||||
@ -139,6 +148,7 @@ patternProperties:
|
||||
items:
|
||||
enum: [ CLKIN, CLKOUT, CLKOUT_F, CLKOUT_R ]
|
||||
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
|
||||
deprecated: true
|
||||
|
||||
st,adc-alt-channel:
|
||||
description:
|
||||
@ -147,6 +157,7 @@ patternProperties:
|
||||
If not set, channel n is connected to SPI input n.
|
||||
If set, channel n is connected to SPI input n + 1.
|
||||
type: boolean
|
||||
deprecated: true
|
||||
|
||||
st,filter0-sync:
|
||||
description:
|
||||
@ -165,11 +176,60 @@ patternProperties:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- st,adc-channels
|
||||
- st,adc-channel-names
|
||||
- st,filter-order
|
||||
- "#io-channel-cells"
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-7]$":
|
||||
type: object
|
||||
$ref: adc.yaml
|
||||
unevaluatedProperties: false
|
||||
description: Represents the external channels which are connected to the DFSDM.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
maximum: 7
|
||||
|
||||
label:
|
||||
description:
|
||||
Unique name to identify which channel this is.
|
||||
|
||||
st,adc-channel-type:
|
||||
description: |
|
||||
Single-ended channel input type.
|
||||
- "SPI_R": SPI with data on rising edge (default)
|
||||
- "SPI_F": SPI with data on falling edge
|
||||
- "MANCH_R": manchester codec, rising edge = logic 0, falling edge = logic 1
|
||||
- "MANCH_F": manchester codec, rising edge = logic 1, falling edge = logic 0
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
enum: [ SPI_R, SPI_F, MANCH_R, MANCH_F ]
|
||||
|
||||
st,adc-channel-clk-src:
|
||||
description: |
|
||||
Conversion clock source.
|
||||
- "CLKIN": external SPI clock (CLKIN x)
|
||||
- "CLKOUT": internal SPI clock (CLKOUT) (default)
|
||||
- "CLKOUT_F": internal SPI clock divided by 2 (falling edge).
|
||||
- "CLKOUT_R": internal SPI clock divided by 2 (rising edge).
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
enum: [ CLKIN, CLKOUT, CLKOUT_F, CLKOUT_R ]
|
||||
|
||||
st,adc-alt-channel:
|
||||
description:
|
||||
Must be defined if two sigma delta modulators are
|
||||
connected on same SPI input.
|
||||
If not set, channel n is connected to SPI input n.
|
||||
If set, channel n is connected to SPI input n + 1.
|
||||
type: boolean
|
||||
|
||||
io-backends:
|
||||
description:
|
||||
Used to pipe external sigma delta modulator or internal ADC backend to DFSDM channel.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
@ -199,9 +259,19 @@ patternProperties:
|
||||
description:
|
||||
From common IIO binding. Used to pipe external sigma delta
|
||||
modulator or internal ADC output to DFSDM channel.
|
||||
deprecated: true
|
||||
|
||||
required:
|
||||
- io-channels
|
||||
if:
|
||||
required:
|
||||
- st,adc-channels
|
||||
then:
|
||||
required:
|
||||
- io-channels
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-7]$":
|
||||
required:
|
||||
- io-backends
|
||||
|
||||
- if:
|
||||
properties:
|
||||
@ -298,6 +368,7 @@ examples:
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
// Example 1: Audio use case with generic binding
|
||||
dfsdm0: filter@0 {
|
||||
compatible = "st,stm32-dfsdm-dmic";
|
||||
reg = <0>;
|
||||
@ -305,12 +376,18 @@ examples:
|
||||
dmas = <&dmamux1 101 0x400 0x01>;
|
||||
dma-names = "rx";
|
||||
#io-channel-cells = <1>;
|
||||
st,adc-channels = <1>;
|
||||
st,adc-channel-names = "dmic0";
|
||||
st,adc-channel-types = "SPI_R";
|
||||
st,adc-channel-clk-src = "CLKOUT";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
st,filter-order = <5>;
|
||||
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
label = "dmic0";
|
||||
st,adc-channel-type = "SPI_R";
|
||||
st,adc-channel-clk-src = "CLKOUT";
|
||||
st,adc-alt-channel;
|
||||
};
|
||||
|
||||
asoc_pdm0: dfsdm-dai {
|
||||
compatible = "st,stm32h7-dfsdm-dai";
|
||||
#sound-dai-cells = <0>;
|
||||
@ -318,19 +395,34 @@ examples:
|
||||
};
|
||||
};
|
||||
|
||||
dfsdm_pdm1: filter@1 {
|
||||
// Example 2: Analog use case with generic binding
|
||||
dfsdm1: filter@1 {
|
||||
compatible = "st,stm32-dfsdm-adc";
|
||||
reg = <1>;
|
||||
interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dmamux1 102 0x400 0x01>;
|
||||
dma-names = "rx";
|
||||
#io-channel-cells = <1>;
|
||||
st,adc-channels = <2 3>;
|
||||
st,adc-channel-names = "in2", "in3";
|
||||
st,adc-channel-types = "SPI_R", "SPI_R";
|
||||
st,adc-channel-clk-src = "CLKOUT_F", "CLKOUT_F";
|
||||
io-channels = <&sd_adc2 &sd_adc3>;
|
||||
st,filter-order = <1>;
|
||||
#io-channel-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@2 {
|
||||
reg = <2>;
|
||||
label = "in2";
|
||||
st,adc-channel-type = "SPI_F";
|
||||
st,adc-channel-clk-src = "CLKOUT";
|
||||
st,adc-alt-channel;
|
||||
io-backends = <&sd_adc2>;
|
||||
};
|
||||
|
||||
channel@3 {
|
||||
reg = <3>;
|
||||
label = "in3";
|
||||
st,adc-channel-type = "SPI_R";
|
||||
st,adc-channel-clk-src = "CLKOUT";
|
||||
io-backends = <&sd_adc3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
181
Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml
Normal file
181
Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml
Normal file
@ -0,0 +1,181 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ltc2664.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices LTC2664 DAC
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
- Kim Seer Paller <kimseer.paller@analog.com>
|
||||
|
||||
description: |
|
||||
Analog Devices LTC2664 4 channel, 12-/16-Bit, +-10V DAC
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/2664fa.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ltc2664
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 50000000
|
||||
|
||||
vcc-supply:
|
||||
description: Analog Supply Voltage Input.
|
||||
|
||||
v-pos-supply:
|
||||
description: Positive Supply Voltage Input.
|
||||
|
||||
v-neg-supply:
|
||||
description: Negative Supply Voltage Input.
|
||||
|
||||
iovcc-supply:
|
||||
description: Digital Input/Output Supply Voltage.
|
||||
|
||||
ref-supply:
|
||||
description:
|
||||
Reference Input/Output. The voltage at the REF pin sets the full-scale
|
||||
range of all channels. If not provided the internal reference is used and
|
||||
also provided on the VREF pin.
|
||||
|
||||
reset-gpios:
|
||||
description:
|
||||
Active-low Asynchronous Clear Input. A logic low at this level-triggered
|
||||
input clears the part to the reset code and range determined by the
|
||||
hardwired option chosen using the MSPAN pins. The control registers are
|
||||
cleared to zero.
|
||||
maxItems: 1
|
||||
|
||||
adi,manual-span-operation-config:
|
||||
description:
|
||||
This property must mimic the MSPAN pin configurations. By tying the MSPAN
|
||||
pins (MSP2, MSP1 and MSP0) to GND and/or VCC, any output range can be
|
||||
hardware-configured with different mid-scale or zero-scale reset options.
|
||||
The hardware configuration is latched during power on reset for proper
|
||||
operation.
|
||||
0 - MPS2=GND, MPS1=GND, MSP0=GND (+-10V, reset to 0V)
|
||||
1 - MPS2=GND, MPS1=GND, MSP0=VCC (+-5V, reset to 0V)
|
||||
2 - MPS2=GND, MPS1=VCC, MSP0=GND (+-2.5V, reset to 0V)
|
||||
3 - MPS2=GND, MPS1=VCC, MSP0=VCC (0V to 10, reset to 0V)
|
||||
4 - MPS2=VCC, MPS1=GND, MSP0=GND (0V to 10V, reset to 5V)
|
||||
5 - MPS2=VCC, MPS1=GND, MSP0=VCC (0V to 5V, reset to 0V)
|
||||
6 - MPS2=VCC, MPS1=VCC, MSP0=GND (0V to 5V, reset to 2.5V)
|
||||
7 - MPS2=VCC, MPS1=VCC, MSP0=VCC (0V to 5V, reset to 0V, enables SoftSpan)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
default: 7
|
||||
|
||||
io-channels:
|
||||
description:
|
||||
ADC channel to monitor voltages and temperature at the MUXOUT pin.
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-3]$":
|
||||
$ref: dac.yaml
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: The channel number representing the DAC output channel.
|
||||
maximum: 3
|
||||
|
||||
adi,toggle-mode:
|
||||
description:
|
||||
Set the channel as a toggle enabled channel. Toggle operation enables
|
||||
fast switching of a DAC output between two different DAC codes without
|
||||
any SPI transaction.
|
||||
type: boolean
|
||||
|
||||
output-range-microvolt:
|
||||
description:
|
||||
This property is only allowed when SoftSpan is enabled. If not present,
|
||||
[0, 5000000] is the default output range.
|
||||
oneOf:
|
||||
- items:
|
||||
- const: 0
|
||||
- enum: [5000000, 10000000]
|
||||
- items:
|
||||
- const: -5000000
|
||||
- const: 5000000
|
||||
- items:
|
||||
- const: -10000000
|
||||
- const: 10000000
|
||||
- items:
|
||||
- const: -2500000
|
||||
- const: 2500000
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
adi,manual-span-operation-config:
|
||||
const: 7
|
||||
then:
|
||||
patternProperties:
|
||||
"^channel@[0-3]$":
|
||||
properties:
|
||||
output-range-microvolt: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- spi-max-frequency
|
||||
- vcc-supply
|
||||
- iovcc-supply
|
||||
- v-pos-supply
|
||||
- v-neg-supply
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@0 {
|
||||
compatible = "adi,ltc2664";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <10000000>;
|
||||
|
||||
vcc-supply = <&vcc>;
|
||||
iovcc-supply = <&vcc>;
|
||||
ref-supply = <&vref>;
|
||||
v-pos-supply = <&vpos>;
|
||||
v-neg-supply = <&vneg>;
|
||||
|
||||
io-channels = <&adc 0>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
adi,toggle-mode;
|
||||
output-range-microvolt = <(-10000000) 10000000>;
|
||||
};
|
||||
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
output-range-microvolt= <0 10000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
160
Documentation/devicetree/bindings/iio/dac/adi,ltc2672.yaml
Normal file
160
Documentation/devicetree/bindings/iio/dac/adi,ltc2672.yaml
Normal file
@ -0,0 +1,160 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ltc2672.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices LTC2672 DAC
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
- Kim Seer Paller <kimseer.paller@analog.com>
|
||||
|
||||
description: |
|
||||
Analog Devices LTC2672 5 channel, 12-/16-Bit, 300mA DAC
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ltc2672.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ltc2672
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 50000000
|
||||
|
||||
vcc-supply:
|
||||
description: Analog Supply Voltage Input.
|
||||
|
||||
v-neg-supply:
|
||||
description: Negative Supply Voltage Input.
|
||||
|
||||
vdd0-supply:
|
||||
description: Positive Supply Voltage Input for DAC OUT0.
|
||||
|
||||
vdd1-supply:
|
||||
description: Positive Supply Voltage Input for DAC OUT1.
|
||||
|
||||
vdd2-supply:
|
||||
description: Positive Supply Voltage Input for DAC OUT2.
|
||||
|
||||
vdd3-supply:
|
||||
description: Positive Supply Voltage Input for DAC OUT3.
|
||||
|
||||
vdd4-supply:
|
||||
description: Positive Supply Voltage Input for DAC OUT4.
|
||||
|
||||
iovcc-supply:
|
||||
description: Digital Input/Output Supply Voltage.
|
||||
|
||||
ref-supply:
|
||||
description:
|
||||
Reference Input/Output. The voltage at the REF pin sets the full-scale
|
||||
range of all channels. If not provided the internal reference is used and
|
||||
also provided on the VREF pin.
|
||||
|
||||
reset-gpios:
|
||||
description:
|
||||
Active Low Asynchronous Clear Input. A logic low at this level triggered
|
||||
input clears the device to the default reset code and output range, which
|
||||
is zero-scale with the outputs off. The control registers are cleared to
|
||||
zero.
|
||||
maxItems: 1
|
||||
|
||||
adi,rfsadj-ohms:
|
||||
description:
|
||||
If FSADJ is tied to VCC, an internal RFSADJ (20 kΩ) is selected, which
|
||||
results in nominal output ranges. When an external resistor of 19 kΩ to
|
||||
41 kΩ can be used instead by connecting the resistor between FSADJ and GND
|
||||
it controls the scaling of the ranges, and the internal resistor is
|
||||
automatically disconnected.
|
||||
minimum: 19000
|
||||
maximum: 41000
|
||||
default: 20000
|
||||
|
||||
io-channels:
|
||||
description:
|
||||
ADC channel to monitor voltages and currents at the MUX pin.
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-4]$":
|
||||
$ref: dac.yaml
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: The channel number representing the DAC output channel.
|
||||
maximum: 4
|
||||
|
||||
adi,toggle-mode:
|
||||
description:
|
||||
Set the channel as a toggle enabled channel. Toggle operation enables
|
||||
fast switching of a DAC output between two different DAC codes without
|
||||
any SPI transaction.
|
||||
type: boolean
|
||||
|
||||
output-range-microamp:
|
||||
items:
|
||||
- const: 0
|
||||
- enum: [3125000, 6250000, 12500000, 25000000, 50000000, 100000000,
|
||||
200000000, 300000000]
|
||||
|
||||
required:
|
||||
- reg
|
||||
- output-range-microamp
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- spi-max-frequency
|
||||
- vcc-supply
|
||||
- iovcc-supply
|
||||
- v-neg-supply
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@0 {
|
||||
compatible = "adi,ltc2672";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <10000000>;
|
||||
|
||||
vcc-supply = <&vcc>;
|
||||
iovcc-supply = <&vcc>;
|
||||
ref-supply = <&vref>;
|
||||
v-neg-supply = <&vneg>;
|
||||
|
||||
io-channels = <&adc 0>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
adi,toggle-mode;
|
||||
output-range-microamp = <0 3125000>;
|
||||
};
|
||||
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
output-range-microamp = <0 6250000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
50
Documentation/devicetree/bindings/iio/dac/dac.yaml
Normal file
50
Documentation/devicetree/bindings/iio/dac/dac.yaml
Normal file
@ -0,0 +1,50 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/dac.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: IIO Common Properties for DAC Channels
|
||||
|
||||
maintainers:
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
description:
|
||||
A few properties are defined in a common way for DAC channels.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^channel(@[0-9a-f]+)?$"
|
||||
description:
|
||||
A channel index should match reg.
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
label:
|
||||
description: Unique name to identify which channel this is.
|
||||
|
||||
output-range-microamp:
|
||||
maxItems: 2
|
||||
minItems: 2
|
||||
description:
|
||||
Specify the channel output full scale range in microamperes.
|
||||
|
||||
output-range-microvolt:
|
||||
maxItems: 2
|
||||
minItems: 2
|
||||
description:
|
||||
Specify the channel output full scale range in microvolts.
|
||||
|
||||
anyOf:
|
||||
- oneOf:
|
||||
- required:
|
||||
- reg
|
||||
- output-range-microamp
|
||||
- required:
|
||||
- reg
|
||||
- output-range-microvolt
|
||||
- required:
|
||||
- reg
|
||||
|
||||
additionalProperties: true
|
@ -17,6 +17,7 @@ description: |
|
||||
applications.
|
||||
|
||||
https://www.analog.com/en/products/adf4377.html
|
||||
https://www.analog.com/en/products/adf4378.html
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -73,6 +74,15 @@ required:
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,adf4378
|
||||
then:
|
||||
properties:
|
||||
clk2-enable-gpios: false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
@ -0,0 +1,55 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/humidity/sciosense,ens210.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ScioSense ENS210 temperature and humidity sensor
|
||||
|
||||
maintainers:
|
||||
- Joshua Felmeden <jfelmeden@thegoodpenguin.co.uk>
|
||||
|
||||
description: |
|
||||
Temperature and Humidity sensor.
|
||||
|
||||
Datasheet:
|
||||
https://www.sciosense.com/wp-content/uploads/2024/04/ENS21x-Datasheet.pdf
|
||||
https://www.sciosense.com/wp-content/uploads/2023/12/ENS210-Datasheet.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- sciosense,ens210a
|
||||
- sciosense,ens211
|
||||
- sciosense,ens212
|
||||
- sciosense,ens213a
|
||||
- sciosense,ens215
|
||||
- const: sciosense,ens210
|
||||
- const: sciosense,ens210
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
temperature-sensor@43 {
|
||||
compatible = "sciosense,ens210";
|
||||
reg = <0x43>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
@ -14,7 +14,9 @@ description:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: liteon,ltrf216a
|
||||
enum:
|
||||
- liteon,ltr308
|
||||
- liteon,ltrf216a
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
53
Documentation/devicetree/bindings/iio/light/rohm,bh1745.yaml
Normal file
53
Documentation/devicetree/bindings/iio/light/rohm,bh1745.yaml
Normal file
@ -0,0 +1,53 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/light/rohm,bh1745.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ROHM BH1745 colour sensor
|
||||
|
||||
maintainers:
|
||||
- Mudit Sharma <muditsharma.info@gmail.com>
|
||||
|
||||
description:
|
||||
BH1745 is an I2C colour sensor with red, green, blue and clear
|
||||
channels. It has a programmable active low interrupt pin.
|
||||
Interrupt occurs when the signal from the selected interrupt
|
||||
source channel crosses set interrupt threshold high/low level.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: rohm,bh1745
|
||||
|
||||
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>;
|
||||
|
||||
colour-sensor@38 {
|
||||
compatible = "rohm,bh1745";
|
||||
reg = <0x38>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
|
||||
vdd-supply = <&vdd>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -1,23 +1,22 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/light/rohm,bu27034.yaml#
|
||||
$id: http://devicetree.org/schemas/iio/light/rohm,bu27034anuc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ROHM BU27034 ambient light sensor
|
||||
title: ROHM BU27034ANUC ambient light sensor
|
||||
|
||||
maintainers:
|
||||
- Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
|
||||
description: |
|
||||
ROHM BU27034 is an ambient light sesnor with 3 channels and 3 photo diodes
|
||||
ROHM BU27034ANUC is an ambient light sensor with 2 channels and 2 photo diodes
|
||||
capable of detecting a very wide range of illuminance. Typical application
|
||||
is adjusting LCD and backlight power of TVs and mobile phones.
|
||||
https://fscdn.rohm.com/en/products/databook/datasheet/ic/sensor/light/bu27034nuc-e.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: rohm,bu27034
|
||||
const: rohm,bu27034anuc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -37,7 +36,7 @@ examples:
|
||||
#size-cells = <0>;
|
||||
|
||||
light-sensor@38 {
|
||||
compatible = "rohm,bu27034";
|
||||
compatible = "rohm,bu27034anuc";
|
||||
reg = <0x38>;
|
||||
vdd-supply = <&vdd>;
|
||||
};
|
@ -18,10 +18,15 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- sensortek,stk3310
|
||||
- sensortek,stk3311
|
||||
- sensortek,stk3335
|
||||
oneOf:
|
||||
- enum:
|
||||
- sensortek,stk3310
|
||||
- sensortek,stk3311
|
||||
- sensortek,stk3335
|
||||
- items:
|
||||
- enum:
|
||||
- sensortek,stk3013
|
||||
- const: sensortek,stk3310
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -23,7 +23,6 @@ properties:
|
||||
- ak8963
|
||||
- ak09911
|
||||
- ak09912
|
||||
- ak09916
|
||||
deprecated: true
|
||||
|
||||
reg:
|
||||
|
@ -36,6 +36,9 @@ properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
mount-matrix:
|
||||
description: an optional 3x3 mounting rotation matrix.
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
|
@ -0,0 +1,46 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/pressure/sensirion,sdp500.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: sdp500/sdp510 pressure sensor with I2C bus interface
|
||||
|
||||
maintainers:
|
||||
- Petar Stoykov <petar.stoykov@prodrive-technologies.com>
|
||||
|
||||
description: |
|
||||
Pressure sensor from Sensirion with I2C bus interface.
|
||||
There is no software difference between sdp500 and sdp510.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: sensirion,sdp510
|
||||
- const: sensirion,sdp500
|
||||
- const: sensirion,sdp500
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
pressure@40 {
|
||||
compatible = "sensirion,sdp500";
|
||||
reg = <0x40>;
|
||||
vdd-supply = <&foo>;
|
||||
};
|
||||
};
|
@ -0,0 +1,93 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/proximity/tyhx,hx9023s.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: TYHX HX9023S capacitive proximity sensor
|
||||
|
||||
maintainers:
|
||||
- Yasin Lee <yasin.lee.x@gmail.com>
|
||||
|
||||
description: |
|
||||
TYHX HX9023S proximity sensor. Datasheet can be found here:
|
||||
http://www.tianyihexin.com/ueditor/php/upload/file/20240614/1718336303992081.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: tyhx,hx9023s
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
Generated by device to announce preceding read request has finished
|
||||
and data is available or that a close/far proximity event has happened.
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-4]$":
|
||||
$ref: /schemas/iio/adc/adc.yaml
|
||||
type: object
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 4
|
||||
description: The channel number.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
proximity@2a {
|
||||
compatible = "tyhx,hx9023s";
|
||||
reg = <0x2a>;
|
||||
interrupt-parent = <&pio>;
|
||||
interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
|
||||
vdd-supply = <&pp1800_prox>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
single-channel = <0>;
|
||||
};
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
single-channel = <1>;
|
||||
};
|
||||
channel@2 {
|
||||
reg = <2>;
|
||||
single-channel = <2>;
|
||||
};
|
||||
channel@3 {
|
||||
reg = <3>;
|
||||
diff-channels = <1 0>;
|
||||
};
|
||||
channel@4 {
|
||||
reg = <4>;
|
||||
diff-channels = <2 0>;
|
||||
};
|
||||
};
|
||||
};
|
@ -1535,6 +1535,8 @@ patternProperties:
|
||||
description: Turing Machines, Inc.
|
||||
"^tyan,.*":
|
||||
description: Tyan Computer Corporation
|
||||
"^tyhx,.*":
|
||||
description: NanjingTianyihexin Electronics Ltd.
|
||||
"^u-blox,.*":
|
||||
description: u-blox
|
||||
"^u-boot,.*":
|
||||
|
131
Documentation/iio/ad4000.rst
Normal file
131
Documentation/iio/ad4000.rst
Normal file
@ -0,0 +1,131 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
=============
|
||||
AD4000 driver
|
||||
=============
|
||||
|
||||
Device driver for Analog Devices Inc. AD4000 series of ADCs.
|
||||
|
||||
Supported devices
|
||||
=================
|
||||
|
||||
* `AD4000 <https://www.analog.com/AD4000>`_
|
||||
* `AD4001 <https://www.analog.com/AD4001>`_
|
||||
* `AD4002 <https://www.analog.com/AD4002>`_
|
||||
* `AD4003 <https://www.analog.com/AD4003>`_
|
||||
* `AD4004 <https://www.analog.com/AD4004>`_
|
||||
* `AD4005 <https://www.analog.com/AD4005>`_
|
||||
* `AD4006 <https://www.analog.com/AD4006>`_
|
||||
* `AD4007 <https://www.analog.com/AD4007>`_
|
||||
* `AD4008 <https://www.analog.com/AD4008>`_
|
||||
* `AD4010 <https://www.analog.com/AD4010>`_
|
||||
* `AD4011 <https://www.analog.com/AD4011>`_
|
||||
* `AD4020 <https://www.analog.com/AD4020>`_
|
||||
* `AD4021 <https://www.analog.com/AD4021>`_
|
||||
* `AD4022 <https://www.analog.com/AD4022>`_
|
||||
* `ADAQ4001 <https://www.analog.com/ADAQ4001>`_
|
||||
* `ADAQ4003 <https://www.analog.com/ADAQ4003>`_
|
||||
|
||||
Wiring connections
|
||||
------------------
|
||||
|
||||
Devices of the AD4000 series can be connected to the SPI host controller in a
|
||||
few different modes.
|
||||
|
||||
CS mode, 3-wire turbo mode
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Datasheet "3-wire" mode is what most resembles standard SPI connection which,
|
||||
for these devices, comprises of connecting the controller CS line to device CNV
|
||||
pin and other SPI lines as usual. This configuration is (misleadingly) called
|
||||
"CS Mode, 3-Wire Turbo Mode" connection in datasheets.
|
||||
NOTE: The datasheet definition of 3-wire mode for the AD4000 series is NOT the
|
||||
same of standard spi-3wire mode.
|
||||
This is the only connection mode that allows configuration register access but
|
||||
it requires the SPI controller to support the ``SPI_MOSI_IDLE_HIGH`` feature.
|
||||
|
||||
Omit the ``adi,sdi-pin`` property in device tree to select this mode.
|
||||
|
||||
::
|
||||
|
||||
+-------------+
|
||||
+ ----------------------------------| SDO |
|
||||
| | |
|
||||
| +-------------------| CS |
|
||||
| v | |
|
||||
| +--------------------+ | HOST |
|
||||
| | CNV | | |
|
||||
+--->| SDI AD4000 SDO |-------->| SDI |
|
||||
| SCK | | |
|
||||
+--------------------+ | |
|
||||
^ | |
|
||||
+--------------------| SCLK |
|
||||
+-------------+
|
||||
|
||||
CS mode, 3-wire, without busy indicator
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Another wiring configuration supported as "3-wire" mode has the SDI pin
|
||||
hard-wired to digital input/output interface supply (VIO). In this setup, the
|
||||
controller is not required to support ``SPI_MOSI_IDLE_HIGH`` but register access
|
||||
is not possible. This connection mode saves one wire and works with any SPI
|
||||
controller.
|
||||
|
||||
Set the ``adi,sdi-pin`` device tree property to ``"high"`` to select this mode.
|
||||
|
||||
::
|
||||
|
||||
+-------------+
|
||||
+--------------------| CS |
|
||||
v | |
|
||||
VIO +--------------------+ | HOST |
|
||||
| | CNV | | |
|
||||
+--->| SDI AD4000 SDO |-------->| SDI |
|
||||
| SCK | | |
|
||||
+--------------------+ | |
|
||||
^ | |
|
||||
+--------------------| SCLK |
|
||||
+-------------+
|
||||
|
||||
Alternatively, a GPIO may be connected to the device CNV pin. This is similar to
|
||||
the previous wiring configuration but saves the use of a CS line.
|
||||
|
||||
::
|
||||
|
||||
+-------------+
|
||||
+--------------------| GPIO |
|
||||
v | |
|
||||
VIO +--------------------+ | HOST |
|
||||
| | CNV | | |
|
||||
+--->| SDI AD4000 SDO |-------->| SDI |
|
||||
| SCK | | |
|
||||
+--------------------+ | |
|
||||
^ | |
|
||||
+--------------------| SCLK |
|
||||
+-------------+
|
||||
|
||||
CS mode, 4-wire without busy indicator
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In datasheet "4-wire" mode, the controller CS line is connected to the ADC SDI
|
||||
pin and a GPIO is connected to the ADC CNV pin. This connection mode may better
|
||||
suit scenarios where multiple ADCs can share one CNV trigger.
|
||||
|
||||
Set ``adi,sdi-pin`` to ``"cs"`` to select this mode.
|
||||
|
||||
|
||||
::
|
||||
|
||||
+-------------+
|
||||
+ ----------------------------------| CS |
|
||||
| | |
|
||||
| +-------------------| GPIO |
|
||||
| v | |
|
||||
| +--------------------+ | HOST |
|
||||
| | CNV | | |
|
||||
+--->| SDI AD4000 SDO |-------->| SDI |
|
||||
| SCK | | |
|
||||
+--------------------+ | |
|
||||
^ | |
|
||||
+--------------------| SCLK |
|
||||
+-------------+
|
162
Documentation/iio/ad4695.rst
Normal file
162
Documentation/iio/ad4695.rst
Normal file
@ -0,0 +1,162 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
=============
|
||||
AD4695 driver
|
||||
=============
|
||||
|
||||
ADC driver for Analog Devices Inc. AD4695 and similar devices. The module name
|
||||
is ``ad4695``.
|
||||
|
||||
|
||||
Supported devices
|
||||
=================
|
||||
|
||||
The following chips are supported by this driver:
|
||||
|
||||
* `AD4695 <https://www.analog.com/AD4695>`_
|
||||
* `AD4696 <https://www.analog.com/AD4696>`_
|
||||
* `AD4697 <https://www.analog.com/AD4697>`_
|
||||
* `AD4698 <https://www.analog.com/AD4698>`_
|
||||
|
||||
|
||||
Supported features
|
||||
==================
|
||||
|
||||
SPI wiring modes
|
||||
----------------
|
||||
|
||||
The driver currently supports the following SPI wiring configuration:
|
||||
|
||||
4-wire mode
|
||||
^^^^^^^^^^^
|
||||
|
||||
In this mode, CNV and CS are tied together and there is a single SDO line.
|
||||
|
||||
.. code-block::
|
||||
|
||||
+-------------+ +-------------+
|
||||
| CS |<-+------| CS |
|
||||
| CNV |<-+ | |
|
||||
| ADC | | HOST |
|
||||
| | | |
|
||||
| SDI |<--------| SDO |
|
||||
| SDO |-------->| SDI |
|
||||
| SCLK |<--------| SCLK |
|
||||
+-------------+ +-------------+
|
||||
|
||||
To use this mode, in the device tree, omit the ``cnv-gpios`` and
|
||||
``spi-rx-bus-width`` properties.
|
||||
|
||||
Channel configuration
|
||||
---------------------
|
||||
|
||||
Since the chip supports multiple ways to configure each channel, this must be
|
||||
described in the device tree based on what is actually wired up to the inputs.
|
||||
|
||||
There are three typical configurations:
|
||||
|
||||
An ``INx`` pin is used as the positive input with the ``REFGND``, ``COM`` or
|
||||
the next ``INx`` pin as the negative input.
|
||||
|
||||
Pairing with REFGND
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Each ``INx`` pin can be used as a pseudo-differential input in conjunction with
|
||||
the ``REFGND`` pin. The device tree will look like this:
|
||||
|
||||
.. code-block::
|
||||
|
||||
channel@0 {
|
||||
reg = <0>; /* IN0 */
|
||||
};
|
||||
|
||||
If no other channel properties are needed (e.g. ``adi,no-high-z``), the channel
|
||||
node can be omitted entirely.
|
||||
|
||||
This will appear on the IIO bus as the ``voltage0`` channel. The processed value
|
||||
(*raw × scale*) will be the voltage present on the ``IN0`` pin relative to
|
||||
``REFGND``. (Offset is always 0 when pairing with ``REFGND``.)
|
||||
|
||||
Pairing with COM
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Each ``INx`` pin can be used as a pseudo-differential input in conjunction with
|
||||
the ``COM`` pin. The device tree will look like this:
|
||||
|
||||
.. code-block::
|
||||
|
||||
com-supply = <&vref_div_2>;
|
||||
|
||||
channel@1 {
|
||||
reg = <1>; /* IN1 */
|
||||
common-mode-channel = <AD4695_COMMON_MODE_COM>;
|
||||
bipolar;
|
||||
};
|
||||
|
||||
This will appear on the IIO bus as the ``voltage1`` channel. The processed value
|
||||
(*(raw + offset) × scale*) will be the voltage measured on the ``IN1`` pin
|
||||
relative to ``REFGND``. (The offset is determined by the ``com-supply`` voltage.)
|
||||
|
||||
The macro comes from:
|
||||
|
||||
.. code-block::
|
||||
|
||||
#include <dt-bindings/iio/adi,ad4695.h>
|
||||
|
||||
Pairing two INx pins
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
An even-numbered ``INx`` pin and the following odd-numbered ``INx`` pin can be
|
||||
used as a pseudo-differential input. The device tree for using ``IN2`` as the
|
||||
positive input and ``IN3`` as the negative input will look like this:
|
||||
|
||||
.. code-block::
|
||||
|
||||
in3-supply = <&vref_div_2>;
|
||||
|
||||
channel@2 {
|
||||
reg = <2>; /* IN2 */
|
||||
common-mode-channel = <3>; /* IN3 */
|
||||
bipolar;
|
||||
};
|
||||
|
||||
This will appear on the IIO bus as the ``voltage2`` channel. The processed value
|
||||
(*(raw + offset) × scale*) will be the voltage measured on the ``IN1`` pin
|
||||
relative to ``REFGND``. (Offset is determined by the ``in3-supply`` voltage.)
|
||||
|
||||
VCC supply
|
||||
----------
|
||||
|
||||
The chip supports being powered by an external LDO via the ``VCC`` input or an
|
||||
internal LDO via the ``LDO_IN`` input. The driver looks at the device tree to
|
||||
determine which is being used. If ``ldo-supply`` is present, then the internal
|
||||
LDO is used. If ``vcc-supply`` is present, then the external LDO is used and
|
||||
the internal LDO is disabled.
|
||||
|
||||
Reference voltage
|
||||
-----------------
|
||||
|
||||
The chip supports an external reference voltage via the ``REF`` input or an
|
||||
internal buffered reference voltage via the ``REFIN`` input. The driver looks
|
||||
at the device tree to determine which is being used. If ``ref-supply`` is
|
||||
present, then the external reference voltage is used and the internal buffer is
|
||||
disabled. If ``refin-supply`` is present, then the internal buffered reference
|
||||
voltage is used.
|
||||
|
||||
Unimplemented features
|
||||
----------------------
|
||||
|
||||
- Additional wiring modes
|
||||
- Threshold events
|
||||
- Oversampling
|
||||
- Gain/offset calibration
|
||||
- GPIO support
|
||||
- CRC support
|
||||
|
||||
Device buffers
|
||||
==============
|
||||
|
||||
This driver supports hardware triggered buffers. This uses the "advanced
|
||||
sequencer" feature of the chip to trigger a burst of conversions.
|
||||
|
||||
Also see :doc:`iio_devbuf` for more general information.
|
130
Documentation/iio/ad7380.rst
Normal file
130
Documentation/iio/ad7380.rst
Normal file
@ -0,0 +1,130 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
=============
|
||||
AD7380 driver
|
||||
=============
|
||||
|
||||
ADC driver for Analog Devices Inc. AD7380 and similar devices. The module name
|
||||
is ``ad7380``.
|
||||
|
||||
|
||||
Supported devices
|
||||
=================
|
||||
|
||||
The following chips are supported by this driver:
|
||||
|
||||
* `AD7380 <https://www.analog.com/en/products/ad7380.html>`_
|
||||
* `AD7381 <https://www.analog.com/en/products/ad7381.html>`_
|
||||
* `AD7383 <https://www.analog.com/en/products/ad7383.html>`_
|
||||
* `AD7384 <https://www.analog.com/en/products/ad7384.html>`_
|
||||
* `AD7386 <https://www.analog.com/en/products/ad7386.html>`_
|
||||
* `AD7387 <https://www.analog.com/en/products/ad7387.html>`_
|
||||
* `AD7388 <https://www.analog.com/en/products/ad7388.html>`_
|
||||
* `AD7380-4 <https://www.analog.com/en/products/ad7380-4.html>`_
|
||||
* `AD7381-4 <https://www.analog.com/en/products/ad7381-4.html>`_
|
||||
* `AD7383-4 <https://www.analog.com/en/products/ad7383-4.html>`_
|
||||
* `AD7384-4 <https://www.analog.com/en/products/ad7384-4.html>`_
|
||||
* `AD7386-4 <https://www.analog.com/en/products/ad7386-4.html>`_
|
||||
* `AD7387-4 <https://www.analog.com/en/products/ad7387-4.html>`_
|
||||
* `AD7388-4 <https://www.analog.com/en/products/ad7388-4.html>`_
|
||||
|
||||
|
||||
Supported features
|
||||
==================
|
||||
|
||||
SPI wiring modes
|
||||
----------------
|
||||
|
||||
ad738x ADCs can output data on several SDO lines (1/2/4). The driver currently
|
||||
supports only 1 SDO line.
|
||||
|
||||
Reference voltage
|
||||
-----------------
|
||||
|
||||
2 possible reference voltage sources are supported:
|
||||
|
||||
- Internal reference (2.5V)
|
||||
- External reference (2.5V to 3.3V)
|
||||
|
||||
The source is determined by the device tree. If ``refio-supply`` is present,
|
||||
then the external reference is used, else the internal reference is used.
|
||||
|
||||
Oversampling and resolution boost
|
||||
---------------------------------
|
||||
|
||||
This family supports 2 types of oversampling: normal average and rolling
|
||||
average. Only normal average is supported by the driver, as rolling average can
|
||||
be achieved by processing a captured data buffer. The following ratios are
|
||||
available: 1 (oversampling disabled)/2/4/8/16/32.
|
||||
|
||||
When the on-chip oversampling function is enabled the performance of the ADC can
|
||||
exceed the default resolution. To accommodate the performance boost achievable,
|
||||
it is possible to enable an additional two bits of resolution. Because the
|
||||
resolution boost feature can only be enabled when oversampling is enabled and
|
||||
oversampling is not as useful without the resolution boost, the driver
|
||||
automatically enables the resolution boost if and only if oversampling is
|
||||
enabled.
|
||||
|
||||
Since the resolution boost feature causes 16-bit chips to now have 18-bit data
|
||||
which means the storagebits has to change from 16 to 32 bits, we use the new
|
||||
ext_scan_type feature to allow changing the scan_type at runtime. Unfortunately
|
||||
libiio does not support it. So when enabling or disabling oversampling, user
|
||||
must restart iiod using the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:~# systemctl restart iiod
|
||||
|
||||
Channel selection and sequencer (single-end chips only)
|
||||
-------------------------------------------------------
|
||||
|
||||
Single-ended chips of this family (ad7386/7/8(-4)) have a 2:1 multiplexer in
|
||||
front of each ADC. They also include additional configuration registers that
|
||||
allow for either manual selection or automatic switching (sequencer mode), of
|
||||
the multiplexer inputs.
|
||||
|
||||
From an IIO point of view, all inputs are exported, i.e ad7386/7/8
|
||||
export 4 channels and ad7386-4/7-4/8-4 export 8 channels.
|
||||
|
||||
Inputs ``AinX0`` of multiplexers correspond to the first half of IIO channels (i.e
|
||||
0-1 or 0-3) and inputs ``AinX1`` correspond to second half (i.e 2-3 or 4-7).
|
||||
Example for AD7386/7/8 (2 channels parts):
|
||||
|
||||
.. code-block::
|
||||
|
||||
IIO | AD7386/7/8
|
||||
| +----------------------------
|
||||
| | _____ ______
|
||||
| | | | | |
|
||||
voltage0 | AinA0 --|--->| | | |
|
||||
| | | mux |----->| ADCA |---
|
||||
voltage2 | AinA1 --|--->| | | |
|
||||
| | |_____| |_____ |
|
||||
| | _____ ______
|
||||
| | | | | |
|
||||
voltage1 | AinB0 --|--->| | | |
|
||||
| | | mux |----->| ADCB |---
|
||||
voltage3 | AinB1 --|--->| | | |
|
||||
| | |_____| |______|
|
||||
| |
|
||||
| +----------------------------
|
||||
|
||||
|
||||
When enabling sequencer mode, the effective sampling rate is divided by two.
|
||||
|
||||
Unimplemented features
|
||||
----------------------
|
||||
|
||||
- 2/4 SDO lines
|
||||
- Rolling average oversampling
|
||||
- Power down mode
|
||||
- CRC indication
|
||||
- Alert
|
||||
|
||||
|
||||
Device buffers
|
||||
==============
|
||||
|
||||
This driver supports IIO triggered buffers.
|
||||
|
||||
See :doc:`iio_devbuf` for more information.
|
233
Documentation/iio/adxl380.rst
Normal file
233
Documentation/iio/adxl380.rst
Normal file
@ -0,0 +1,233 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===============
|
||||
ADXL380 driver
|
||||
===============
|
||||
|
||||
This driver supports Analog Device's ADXL380/382 on SPI/I2C bus.
|
||||
|
||||
1. Supported devices
|
||||
====================
|
||||
|
||||
* `ADXL380 <https://www.analog.com/ADXL380>`_
|
||||
* `ADXL382 <https://www.analog.com/ADXL382>`_
|
||||
|
||||
The ADXL380/ADXL382 is a low noise density, low power, 3-axis accelerometer with
|
||||
selectable measurement ranges. The ADXL380 supports the ±4 g, ±8 g, and ±16 g
|
||||
ranges, and the ADXL382 supports ±15 g, ±30 g, and ±60 g ranges.
|
||||
|
||||
2. Device attributes
|
||||
====================
|
||||
|
||||
Accelerometer measurements are always provided.
|
||||
|
||||
Temperature data are also provided. This data can be used to monitor the
|
||||
internal system temperature or to improve the temperature stability of the
|
||||
device via calibration.
|
||||
|
||||
Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:deviceX``,
|
||||
where X is the IIO index of the device. Under these folders reside a set of
|
||||
device files, depending on the characteristics and features of the hardware
|
||||
device in questions. These files are consistently generalized and documented in
|
||||
the IIO ABI documentation.
|
||||
|
||||
The following tables show the adxl380 related device files, found in the
|
||||
specific device folder path ``/sys/bus/iio/devices/iio:deviceX``.
|
||||
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| 3-Axis Accelerometer related device files | Description |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_scale | Scale for the accelerometer channels. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_filter_high_pass_3db_frequency | Low pass filter bandwidth. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_filter_high_pass_3db_frequency_available | Available low pass filter bandwidth configurations. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_filter_low_pass_3db_frequency | High pass filter bandwidth. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_filter_low_pass_3db_frequency_available | Available high pass filter bandwidth configurations. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_x_calibbias | Calibration offset for the X-axis accelerometer channel. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_x_raw | Raw X-axis accelerometer channel value. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_y_calibbias | y-axis acceleration offset correction |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_y_raw | Raw Y-axis accelerometer channel value. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_z_calibbias | Calibration offset for the Z-axis accelerometer channel. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_z_raw | Raw Z-axis accelerometer channel value. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
|
||||
+----------------------------------+--------------------------------------------+
|
||||
| Temperature sensor related files | Description |
|
||||
+----------------------------------+--------------------------------------------+
|
||||
| in_temp_raw | Raw temperature channel value. |
|
||||
+----------------------------------+--------------------------------------------+
|
||||
| in_temp_offset | Offset for the temperature sensor channel. |
|
||||
+----------------------------------+--------------------------------------------+
|
||||
| in_temp_scale | Scale for the temperature sensor channel. |
|
||||
+----------------------------------+--------------------------------------------+
|
||||
|
||||
+------------------------------+----------------------------------------------+
|
||||
| Miscellaneous device files | Description |
|
||||
+------------------------------+----------------------------------------------+
|
||||
| name | Name of the IIO device. |
|
||||
+------------------------------+----------------------------------------------+
|
||||
| sampling_frequency | Currently selected sample rate. |
|
||||
+------------------------------+----------------------------------------------+
|
||||
| sampling_frequency_available | Available sampling frequency configurations. |
|
||||
+------------------------------+----------------------------------------------+
|
||||
|
||||
Channels processed values
|
||||
-------------------------
|
||||
|
||||
A channel value can be read from its _raw attribute. The value returned is the
|
||||
raw value as reported by the devices. To get the processed value of the channel,
|
||||
apply the following formula:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
processed value = (_raw + _offset) * _scale
|
||||
|
||||
Where _offset and _scale are device attributes. If no _offset attribute is
|
||||
present, simply assume its value is 0.
|
||||
|
||||
The adis16475 driver offers data for 2 types of channels, the table below shows
|
||||
the measurement units for the processed value, which are defined by the IIO
|
||||
framework:
|
||||
|
||||
+-------------------------------------+---------------------------+
|
||||
| Channel type | Measurement unit |
|
||||
+-------------------------------------+---------------------------+
|
||||
| Acceleration on X, Y, and Z axis | Meters per Second squared |
|
||||
+-------------------------------------+---------------------------+
|
||||
| Temperature | Millidegrees Celsius |
|
||||
+-------------------------------------+---------------------------+
|
||||
|
||||
Usage examples
|
||||
--------------
|
||||
|
||||
Show device name:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat name
|
||||
adxl382
|
||||
|
||||
Show accelerometer channels value:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_raw
|
||||
-1771
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_y_raw
|
||||
282
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_z_raw
|
||||
-1523
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_scale
|
||||
0.004903325
|
||||
|
||||
- X-axis acceleration = in_accel_x_raw * in_accel_scale = −8.683788575 m/s^2
|
||||
- Y-axis acceleration = in_accel_y_raw * in_accel_scale = 1.38273765 m/s^2
|
||||
- Z-axis acceleration = in_accel_z_raw * in_accel_scale = -7.467763975 m/s^2
|
||||
|
||||
Set calibration offset for accelerometer channels:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
|
||||
0
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 50 > in_accel_x_calibbias
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
|
||||
50
|
||||
|
||||
Set sampling frequency:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat sampling_frequency
|
||||
16000
|
||||
root:/sys/bus/iio/devices/iio:device0> cat sampling_frequency_available
|
||||
16000 32000 64000
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 32000 > sampling_frequency
|
||||
root:/sys/bus/iio/devices/iio:device0> cat sampling_frequency
|
||||
32000
|
||||
|
||||
Set low pass filter bandwidth for accelerometer channels:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_filter_low_pass_3db_frequency
|
||||
32000
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_filter_low_pass_3db_frequency_available
|
||||
32000 8000 4000 2000
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 2000 > in_accel_filter_low_pass_3db_frequency
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_filter_low_pass_3db_frequency
|
||||
2000
|
||||
|
||||
3. Device buffers
|
||||
=================
|
||||
|
||||
This driver supports IIO buffers.
|
||||
|
||||
All devices support retrieving the raw acceleration and temperature measurements
|
||||
using buffers.
|
||||
|
||||
Usage examples
|
||||
--------------
|
||||
|
||||
Select channels for buffer read:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_accel_x_en
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_accel_y_en
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_accel_z_en
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_temp_en
|
||||
|
||||
Set the number of samples to be stored in the buffer:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 10 > buffer/length
|
||||
|
||||
Enable buffer readings:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable
|
||||
|
||||
Obtain buffered data:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> hexdump -C /dev/iio\:device0
|
||||
...
|
||||
002bc300 f7 e7 00 a8 fb c5 24 80 f7 e7 01 04 fb d6 24 80 |......$.......$.|
|
||||
002bc310 f7 f9 00 ab fb dc 24 80 f7 c3 00 b8 fb e2 24 80 |......$.......$.|
|
||||
002bc320 f7 fb 00 bb fb d1 24 80 f7 b1 00 5f fb d1 24 80 |......$...._..$.|
|
||||
002bc330 f7 c4 00 c6 fb a6 24 80 f7 a6 00 68 fb f1 24 80 |......$....h..$.|
|
||||
002bc340 f7 b8 00 a3 fb e7 24 80 f7 9a 00 b1 fb af 24 80 |......$.......$.|
|
||||
002bc350 f7 b1 00 67 fb ee 24 80 f7 96 00 be fb 92 24 80 |...g..$.......$.|
|
||||
002bc360 f7 ab 00 7a fc 1b 24 80 f7 b6 00 ae fb 76 24 80 |...z..$......v$.|
|
||||
002bc370 f7 ce 00 a3 fc 02 24 80 f7 c0 00 be fb 8b 24 80 |......$.......$.|
|
||||
002bc380 f7 c3 00 93 fb d0 24 80 f7 ce 00 d8 fb c8 24 80 |......$.......$.|
|
||||
002bc390 f7 bd 00 c0 fb 82 24 80 f8 00 00 e8 fb db 24 80 |......$.......$.|
|
||||
002bc3a0 f7 d8 00 d3 fb b4 24 80 f8 0b 00 e5 fb c3 24 80 |......$.......$.|
|
||||
002bc3b0 f7 eb 00 c8 fb 92 24 80 f7 e7 00 ea fb cb 24 80 |......$.......$.|
|
||||
002bc3c0 f7 fd 00 cb fb 94 24 80 f7 e3 00 f2 fb b8 24 80 |......$.......$.|
|
||||
...
|
||||
|
||||
See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered
|
||||
data is structured.
|
||||
|
||||
4. IIO Interfacing Tools
|
||||
========================
|
||||
|
||||
See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO
|
||||
interfacing tools.
|
@ -18,8 +18,12 @@ Industrial I/O Kernel Drivers
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
ad4000
|
||||
ad4695
|
||||
ad7380
|
||||
ad7944
|
||||
adis16475
|
||||
adis16480
|
||||
adxl380
|
||||
bno055
|
||||
ep93xx_adc
|
||||
|
@ -614,6 +614,89 @@ queue, and then start some asynchronous transfer engine (unless it's
|
||||
already running).
|
||||
|
||||
|
||||
Extensions to the SPI protocol
|
||||
------------------------------
|
||||
The fact that SPI doesn't have a formal specification or standard permits chip
|
||||
manufacturers to implement the SPI protocol in slightly different ways. In most
|
||||
cases, SPI protocol implementations from different vendors are compatible among
|
||||
each other. For example, in SPI mode 0 (CPOL=0, CPHA=0) the bus lines may behave
|
||||
like the following:
|
||||
|
||||
::
|
||||
|
||||
nCSx ___ ___
|
||||
\_________________________________________________________________/
|
||||
• •
|
||||
• •
|
||||
SCLK ___ ___ ___ ___ ___ ___ ___ ___
|
||||
_______/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \_____
|
||||
• : ; : ; : ; : ; : ; : ; : ; : ; •
|
||||
• : ; : ; : ; : ; : ; : ; : ; : ; •
|
||||
MOSI XXX__________ _______ _______ ________XXX
|
||||
0xA5 XXX__/ 1 \_0_____/ 1 \_0_______0_____/ 1 \_0_____/ 1 \_XXX
|
||||
• ; ; ; ; ; ; ; ; •
|
||||
• ; ; ; ; ; ; ; ; •
|
||||
MISO XXX__________ _______________________ _______ XXX
|
||||
0xBA XXX__/ 1 \_____0_/ 1 1 1 \_____0__/ 1 \____0__XXX
|
||||
|
||||
Legend::
|
||||
|
||||
• marks the start/end of transmission;
|
||||
: marks when data is clocked into the peripheral;
|
||||
; marks when data is clocked into the controller;
|
||||
X marks when line states are not specified.
|
||||
|
||||
In some few cases, chips extend the SPI protocol by specifying line behaviors
|
||||
that other SPI protocols don't (e.g. data line state for when CS is not
|
||||
asserted). Those distinct SPI protocols, modes, and configurations are supported
|
||||
by different SPI mode flags.
|
||||
|
||||
MOSI idle state configuration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Common SPI protocol implementations don't specify any state or behavior for the
|
||||
MOSI line when the controller is not clocking out data. However, there do exist
|
||||
peripherals that require specific MOSI line state when data is not being clocked
|
||||
out. For example, if the peripheral expects the MOSI line to be high when the
|
||||
controller is not clocking out data (``SPI_MOSI_IDLE_HIGH``), then a transfer in
|
||||
SPI mode 0 would look like the following:
|
||||
|
||||
::
|
||||
|
||||
nCSx ___ ___
|
||||
\_________________________________________________________________/
|
||||
• •
|
||||
• •
|
||||
SCLK ___ ___ ___ ___ ___ ___ ___ ___
|
||||
_______/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \_____
|
||||
• : ; : ; : ; : ; : ; : ; : ; : ; •
|
||||
• : ; : ; : ; : ; : ; : ; : ; : ; •
|
||||
MOSI _____ _______ _______ _______________ ___
|
||||
0x56 \_0_____/ 1 \_0_____/ 1 \_0_____/ 1 1 \_0_____/
|
||||
• ; ; ; ; ; ; ; ; •
|
||||
• ; ; ; ; ; ; ; ; •
|
||||
MISO XXX__________ _______________________ _______ XXX
|
||||
0xBA XXX__/ 1 \_____0_/ 1 1 1 \_____0__/ 1 \____0__XXX
|
||||
|
||||
Legend::
|
||||
|
||||
• marks the start/end of transmission;
|
||||
: marks when data is clocked into the peripheral;
|
||||
; marks when data is clocked into the controller;
|
||||
X marks when line states are not specified.
|
||||
|
||||
In this extension to the usual SPI protocol, the MOSI line state is specified to
|
||||
be kept high when CS is asserted but the controller is not clocking out data to
|
||||
the peripheral and also when CS is not asserted.
|
||||
|
||||
Peripherals that require this extension must request it by setting the
|
||||
``SPI_MOSI_IDLE_HIGH`` bit into the mode attribute of their ``struct
|
||||
spi_device`` and call spi_setup(). Controllers that support this extension
|
||||
should indicate it by setting ``SPI_MOSI_IDLE_HIGH`` in the mode_bits attribute
|
||||
of their ``struct spi_controller``. The configuration to idle MOSI low is
|
||||
analogous but uses the ``SPI_MOSI_IDLE_LOW`` mode bit.
|
||||
|
||||
|
||||
THANKS TO
|
||||
---------
|
||||
Contributors to Linux-SPI discussions include (in alphabetical order,
|
||||
|
73
MAINTAINERS
73
MAINTAINERS
@ -448,6 +448,7 @@ S: Supported
|
||||
W: https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/ad738x
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
|
||||
F: Documentation/iio/ad7380.rst
|
||||
F: drivers/iio/adc/ad7380.c
|
||||
|
||||
AD7877 TOUCHSCREEN DRIVER
|
||||
@ -619,6 +620,17 @@ F: drivers/iio/accel/adxl372.c
|
||||
F: drivers/iio/accel/adxl372_i2c.c
|
||||
F: drivers/iio/accel/adxl372_spi.c
|
||||
|
||||
ADXL380 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
|
||||
M: Ramona Gradinariu <ramona.gradinariu@analog.com>
|
||||
M: Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/accel/adi,adxl380.yaml
|
||||
F: drivers/iio/accel/adxl380.c
|
||||
F: drivers/iio/accel/adxl380.h
|
||||
F: drivers/iio/accel/adxl380_i2c.c
|
||||
F: drivers/iio/accel/adxl380_spi.c
|
||||
|
||||
AF8133J THREE-AXIS MAGNETOMETER DRIVER
|
||||
M: Ondřej Jirman <megi@xff.cz>
|
||||
S: Maintained
|
||||
@ -1202,6 +1214,15 @@ W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
|
||||
F: drivers/iio/dac/ad3552r.c
|
||||
|
||||
ANALOG DEVICES INC AD4000 DRIVER
|
||||
M: Marcelo Schmitt <marcelo.schmitt@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad4000.yaml
|
||||
F: Documentation/iio/ad4000.rst
|
||||
F: drivers/iio/adc/ad4000.c
|
||||
|
||||
ANALOG DEVICES INC AD4130 DRIVER
|
||||
M: Cosmin Tanislav <cosmin.tanislav@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
@ -1211,6 +1232,18 @@ F: Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml
|
||||
F: drivers/iio/adc/ad4130.c
|
||||
|
||||
ANALOG DEVICES INC AD4695 DRIVER
|
||||
M: Michael Hennerich <michael.hennerich@analog.com>
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
R: David Lechner <dlechner@baylibre.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
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
|
||||
|
||||
ANALOG DEVICES INC AD7091R DRIVER
|
||||
M: Marcelo Schmitt <marcelo.schmitt@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
@ -1277,6 +1310,16 @@ W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
|
||||
F: drivers/iio/adc/ad7780.c
|
||||
|
||||
ANALOG DEVICES INC AD9467 DRIVER
|
||||
M: Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
M: Nuno Sa <nuno.sa@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/ABI/testing/debugfs-iio-ad9467
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml
|
||||
F: drivers/iio/adc/ad9467.c
|
||||
|
||||
ANALOG DEVICES INC AD9739a DRIVER
|
||||
M: Nuno Sa <nuno.sa@analog.com>
|
||||
M: Dragos Bogdan <dragos.bogdan@analog.com>
|
||||
@ -10861,6 +10904,7 @@ M: Nuno Sa <nuno.sa@analog.com>
|
||||
R: Olivier Moysan <olivier.moysan@foss.st.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/debugfs-iio-backend
|
||||
F: drivers/iio/industrialio-backend.c
|
||||
F: include/linux/iio/backend.h
|
||||
|
||||
@ -13261,6 +13305,16 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml
|
||||
F: drivers/iio/dac/ltc1660.c
|
||||
|
||||
LTC2664 IIO DAC DRIVER
|
||||
M: Michael Hennerich <michael.hennerich@analog.com>
|
||||
M: Kim Seer Paller <kimseer.paller@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/dac/adi,ltc2664.yaml
|
||||
F: Documentation/devicetree/bindings/iio/dac/adi,ltc2672.yaml
|
||||
F: drivers/iio/dac/ltc2664.c
|
||||
|
||||
LTC2688 IIO DAC DRIVER
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
@ -15022,6 +15076,13 @@ F: Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml
|
||||
F: drivers/nvmem/microchip-otpc.c
|
||||
F: include/dt-bindings/nvmem/microchip,sama7g5-otpc.h
|
||||
|
||||
MICROCHIP PAC1921 POWER/CURRENT MONITOR DRIVER
|
||||
M: Matteo Martelli <matteomartelli3@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/iio/adc/microchip,pac1921.yaml
|
||||
F: drivers/iio/adc/pac1921.c
|
||||
|
||||
MICROCHIP PAC1934 POWER/ENERGY MONITOR DRIVER
|
||||
M: Marius Cristea <marius.cristea@microchip.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
@ -19767,6 +19828,12 @@ S: Supported
|
||||
F: drivers/power/supply/bd99954-charger.c
|
||||
F: drivers/power/supply/bd99954-charger.h
|
||||
|
||||
ROHM BH1745 COLOUR SENSOR
|
||||
M: Mudit Sharma <muditsharma.info@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/iio/light/bh1745.c
|
||||
|
||||
ROHM BH1750 AMBIENT LIGHT SENSOR DRIVER
|
||||
M: Tomasz Duszynski <tduszyns@gmail.com>
|
||||
S: Maintained
|
||||
@ -20582,6 +20649,12 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/chemical/sensirion,scd4x.yaml
|
||||
F: drivers/iio/chemical/scd4x.c
|
||||
|
||||
SENSIRION SDP500 DIFFERENTIAL PRESSURE SENSOR DRIVER
|
||||
M: Petar Stoykov <petar.stoykov@prodrive-technologies.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/pressure/sensirion,sdp500.yaml
|
||||
F: drivers/iio/pressure/sdp500.c
|
||||
|
||||
SENSIRION SGP40 GAS SENSOR DRIVER
|
||||
M: Andreas Klinger <ak@it-klinger.de>
|
||||
S: Maintained
|
||||
|
@ -177,6 +177,33 @@ config ADXL372_I2C
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adxl372_i2c.
|
||||
|
||||
config ADXL380
|
||||
tristate
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
|
||||
config ADXL380_SPI
|
||||
tristate "Analog Devices ADXL380 3-Axis Accelerometer SPI Driver"
|
||||
depends on SPI
|
||||
select ADXL380
|
||||
select REGMAP_SPI
|
||||
help
|
||||
Say yes here to add support for the Analog Devices ADXL380 triaxial
|
||||
acceleration sensor.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adxl380_spi.
|
||||
|
||||
config ADXL380_I2C
|
||||
tristate "Analog Devices ADXL380 3-Axis Accelerometer I2C Driver"
|
||||
depends on I2C
|
||||
select ADXL380
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say yes here to add support for the Analog Devices ADXL380 triaxial
|
||||
acceleration sensor.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adxl380_i2c.
|
||||
|
||||
config BMA180
|
||||
tristate "Bosch BMA023/BMA1x0/BMA250 3-Axis Accelerometer Driver"
|
||||
depends on I2C && INPUT_BMA150=n
|
||||
|
@ -21,6 +21,9 @@ obj-$(CONFIG_ADXL367_SPI) += adxl367_spi.o
|
||||
obj-$(CONFIG_ADXL372) += adxl372.o
|
||||
obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o
|
||||
obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o
|
||||
obj-$(CONFIG_ADXL380) += adxl380.o
|
||||
obj-$(CONFIG_ADXL380_I2C) += adxl380_i2c.o
|
||||
obj-$(CONFIG_ADXL380_SPI) += adxl380_spi.o
|
||||
obj-$(CONFIG_BMA180) += bma180.o
|
||||
obj-$(CONFIG_BMA220) += bma220_spi.o
|
||||
obj-$(CONFIG_BMA400) += bma400_core.o
|
||||
|
@ -1220,7 +1220,7 @@ static int adxl367_update_scan_mode(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
|
||||
st->fifo_set_size = bitmap_weight(active_scan_mask,
|
||||
indio_dev->masklength);
|
||||
iio_get_masklength(indio_dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ static int adxl367_write(void *context, const void *val_buf, size_t val_size)
|
||||
return spi_sync(st->spi, &st->reg_write_msg);
|
||||
}
|
||||
|
||||
static struct regmap_bus adxl367_spi_regmap_bus = {
|
||||
static const struct regmap_bus adxl367_spi_regmap_bus = {
|
||||
.read = adxl367_read,
|
||||
.write = adxl367_write,
|
||||
};
|
||||
|
@ -1050,7 +1050,7 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
|
||||
st->fifo_format = adxl372_axis_lookup_table[i].fifo_format;
|
||||
st->fifo_axis_mask = adxl372_axis_lookup_table[i].bits;
|
||||
st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask,
|
||||
indio_dev->masklength);
|
||||
iio_get_masklength(indio_dev));
|
||||
|
||||
/* Configure the FIFO to store sets of impact event peak. */
|
||||
if (st->peak_fifo_mode_en) {
|
||||
|
1905
drivers/iio/accel/adxl380.c
Normal file
1905
drivers/iio/accel/adxl380.c
Normal file
File diff suppressed because it is too large
Load Diff
26
drivers/iio/accel/adxl380.h
Normal file
26
drivers/iio/accel/adxl380.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* ADXL380 3-Axis Digital Accelerometer
|
||||
*
|
||||
* Copyright 2024 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#ifndef _ADXL380_H_
|
||||
#define _ADXL380_H_
|
||||
|
||||
struct adxl380_chip_info {
|
||||
const char *name;
|
||||
const int scale_tbl[3][2];
|
||||
const int samp_freq_tbl[3];
|
||||
const int temp_offset;
|
||||
const u16 chip_id;
|
||||
};
|
||||
|
||||
extern const struct adxl380_chip_info adxl380_chip_info;
|
||||
extern const struct adxl380_chip_info adxl382_chip_info;
|
||||
|
||||
int adxl380_probe(struct device *dev, struct regmap *regmap,
|
||||
const struct adxl380_chip_info *chip_info);
|
||||
bool adxl380_readable_noinc_reg(struct device *dev, unsigned int reg);
|
||||
|
||||
#endif /* _ADXL380_H_ */
|
64
drivers/iio/accel/adxl380_i2c.c
Normal file
64
drivers/iio/accel/adxl380_i2c.c
Normal file
@ -0,0 +1,64 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ADXL380 3-Axis Digital Accelerometer I2C driver
|
||||
*
|
||||
* Copyright 2024 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "adxl380.h"
|
||||
|
||||
static const struct regmap_config adxl380_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.readable_noinc_reg = adxl380_readable_noinc_reg,
|
||||
};
|
||||
|
||||
static int adxl380_i2c_probe(struct i2c_client *client)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
const struct adxl380_chip_info *chip_data;
|
||||
|
||||
chip_data = i2c_get_match_data(client);
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &adxl380_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
return adxl380_probe(&client->dev, regmap, chip_data);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adxl380_i2c_id[] = {
|
||||
{ "adxl380", (kernel_ulong_t)&adxl380_chip_info },
|
||||
{ "adxl382", (kernel_ulong_t)&adxl382_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adxl380_i2c_id);
|
||||
|
||||
static const struct of_device_id adxl380_of_match[] = {
|
||||
{ .compatible = "adi,adxl380", .data = &adxl380_chip_info },
|
||||
{ .compatible = "adi,adxl382", .data = &adxl382_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adxl380_of_match);
|
||||
|
||||
static struct i2c_driver adxl380_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "adxl380_i2c",
|
||||
.of_match_table = adxl380_of_match,
|
||||
},
|
||||
.probe = adxl380_i2c_probe,
|
||||
.id_table = adxl380_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(adxl380_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Ramona Gradinariu <ramona.gradinariu@analog.com>");
|
||||
MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices ADXL380 3-axis accelerometer I2C driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(IIO_ADXL380);
|
66
drivers/iio/accel/adxl380_spi.c
Normal file
66
drivers/iio/accel/adxl380_spi.c
Normal file
@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ADXL380 3-Axis Digital Accelerometer SPI driver
|
||||
*
|
||||
* Copyright 2024 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include "adxl380.h"
|
||||
|
||||
static const struct regmap_config adxl380_spi_regmap_config = {
|
||||
.reg_bits = 7,
|
||||
.pad_bits = 1,
|
||||
.val_bits = 8,
|
||||
.read_flag_mask = BIT(0),
|
||||
.readable_noinc_reg = adxl380_readable_noinc_reg,
|
||||
};
|
||||
|
||||
static int adxl380_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct adxl380_chip_info *chip_data;
|
||||
struct regmap *regmap;
|
||||
|
||||
chip_data = spi_get_device_match_data(spi);
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &adxl380_spi_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
return adxl380_probe(&spi->dev, regmap, chip_data);
|
||||
}
|
||||
|
||||
static const struct spi_device_id adxl380_spi_id[] = {
|
||||
{ "adxl380", (kernel_ulong_t)&adxl380_chip_info },
|
||||
{ "adxl382", (kernel_ulong_t)&adxl382_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adxl380_spi_id);
|
||||
|
||||
static const struct of_device_id adxl380_of_match[] = {
|
||||
{ .compatible = "adi,adxl380", .data = &adxl380_chip_info },
|
||||
{ .compatible = "adi,adxl382", .data = &adxl382_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adxl380_of_match);
|
||||
|
||||
static struct spi_driver adxl380_spi_driver = {
|
||||
.driver = {
|
||||
.name = "adxl380_spi",
|
||||
.of_match_table = adxl380_of_match,
|
||||
},
|
||||
.probe = adxl380_spi_probe,
|
||||
.id_table = adxl380_spi_id,
|
||||
};
|
||||
|
||||
module_spi_driver(adxl380_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Ramona Gradinariu <ramona.gradinariu@analog.com>");
|
||||
MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices ADXL380 3-axis accelerometer SPI driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(IIO_ADXL380);
|
@ -876,8 +876,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
ret = bma180_get_data_reg(data, bit);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->mutex);
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
@ -795,21 +796,19 @@ static int bma400_enable_steps(struct bma400_data *data, int val)
|
||||
|
||||
static int bma400_get_steps_reg(struct bma400_data *data, int *val)
|
||||
{
|
||||
u8 *steps_raw;
|
||||
int ret;
|
||||
|
||||
steps_raw = kmalloc(BMA400_STEP_RAW_LEN, GFP_KERNEL);
|
||||
u8 *steps_raw __free(kfree) = kmalloc(BMA400_STEP_RAW_LEN, GFP_KERNEL);
|
||||
if (!steps_raw)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, BMA400_STEP_CNT0_REG,
|
||||
steps_raw, BMA400_STEP_RAW_LEN);
|
||||
if (ret) {
|
||||
kfree(steps_raw);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
*val = get_unaligned_le24(steps_raw);
|
||||
kfree(steps_raw);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ static int bma400_regmap_spi_write(void *context, const void *data,
|
||||
return spi_write(spi, data, count);
|
||||
}
|
||||
|
||||
static struct regmap_bus bma400_regmap_bus = {
|
||||
static const struct regmap_bus bma400_regmap_bus = {
|
||||
.read = bma400_regmap_spi_read,
|
||||
.write = bma400_regmap_spi_write,
|
||||
.read_flag_mask = BIT(7),
|
||||
|
@ -1007,8 +1007,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
|
||||
int j, bit;
|
||||
|
||||
j = 0;
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength)
|
||||
iio_for_each_active_channel(indio_dev, bit)
|
||||
memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit],
|
||||
sizeof(data->scan.channels[0]));
|
||||
|
||||
|
@ -36,7 +36,7 @@ static int bmi088_regmap_spi_read(void *context, const void *reg,
|
||||
return spi_write_then_read(spi, addr, sizeof(addr), val, val_size);
|
||||
}
|
||||
|
||||
static struct regmap_bus bmi088_regmap_bus = {
|
||||
static const struct regmap_bus bmi088_regmap_bus = {
|
||||
.write = bmi088_regmap_spi_write,
|
||||
.read = bmi088_regmap_spi_read,
|
||||
};
|
||||
|
@ -62,7 +62,7 @@ static int cros_ec_accel_legacy_read_cmd(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
for_each_set_bit(i, &scan_mask, indio_dev->masklength) {
|
||||
for_each_set_bit(i, &scan_mask, iio_get_masklength(indio_dev)) {
|
||||
*data = st->resp->dump.sensor[sensor_num].data[i] *
|
||||
st->sign[i];
|
||||
data++;
|
||||
|
@ -966,8 +966,7 @@ static int fxls8962af_fifo_flush(struct iio_dev *indio_dev)
|
||||
int j, bit;
|
||||
|
||||
j = 0;
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit],
|
||||
sizeof(data->scan.channels[0]));
|
||||
}
|
||||
|
@ -173,6 +173,7 @@ enum kx_chipset {
|
||||
KXCJ91008,
|
||||
KXTJ21009,
|
||||
KXTF9,
|
||||
KX0221020,
|
||||
KX0231025,
|
||||
KX_MAX_CHIPS /* this must be last */
|
||||
};
|
||||
@ -580,8 +581,8 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* On KX023, route all used interrupts to INT1 for now */
|
||||
if (data->chipset == KX0231025 && data->client->irq > 0) {
|
||||
/* On KX023 and KX022, route all used interrupts to INT1 for now */
|
||||
if ((data->chipset == KX0231025 || data->chipset == KX0221020) && data->client->irq > 0) {
|
||||
ret = i2c_smbus_write_byte_data(data->client, KX023_REG_INC4,
|
||||
KX023_REG_INC4_DRDY1 |
|
||||
KX023_REG_INC4_WUFI1);
|
||||
@ -1507,6 +1508,7 @@ static int kxcjk1013_probe(struct i2c_client *client)
|
||||
case KXTF9:
|
||||
data->regs = &kxtf9_regs;
|
||||
break;
|
||||
case KX0221020:
|
||||
case KX0231025:
|
||||
data->regs = &kx0231025_regs;
|
||||
break;
|
||||
@ -1712,6 +1714,7 @@ static const struct i2c_device_id kxcjk1013_id[] = {
|
||||
{"kxcj91008", KXCJ91008},
|
||||
{"kxtj21009", KXTJ21009},
|
||||
{"kxtf9", KXTF9},
|
||||
{"kx022-1020", KX0221020},
|
||||
{"kx023-1025", KX0231025},
|
||||
{"SMO8500", KXCJ91008},
|
||||
{}
|
||||
@ -1724,6 +1727,7 @@ static const struct of_device_id kxcjk1013_of_match[] = {
|
||||
{ .compatible = "kionix,kxcj91008", },
|
||||
{ .compatible = "kionix,kxtj21009", },
|
||||
{ .compatible = "kionix,kxtf9", },
|
||||
{ .compatible = "kionix,kx022-1020", },
|
||||
{ .compatible = "kionix,kx023-1025", },
|
||||
{ }
|
||||
};
|
||||
|
@ -900,8 +900,7 @@ static irqreturn_t msa311_buffer_thread(int irq, void *p)
|
||||
|
||||
mutex_lock(&msa311->lock);
|
||||
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
chan = &msa311_channels[bit];
|
||||
|
||||
err = msa311_get_axis(msa311, chan, &axis);
|
||||
|
@ -494,8 +494,7 @@ static irqreturn_t sca3300_trigger_handler(int irq, void *p)
|
||||
int bit, ret, val, i = 0;
|
||||
s16 *channels = (s16 *)data->buffer;
|
||||
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
ret = sca3300_read_reg(data, indio_dev->channels[bit].address, &val);
|
||||
if (ret) {
|
||||
dev_err_ratelimited(&data->spi->dev,
|
||||
|
@ -448,8 +448,7 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
ret = stk8312_read_accel(data, bit);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
|
@ -330,8 +330,7 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p)
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
ret = stk8ba50_read_accel(data,
|
||||
stk8ba50_channel_table[bit]);
|
||||
if (ret < 0)
|
||||
|
@ -21,6 +21,18 @@ config AD_SIGMA_DELTA
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
|
||||
config AD4000
|
||||
tristate "Analog Devices AD4000 ADC Driver"
|
||||
depends on SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD4000 high speed
|
||||
SPI analog to digital converters (ADC).
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad4000.
|
||||
|
||||
config AD4130
|
||||
tristate "Analog Device AD4130 ADC Driver"
|
||||
depends on SPI
|
||||
@ -36,6 +48,17 @@ config AD4130
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad4130.
|
||||
|
||||
config AD4695
|
||||
tristate "Analog Device AD4695 ADC Driver"
|
||||
depends on SPI
|
||||
select REGMAP_SPI
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD4695 and similar
|
||||
analog to digital converters (ADC).
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad4695.
|
||||
|
||||
config AD7091R
|
||||
tristate
|
||||
|
||||
@ -991,6 +1014,19 @@ config NPCM_ADC
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called npcm_adc.
|
||||
|
||||
config PAC1921
|
||||
tristate "Microchip Technology PAC1921 driver"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Microchip Technology's PAC1921
|
||||
High-Side Power/Current Monitor with Analog Output.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pac1921.
|
||||
|
||||
config PAC1934
|
||||
tristate "Microchip Technology PAC1934 driver"
|
||||
depends on I2C
|
||||
@ -1171,6 +1207,7 @@ config SD_ADC_MODULATOR
|
||||
tristate "Generic sigma delta modulator"
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select IIO_BACKEND
|
||||
help
|
||||
Select this option to enables sigma delta modulator. This driver can
|
||||
support generic sigma delta modulators.
|
||||
@ -1225,6 +1262,7 @@ config STM32_DFSDM_ADC
|
||||
select IIO_BUFFER
|
||||
select IIO_BUFFER_HW_CONSUMER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select IIO_BACKEND
|
||||
help
|
||||
Select this option to support ADCSigma delta modulator for
|
||||
STMicroelectronics STM32 digital filter for sigma delta converter.
|
||||
|
@ -6,7 +6,9 @@
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
|
||||
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
|
||||
obj-$(CONFIG_AD4000) += ad4000.o
|
||||
obj-$(CONFIG_AD4130) += ad4130.o
|
||||
obj-$(CONFIG_AD4695) += ad4695.o
|
||||
obj-$(CONFIG_AD7091R) += ad7091r-base.o
|
||||
obj-$(CONFIG_AD7091R5) += ad7091r5.o
|
||||
obj-$(CONFIG_AD7091R8) += ad7091r8.o
|
||||
@ -90,6 +92,7 @@ obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o
|
||||
obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
|
||||
obj-$(CONFIG_NAU7802) += nau7802.o
|
||||
obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
|
||||
obj-$(CONFIG_PAC1921) += pac1921.o
|
||||
obj-$(CONFIG_PAC1934) += pac1934.o
|
||||
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
|
||||
obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
|
||||
|
722
drivers/iio/adc/ad4000.c
Normal file
722
drivers/iio/adc/ad4000.c
Normal file
@ -0,0 +1,722 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* AD4000 SPI ADC driver
|
||||
*
|
||||
* Copyright 2024 Analog Devices Inc.
|
||||
*/
|
||||
#include <linux/bits.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/byteorder/generic.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/units.h>
|
||||
#include <linux/util_macros.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
|
||||
#define AD4000_READ_COMMAND 0x54
|
||||
#define AD4000_WRITE_COMMAND 0x14
|
||||
|
||||
#define AD4000_CONFIG_REG_DEFAULT 0xE1
|
||||
|
||||
/* AD4000 Configuration Register programmable bits */
|
||||
#define AD4000_CFG_SPAN_COMP BIT(3) /* Input span compression */
|
||||
#define AD4000_CFG_HIGHZ BIT(2) /* High impedance mode */
|
||||
|
||||
#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, \
|
||||
.indexed = 1, \
|
||||
.differential = 1, \
|
||||
.channel = 0, \
|
||||
.channel2 = 1, \
|
||||
.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_type = { \
|
||||
.sign = _sign, \
|
||||
.realbits = _real_bits, \
|
||||
.storagebits = _storage_bits, \
|
||||
.shift = _storage_bits - _real_bits, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access) \
|
||||
__AD4000_DIFF_CHANNEL((_sign), (_real_bits), \
|
||||
((_real_bits) > 16 ? 32 : 16), (_reg_access))
|
||||
|
||||
#define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access)\
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = 0, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET), \
|
||||
.info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\
|
||||
.scan_type = { \
|
||||
.sign = _sign, \
|
||||
.realbits = _real_bits, \
|
||||
.storagebits = _storage_bits, \
|
||||
.shift = _storage_bits - _real_bits, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access) \
|
||||
__AD4000_PSEUDO_DIFF_CHANNEL((_sign), (_real_bits), \
|
||||
((_real_bits) > 16 ? 32 : 16), (_reg_access))
|
||||
|
||||
static const char * const ad4000_power_supplies[] = {
|
||||
"vdd", "vio"
|
||||
};
|
||||
|
||||
enum ad4000_sdi {
|
||||
AD4000_SDI_MOSI,
|
||||
AD4000_SDI_VIO,
|
||||
AD4000_SDI_CS,
|
||||
AD4000_SDI_GND,
|
||||
};
|
||||
|
||||
/* maps adi,sdi-pin property value to enum */
|
||||
static const char * const ad4000_sdi_pin[] = {
|
||||
[AD4000_SDI_MOSI] = "sdi",
|
||||
[AD4000_SDI_VIO] = "high",
|
||||
[AD4000_SDI_CS] = "cs",
|
||||
[AD4000_SDI_GND] = "low",
|
||||
};
|
||||
|
||||
/* Gains stored as fractions of 1000 so they can be expressed by integers. */
|
||||
static const int ad4000_gains[] = {
|
||||
454, 909, 1000, 1900,
|
||||
};
|
||||
|
||||
struct ad4000_chip_info {
|
||||
const char *dev_name;
|
||||
struct iio_chan_spec chan_spec;
|
||||
struct iio_chan_spec reg_access_chan_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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
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),
|
||||
.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),
|
||||
.has_hardware_gain = true,
|
||||
};
|
||||
|
||||
struct ad4000_state {
|
||||
struct spi_device *spi;
|
||||
struct gpio_desc *cnv_gpio;
|
||||
struct spi_transfer xfers[2];
|
||||
struct spi_message msg;
|
||||
struct mutex lock; /* Protect read modify write cycle */
|
||||
int vref_mv;
|
||||
enum ad4000_sdi sdi_pin;
|
||||
bool span_comp;
|
||||
u16 gain_milli;
|
||||
int scale_tbl[AD4000_SCALE_OPTIONS][2];
|
||||
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires the transfer buffers
|
||||
* to live in their own cache lines.
|
||||
*/
|
||||
struct {
|
||||
union {
|
||||
__be16 sample_buf16;
|
||||
__be32 sample_buf32;
|
||||
} data;
|
||||
s64 timestamp __aligned(8);
|
||||
} scan __aligned(IIO_DMA_MINALIGN);
|
||||
u8 tx_buf[2];
|
||||
u8 rx_buf[2];
|
||||
};
|
||||
|
||||
static void ad4000_fill_scale_tbl(struct ad4000_state *st,
|
||||
struct iio_chan_spec const *chan)
|
||||
{
|
||||
int val, tmp0, tmp1;
|
||||
int scale_bits;
|
||||
u64 tmp2;
|
||||
|
||||
/*
|
||||
* ADCs that output two's complement code have one less bit to express
|
||||
* voltage magnitude.
|
||||
*/
|
||||
if (chan->scan_type.sign == 's')
|
||||
scale_bits = chan->scan_type.realbits - 1;
|
||||
else
|
||||
scale_bits = chan->scan_type.realbits;
|
||||
|
||||
/*
|
||||
* The gain is stored as a fraction of 1000 and, as we need to
|
||||
* divide vref_mv by the gain, we invert the gain/1000 fraction.
|
||||
* Also multiply by an extra MILLI to preserve precision.
|
||||
* Thus, we have MILLI * MILLI equals MICRO as fraction numerator.
|
||||
*/
|
||||
val = mult_frac(st->vref_mv, MICRO, st->gain_milli);
|
||||
|
||||
/* Would multiply by NANO here but we multiplied by extra MILLI */
|
||||
tmp2 = shift_right((u64)val * MICRO, scale_bits);
|
||||
tmp0 = div_s64_rem(tmp2, NANO, &tmp1);
|
||||
|
||||
/* Store scale for when span compression is disabled */
|
||||
st->scale_tbl[0][0] = tmp0; /* Integer part */
|
||||
st->scale_tbl[0][1] = abs(tmp1); /* Fractional part */
|
||||
|
||||
/* Store scale for when span compression is enabled */
|
||||
st->scale_tbl[1][0] = tmp0;
|
||||
|
||||
/* The integer part is always zero so don't bother to divide it. */
|
||||
if (chan->differential)
|
||||
st->scale_tbl[1][1] = DIV_ROUND_CLOSEST(abs(tmp1) * 4, 5);
|
||||
else
|
||||
st->scale_tbl[1][1] = DIV_ROUND_CLOSEST(abs(tmp1) * 9, 10);
|
||||
}
|
||||
|
||||
static int ad4000_write_reg(struct ad4000_state *st, uint8_t val)
|
||||
{
|
||||
st->tx_buf[0] = AD4000_WRITE_COMMAND;
|
||||
st->tx_buf[1] = val;
|
||||
return spi_write(st->spi, st->tx_buf, ARRAY_SIZE(st->tx_buf));
|
||||
}
|
||||
|
||||
static int ad4000_read_reg(struct ad4000_state *st, unsigned int *val)
|
||||
{
|
||||
struct spi_transfer t = {
|
||||
.tx_buf = st->tx_buf,
|
||||
.rx_buf = st->rx_buf,
|
||||
.len = 2,
|
||||
};
|
||||
int ret;
|
||||
|
||||
st->tx_buf[0] = AD4000_READ_COMMAND;
|
||||
ret = spi_sync_transfer(st->spi, &t, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = st->rx_buf[1];
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad4000_convert_and_acquire(struct ad4000_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* In 4-wire mode, the CNV line is held high for the entire conversion
|
||||
* and acquisition process. In other modes, the CNV GPIO is optional
|
||||
* and, if provided, replaces controller CS. If CNV GPIO is not defined
|
||||
* gpiod_set_value_cansleep() has no effect.
|
||||
*/
|
||||
gpiod_set_value_cansleep(st->cnv_gpio, 1);
|
||||
ret = spi_sync(st->spi, &st->msg);
|
||||
gpiod_set_value_cansleep(st->cnv_gpio, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad4000_single_conversion(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, int *val)
|
||||
{
|
||||
struct ad4000_state *st = iio_priv(indio_dev);
|
||||
u32 sample;
|
||||
int ret;
|
||||
|
||||
ret = ad4000_convert_and_acquire(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (chan->scan_type.storagebits > 16)
|
||||
sample = be32_to_cpu(st->scan.data.sample_buf32);
|
||||
else
|
||||
sample = be16_to_cpu(st->scan.data.sample_buf16);
|
||||
|
||||
sample >>= chan->scan_type.shift;
|
||||
|
||||
if (chan->scan_type.sign == 's')
|
||||
*val = sign_extend32(sample, chan->scan_type.realbits - 1);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int ad4000_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long info)
|
||||
{
|
||||
struct ad4000_state *st = iio_priv(indio_dev);
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
|
||||
return ad4000_single_conversion(indio_dev, chan, val);
|
||||
unreachable();
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = st->scale_tbl[st->span_comp][0];
|
||||
*val2 = st->scale_tbl[st->span_comp][1];
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = 0;
|
||||
if (st->span_comp)
|
||||
*val = mult_frac(st->vref_mv, 1, 10);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad4000_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length,
|
||||
long info)
|
||||
{
|
||||
struct ad4000_state *st = iio_priv(indio_dev);
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*vals = (int *)st->scale_tbl;
|
||||
*length = AD4000_SCALE_OPTIONS * 2;
|
||||
*type = IIO_VAL_INT_PLUS_NANO;
|
||||
return IIO_AVAIL_LIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad4000_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, long mask)
|
||||
{
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
default:
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad4000_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int val, int val2,
|
||||
long mask)
|
||||
{
|
||||
struct ad4000_state *st = iio_priv(indio_dev);
|
||||
unsigned int reg_val;
|
||||
bool span_comp_en;
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
ret = ad4000_read_reg(st, ®_val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
span_comp_en = val2 == st->scale_tbl[1][1];
|
||||
reg_val &= ~AD4000_CFG_SPAN_COMP;
|
||||
reg_val |= FIELD_PREP(AD4000_CFG_SPAN_COMP, span_comp_en);
|
||||
|
||||
ret = ad4000_write_reg(st, reg_val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st->span_comp = span_comp_en;
|
||||
return 0;
|
||||
}
|
||||
unreachable();
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t ad4000_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct ad4000_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = ad4000_convert_and_acquire(st);
|
||||
if (ret < 0)
|
||||
goto err_out;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp);
|
||||
|
||||
err_out:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct iio_info ad4000_reg_access_info = {
|
||||
.read_raw = &ad4000_read_raw,
|
||||
.read_avail = &ad4000_read_avail,
|
||||
.write_raw = &ad4000_write_raw,
|
||||
.write_raw_get_fmt = &ad4000_write_raw_get_fmt,
|
||||
};
|
||||
|
||||
static const struct iio_info ad4000_info = {
|
||||
.read_raw = &ad4000_read_raw,
|
||||
};
|
||||
|
||||
/*
|
||||
* This executes a data sample transfer for when the device connections are
|
||||
* in "3-wire" mode, selected when the adi,sdi-pin device tree property is
|
||||
* absent or set to "high". In this connection mode, the ADC SDI pin is
|
||||
* connected to MOSI or to VIO and ADC CNV pin is connected either to a SPI
|
||||
* controller CS or to a GPIO.
|
||||
* AD4000 series of devices initiate conversions on the rising edge of CNV pin.
|
||||
*
|
||||
* If the CNV pin is connected to an SPI controller CS line (which is by default
|
||||
* active low), the ADC readings would have a latency (delay) of one read.
|
||||
* Moreover, since we also do ADC sampling for filling the buffer on triggered
|
||||
* buffer mode, the timestamps of buffer readings would be disarranged.
|
||||
* To prevent the read latency and reduce the time discrepancy between the
|
||||
* sample read request and the time of actual sampling by the ADC, do a
|
||||
* preparatory transfer to pulse the CS/CNV line.
|
||||
*/
|
||||
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.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.unit = SPI_DELAY_UNIT_NSECS;
|
||||
|
||||
spi_message_init_with_transfers(&st->msg, st->xfers, 2);
|
||||
|
||||
return devm_spi_optimize_message(&st->spi->dev, st->spi, &st->msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* This executes a data sample transfer for when the device connections are
|
||||
* in "4-wire" mode, selected when the adi,sdi-pin device tree property is
|
||||
* set to "cs". In this connection mode, the controller CS pin is connected to
|
||||
* ADC SDI pin and a GPIO is connected to ADC CNV pin.
|
||||
* The GPIO connected to ADC CNV pin is set outside of the SPI transfer.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
* Dummy transfer to cause enough delay between CNV going high and SDI
|
||||
* going low.
|
||||
*/
|
||||
xfers[0].cs_off = 1;
|
||||
xfers[0].delay.value = cnv_to_sdi_time;
|
||||
xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
|
||||
xfers[1].rx_buf = &st->scan.data;
|
||||
xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits);
|
||||
|
||||
spi_message_init_with_transfers(&st->msg, st->xfers, 2);
|
||||
|
||||
return devm_spi_optimize_message(&st->spi->dev, st->spi, &st->msg);
|
||||
}
|
||||
|
||||
static int ad4000_config(struct ad4000_state *st)
|
||||
{
|
||||
unsigned int reg_val = AD4000_CONFIG_REG_DEFAULT;
|
||||
|
||||
if (device_property_present(&st->spi->dev, "adi,high-z-input"))
|
||||
reg_val |= FIELD_PREP(AD4000_CFG_HIGHZ, 1);
|
||||
|
||||
return ad4000_write_reg(st, reg_val);
|
||||
}
|
||||
|
||||
static int ad4000_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct ad4000_chip_info *chip;
|
||||
struct device *dev = &spi->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad4000_state *st;
|
||||
int gain_idx, ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
chip = spi_get_device_match_data(spi);
|
||||
if (!chip)
|
||||
return -EINVAL;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
st->spi = spi;
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4000_power_supplies),
|
||||
ad4000_power_supplies);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to enable power supplies\n");
|
||||
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, "ref");
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to get ref regulator reference\n");
|
||||
st->vref_mv = ret / 1000;
|
||||
|
||||
st->cnv_gpio = devm_gpiod_get_optional(dev, "cnv", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(st->cnv_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(st->cnv_gpio),
|
||||
"Failed to get CNV GPIO");
|
||||
|
||||
ret = device_property_match_property_string(dev, "adi,sdi-pin",
|
||||
ad4000_sdi_pin,
|
||||
ARRAY_SIZE(ad4000_sdi_pin));
|
||||
if (ret < 0 && ret != -EINVAL)
|
||||
return dev_err_probe(dev, ret,
|
||||
"getting adi,sdi-pin property failed\n");
|
||||
|
||||
/* Default to usual SPI connections if pin properties are not present */
|
||||
st->sdi_pin = ret == -EINVAL ? AD4000_SDI_MOSI : ret;
|
||||
switch (st->sdi_pin) {
|
||||
case AD4000_SDI_MOSI:
|
||||
indio_dev->info = &ad4000_reg_access_info;
|
||||
indio_dev->channels = &chip->reg_access_chan_spec;
|
||||
|
||||
/*
|
||||
* In "3-wire mode", the ADC SDI line must be kept high when
|
||||
* data is not being clocked out of the controller.
|
||||
* Request the SPI controller to make MOSI idle high.
|
||||
*/
|
||||
spi->mode |= SPI_MOSI_IDLE_HIGH;
|
||||
ret = spi_setup(spi);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad4000_prepare_3wire_mode_message(st, indio_dev->channels);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad4000_config(st);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to config device\n");
|
||||
|
||||
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);
|
||||
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);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
case AD4000_SDI_GND:
|
||||
return dev_err_probe(dev, -EPROTONOSUPPORT,
|
||||
"Unsupported connection mode\n");
|
||||
|
||||
default:
|
||||
return dev_err_probe(dev, -EINVAL, "Unrecognized connection mode\n");
|
||||
}
|
||||
|
||||
indio_dev->name = chip->dev_name;
|
||||
indio_dev->num_channels = 1;
|
||||
|
||||
devm_mutex_init(dev, &st->lock);
|
||||
|
||||
st->gain_milli = 1000;
|
||||
if (chip->has_hardware_gain) {
|
||||
ret = device_property_read_u16(dev, "adi,gain-milli",
|
||||
&st->gain_milli);
|
||||
if (!ret) {
|
||||
/* Match gain value from dt to one of supported gains */
|
||||
gain_idx = find_closest(st->gain_milli, ad4000_gains,
|
||||
ARRAY_SIZE(ad4000_gains));
|
||||
st->gain_milli = ad4000_gains[gain_idx];
|
||||
} else {
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to read gain property\n");
|
||||
}
|
||||
}
|
||||
|
||||
ad4000_fill_scale_tbl(st, indio_dev->channels);
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
&ad4000_trigger_handler, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad4000_id[] = {
|
||||
{ "ad4000", (kernel_ulong_t)&ad4000_chip_info },
|
||||
{ "ad4001", (kernel_ulong_t)&ad4001_chip_info },
|
||||
{ "ad4002", (kernel_ulong_t)&ad4002_chip_info },
|
||||
{ "ad4003", (kernel_ulong_t)&ad4003_chip_info },
|
||||
{ "ad4004", (kernel_ulong_t)&ad4004_chip_info },
|
||||
{ "ad4005", (kernel_ulong_t)&ad4005_chip_info },
|
||||
{ "ad4006", (kernel_ulong_t)&ad4006_chip_info },
|
||||
{ "ad4007", (kernel_ulong_t)&ad4007_chip_info },
|
||||
{ "ad4008", (kernel_ulong_t)&ad4008_chip_info },
|
||||
{ "ad4010", (kernel_ulong_t)&ad4010_chip_info },
|
||||
{ "ad4011", (kernel_ulong_t)&ad4011_chip_info },
|
||||
{ "ad4020", (kernel_ulong_t)&ad4020_chip_info },
|
||||
{ "ad4021", (kernel_ulong_t)&ad4021_chip_info },
|
||||
{ "ad4022", (kernel_ulong_t)&ad4022_chip_info },
|
||||
{ "adaq4001", (kernel_ulong_t)&adaq4001_chip_info },
|
||||
{ "adaq4003", (kernel_ulong_t)&adaq4003_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad4000_id);
|
||||
|
||||
static const struct of_device_id ad4000_of_match[] = {
|
||||
{ .compatible = "adi,ad4000", .data = &ad4000_chip_info },
|
||||
{ .compatible = "adi,ad4001", .data = &ad4001_chip_info },
|
||||
{ .compatible = "adi,ad4002", .data = &ad4002_chip_info },
|
||||
{ .compatible = "adi,ad4003", .data = &ad4003_chip_info },
|
||||
{ .compatible = "adi,ad4004", .data = &ad4004_chip_info },
|
||||
{ .compatible = "adi,ad4005", .data = &ad4005_chip_info },
|
||||
{ .compatible = "adi,ad4006", .data = &ad4006_chip_info },
|
||||
{ .compatible = "adi,ad4007", .data = &ad4007_chip_info },
|
||||
{ .compatible = "adi,ad4008", .data = &ad4008_chip_info },
|
||||
{ .compatible = "adi,ad4010", .data = &ad4010_chip_info },
|
||||
{ .compatible = "adi,ad4011", .data = &ad4011_chip_info },
|
||||
{ .compatible = "adi,ad4020", .data = &ad4020_chip_info },
|
||||
{ .compatible = "adi,ad4021", .data = &ad4021_chip_info },
|
||||
{ .compatible = "adi,ad4022", .data = &ad4022_chip_info },
|
||||
{ .compatible = "adi,adaq4001", .data = &adaq4001_chip_info },
|
||||
{ .compatible = "adi,adaq4003", .data = &adaq4003_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad4000_of_match);
|
||||
|
||||
static struct spi_driver ad4000_driver = {
|
||||
.driver = {
|
||||
.name = "ad4000",
|
||||
.of_match_table = ad4000_of_match,
|
||||
},
|
||||
.probe = ad4000_probe,
|
||||
.id_table = ad4000_id,
|
||||
};
|
||||
module_spi_driver(ad4000_driver);
|
||||
|
||||
MODULE_AUTHOR("Marcelo Schmitt <marcelo.schmitt@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD4000 ADC driver");
|
||||
MODULE_LICENSE("GPL");
|
978
drivers/iio/adc/ad4695.c
Normal file
978
drivers/iio/adc/ad4695.c
Normal file
@ -0,0 +1,978 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPI ADC driver for Analog Devices Inc. AD4695 and similar chips
|
||||
*
|
||||
* https://www.analog.com/en/products/ad4695.html
|
||||
* https://www.analog.com/en/products/ad4696.html
|
||||
* https://www.analog.com/en/products/ad4697.html
|
||||
* https://www.analog.com/en/products/ad4698.html
|
||||
*
|
||||
* Copyright 2024 Analog Devices Inc.
|
||||
* Copyright 2024 BayLibre, SAS
|
||||
*/
|
||||
|
||||
#include <linux/align.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include <dt-bindings/iio/adi,ad4695.h>
|
||||
|
||||
/* AD4695 registers */
|
||||
#define AD4695_REG_SPI_CONFIG_A 0x0000
|
||||
#define AD4695_REG_SPI_CONFIG_A_SW_RST (BIT(7) | BIT(0))
|
||||
#define AD4695_REG_SPI_CONFIG_B 0x0001
|
||||
#define AD4695_REG_SPI_CONFIG_B_INST_MODE BIT(7)
|
||||
#define AD4695_REG_DEVICE_TYPE 0x0003
|
||||
#define AD4695_REG_SCRATCH_PAD 0x000A
|
||||
#define AD4695_REG_VENDOR_L 0x000C
|
||||
#define AD4695_REG_VENDOR_H 0x000D
|
||||
#define AD4695_REG_LOOP_MODE 0x000E
|
||||
#define AD4695_REG_SPI_CONFIG_C 0x0010
|
||||
#define AD4695_REG_SPI_CONFIG_C_MB_STRICT BIT(7)
|
||||
#define AD4695_REG_SPI_STATUS 0x0011
|
||||
#define AD4695_REG_STATUS 0x0014
|
||||
#define AD4695_REG_ALERT_STATUS1 0x0015
|
||||
#define AD4695_REG_ALERT_STATUS2 0x0016
|
||||
#define AD4695_REG_CLAMP_STATUS 0x001A
|
||||
#define AD4695_REG_SETUP 0x0020
|
||||
#define AD4695_REG_SETUP_LDO_EN BIT(4)
|
||||
#define AD4695_REG_SETUP_SPI_MODE BIT(2)
|
||||
#define AD4695_REG_SETUP_SPI_CYC_CTRL BIT(1)
|
||||
#define AD4695_REG_REF_CTRL 0x0021
|
||||
#define AD4695_REG_REF_CTRL_OV_MODE BIT(7)
|
||||
#define AD4695_REG_REF_CTRL_VREF_SET GENMASK(4, 2)
|
||||
#define AD4695_REG_REF_CTRL_REFHIZ_EN BIT(1)
|
||||
#define AD4695_REG_REF_CTRL_REFBUF_EN BIT(0)
|
||||
#define AD4695_REG_SEQ_CTRL 0x0022
|
||||
#define AD4695_REG_SEQ_CTRL_STD_SEQ_EN BIT(7)
|
||||
#define AD4695_REG_SEQ_CTRL_NUM_SLOTS_AS GENMASK(6, 0)
|
||||
#define AD4695_REG_AC_CTRL 0x0023
|
||||
#define AD4695_REG_STD_SEQ_CONFIG 0x0024
|
||||
#define AD4695_REG_GPIO_CTRL 0x0026
|
||||
#define AD4695_REG_GP_MODE 0x0027
|
||||
#define AD4695_REG_TEMP_CTRL 0x0029
|
||||
#define AD4695_REG_TEMP_CTRL_TEMP_EN BIT(0)
|
||||
#define AD4695_REG_CONFIG_IN(n) (0x0030 | (n))
|
||||
#define AD4695_REG_CONFIG_IN_MODE BIT(6)
|
||||
#define AD4695_REG_CONFIG_IN_PAIR GENMASK(5, 4)
|
||||
#define AD4695_REG_CONFIG_IN_AINHIGHZ_EN BIT(3)
|
||||
#define AD4695_REG_UPPER_IN(n) (0x0040 | (2 * (n)))
|
||||
#define AD4695_REG_LOWER_IN(n) (0x0060 | (2 * (n)))
|
||||
#define AD4695_REG_HYST_IN(n) (0x0080 | (2 * (n)))
|
||||
#define AD4695_REG_OFFSET_IN(n) (0x00A0 | (2 * (n)))
|
||||
#define AD4695_REG_GAIN_IN(n) (0x00C0 | (2 * (n)))
|
||||
#define AD4695_REG_AS_SLOT(n) (0x0100 | (n))
|
||||
#define AD4695_REG_AS_SLOT_INX GENMASK(3, 0)
|
||||
#define AD4695_MAX_REG 0x017F
|
||||
|
||||
/* Conversion mode commands */
|
||||
#define AD4695_CMD_EXIT_CNV_MODE 0x0A
|
||||
#define AD4695_CMD_TEMP_CHAN 0x0F
|
||||
#define AD4695_CMD_VOLTAGE_CHAN(n) (0x10 | (n))
|
||||
|
||||
/* timing specs */
|
||||
#define AD4695_T_CONVERT_NS 415
|
||||
#define AD4695_T_WAKEUP_HW_MS 3
|
||||
#define AD4695_T_WAKEUP_SW_MS 3
|
||||
#define AD4695_T_REFBUF_MS 100
|
||||
#define AD4695_T_REGCONFIG_NS 20
|
||||
#define AD4695_REG_ACCESS_SCLK_HZ (10 * MEGA)
|
||||
|
||||
/* Max number of voltage input channels. */
|
||||
#define AD4695_MAX_CHANNELS 16
|
||||
/* Max size of 1 raw sample in bytes. */
|
||||
#define AD4695_MAX_CHANNEL_SIZE 2
|
||||
|
||||
enum ad4695_in_pair {
|
||||
AD4695_IN_PAIR_REFGND,
|
||||
AD4695_IN_PAIR_COM,
|
||||
AD4695_IN_PAIR_EVEN_ODD,
|
||||
};
|
||||
|
||||
struct ad4695_chip_info {
|
||||
const char *name;
|
||||
int max_sample_rate;
|
||||
u32 t_acq_ns;
|
||||
u8 num_voltage_inputs;
|
||||
};
|
||||
|
||||
struct ad4695_channel_config {
|
||||
unsigned int channel;
|
||||
bool highz_en;
|
||||
bool bipolar;
|
||||
enum ad4695_in_pair pin_pairing;
|
||||
unsigned int common_mode_mv;
|
||||
};
|
||||
|
||||
struct ad4695_state {
|
||||
struct spi_device *spi;
|
||||
struct regmap *regmap;
|
||||
struct gpio_desc *reset_gpio;
|
||||
/* voltages channels plus temperature and timestamp */
|
||||
struct iio_chan_spec iio_chan[AD4695_MAX_CHANNELS + 2];
|
||||
struct ad4695_channel_config channels_cfg[AD4695_MAX_CHANNELS];
|
||||
const struct ad4695_chip_info *chip_info;
|
||||
/* Reference voltage. */
|
||||
unsigned int vref_mv;
|
||||
/* Common mode input pin voltage. */
|
||||
unsigned int com_mv;
|
||||
/* 1 per voltage and temperature chan plus 1 xfer to trigger 1st CNV */
|
||||
struct spi_transfer buf_read_xfer[AD4695_MAX_CHANNELS + 2];
|
||||
struct spi_message buf_read_msg;
|
||||
/* Raw conversion data received. */
|
||||
u8 buf[ALIGN((AD4695_MAX_CHANNELS + 2) * AD4695_MAX_CHANNEL_SIZE,
|
||||
sizeof(s64)) + sizeof(s64)] __aligned(IIO_DMA_MINALIGN);
|
||||
u16 raw_data;
|
||||
/* Commands to send for single conversion. */
|
||||
u16 cnv_cmd;
|
||||
u8 cnv_cmd2;
|
||||
};
|
||||
|
||||
static const struct regmap_range ad4695_regmap_rd_ranges[] = {
|
||||
regmap_reg_range(AD4695_REG_SPI_CONFIG_A, AD4695_REG_SPI_CONFIG_B),
|
||||
regmap_reg_range(AD4695_REG_DEVICE_TYPE, AD4695_REG_DEVICE_TYPE),
|
||||
regmap_reg_range(AD4695_REG_SCRATCH_PAD, AD4695_REG_SCRATCH_PAD),
|
||||
regmap_reg_range(AD4695_REG_VENDOR_L, AD4695_REG_LOOP_MODE),
|
||||
regmap_reg_range(AD4695_REG_SPI_CONFIG_C, AD4695_REG_SPI_STATUS),
|
||||
regmap_reg_range(AD4695_REG_STATUS, AD4695_REG_ALERT_STATUS2),
|
||||
regmap_reg_range(AD4695_REG_CLAMP_STATUS, AD4695_REG_CLAMP_STATUS),
|
||||
regmap_reg_range(AD4695_REG_SETUP, AD4695_REG_TEMP_CTRL),
|
||||
regmap_reg_range(AD4695_REG_CONFIG_IN(0), AD4695_MAX_REG),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table ad4695_regmap_rd_table = {
|
||||
.yes_ranges = ad4695_regmap_rd_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(ad4695_regmap_rd_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_range ad4695_regmap_wr_ranges[] = {
|
||||
regmap_reg_range(AD4695_REG_SPI_CONFIG_A, AD4695_REG_SPI_CONFIG_B),
|
||||
regmap_reg_range(AD4695_REG_SCRATCH_PAD, AD4695_REG_SCRATCH_PAD),
|
||||
regmap_reg_range(AD4695_REG_LOOP_MODE, AD4695_REG_LOOP_MODE),
|
||||
regmap_reg_range(AD4695_REG_SPI_CONFIG_C, AD4695_REG_SPI_STATUS),
|
||||
regmap_reg_range(AD4695_REG_SETUP, AD4695_REG_TEMP_CTRL),
|
||||
regmap_reg_range(AD4695_REG_CONFIG_IN(0), AD4695_MAX_REG),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table ad4695_regmap_wr_table = {
|
||||
.yes_ranges = ad4695_regmap_wr_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(ad4695_regmap_wr_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config ad4695_regmap_config = {
|
||||
.name = "ad4695",
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.max_register = AD4695_MAX_REG,
|
||||
.rd_table = &ad4695_regmap_rd_table,
|
||||
.wr_table = &ad4695_regmap_wr_table,
|
||||
.can_multi_write = true,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad4695_channel_template = {
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET),
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad4695_temp_channel_template = {
|
||||
.address = AD4695_CMD_TEMP_CHAN,
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET),
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad4695_soft_timestamp_channel_template =
|
||||
IIO_CHAN_SOFT_TIMESTAMP(0);
|
||||
|
||||
static const char * const ad4695_power_supplies[] = {
|
||||
"avdd", "vio"
|
||||
};
|
||||
|
||||
static const struct ad4695_chip_info ad4695_chip_info = {
|
||||
.name = "ad4695",
|
||||
.max_sample_rate = 500 * KILO,
|
||||
.t_acq_ns = 1715,
|
||||
.num_voltage_inputs = 16,
|
||||
};
|
||||
|
||||
static const struct ad4695_chip_info ad4696_chip_info = {
|
||||
.name = "ad4696",
|
||||
.max_sample_rate = 1 * MEGA,
|
||||
.t_acq_ns = 715,
|
||||
.num_voltage_inputs = 16,
|
||||
};
|
||||
|
||||
static const struct ad4695_chip_info ad4697_chip_info = {
|
||||
.name = "ad4697",
|
||||
.max_sample_rate = 500 * KILO,
|
||||
.t_acq_ns = 1715,
|
||||
.num_voltage_inputs = 8,
|
||||
};
|
||||
|
||||
static const struct ad4695_chip_info ad4698_chip_info = {
|
||||
.name = "ad4698",
|
||||
.max_sample_rate = 1 * MEGA,
|
||||
.t_acq_ns = 715,
|
||||
.num_voltage_inputs = 8,
|
||||
};
|
||||
|
||||
/**
|
||||
* ad4695_set_single_cycle_mode - Set the device in single cycle mode
|
||||
* @st: The AD4695 state
|
||||
* @channel: The first channel to read
|
||||
*
|
||||
* As per the datasheet, to enable single cycle mode, we need to set
|
||||
* STD_SEQ_EN=0, NUM_SLOTS_AS=0 and CYC_CTRL=1 (Table 15). Setting SPI_MODE=1
|
||||
* triggers the first conversion using the channel in AS_SLOT0.
|
||||
*
|
||||
* Context: can sleep, must be called with iio_device_claim_direct held
|
||||
* Return: 0 on success, a negative error code on failure
|
||||
*/
|
||||
static int ad4695_set_single_cycle_mode(struct ad4695_state *st,
|
||||
unsigned int channel)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_clear_bits(st->regmap, AD4695_REG_SEQ_CTRL,
|
||||
AD4695_REG_SEQ_CTRL_STD_SEQ_EN |
|
||||
AD4695_REG_SEQ_CTRL_NUM_SLOTS_AS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(st->regmap, AD4695_REG_AS_SLOT(0),
|
||||
FIELD_PREP(AD4695_REG_AS_SLOT_INX, channel));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_set_bits(st->regmap, AD4695_REG_SETUP,
|
||||
AD4695_REG_SETUP_SPI_MODE |
|
||||
AD4695_REG_SETUP_SPI_CYC_CTRL);
|
||||
}
|
||||
|
||||
/**
|
||||
* ad4695_enter_advanced_sequencer_mode - Put the ADC in advanced sequencer mode
|
||||
* @st: The driver state
|
||||
* @n: The number of slots to use - must be >= 2, <= 128
|
||||
*
|
||||
* As per the datasheet, to enable advanced sequencer, we need to set
|
||||
* STD_SEQ_EN=0, NUM_SLOTS_AS=n-1 and CYC_CTRL=0 (Table 15). Setting SPI_MODE=1
|
||||
* triggers the first conversion using the channel in AS_SLOT0.
|
||||
*
|
||||
* Return: 0 on success, a negative error code on failure
|
||||
*/
|
||||
static int ad4695_enter_advanced_sequencer_mode(struct ad4695_state *st, u32 n)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(st->regmap, AD4695_REG_SEQ_CTRL,
|
||||
AD4695_REG_SEQ_CTRL_STD_SEQ_EN |
|
||||
AD4695_REG_SEQ_CTRL_NUM_SLOTS_AS,
|
||||
FIELD_PREP(AD4695_REG_SEQ_CTRL_STD_SEQ_EN, 0) |
|
||||
FIELD_PREP(AD4695_REG_SEQ_CTRL_NUM_SLOTS_AS, n - 1));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(st->regmap, AD4695_REG_SETUP,
|
||||
AD4695_REG_SETUP_SPI_MODE | AD4695_REG_SETUP_SPI_CYC_CTRL,
|
||||
FIELD_PREP(AD4695_REG_SETUP_SPI_MODE, 1) |
|
||||
FIELD_PREP(AD4695_REG_SETUP_SPI_CYC_CTRL, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* ad4695_exit_conversion_mode - Exit conversion mode
|
||||
* @st: The AD4695 state
|
||||
*
|
||||
* Sends SPI command to exit conversion mode.
|
||||
*
|
||||
* Return: 0 on success, a negative error code on failure
|
||||
*/
|
||||
static int ad4695_exit_conversion_mode(struct ad4695_state *st)
|
||||
{
|
||||
struct spi_transfer xfer = {
|
||||
.tx_buf = &st->cnv_cmd2,
|
||||
.len = 1,
|
||||
.delay.value = AD4695_T_REGCONFIG_NS,
|
||||
.delay.unit = SPI_DELAY_UNIT_NSECS,
|
||||
};
|
||||
|
||||
/*
|
||||
* Technically, could do a 5-bit transfer, but shifting to start of
|
||||
* 8 bits instead for better SPI controller support.
|
||||
*/
|
||||
st->cnv_cmd2 = AD4695_CMD_EXIT_CNV_MODE << 3;
|
||||
|
||||
return spi_sync_transfer(st->spi, &xfer, 1);
|
||||
}
|
||||
|
||||
static int ad4695_set_ref_voltage(struct ad4695_state *st, int vref_mv)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
if (vref_mv >= 2400 && vref_mv <= 2750)
|
||||
val = 0;
|
||||
else if (vref_mv > 2750 && vref_mv <= 3250)
|
||||
val = 1;
|
||||
else if (vref_mv > 3250 && vref_mv <= 3750)
|
||||
val = 2;
|
||||
else if (vref_mv > 3750 && vref_mv <= 4500)
|
||||
val = 3;
|
||||
else if (vref_mv > 4500 && vref_mv <= 5100)
|
||||
val = 4;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_update_bits(st->regmap, AD4695_REG_REF_CTRL,
|
||||
AD4695_REG_REF_CTRL_VREF_SET,
|
||||
FIELD_PREP(AD4695_REG_REF_CTRL_VREF_SET, val));
|
||||
}
|
||||
|
||||
static int ad4695_write_chn_cfg(struct ad4695_state *st,
|
||||
struct ad4695_channel_config *cfg)
|
||||
{
|
||||
u32 mask, val;
|
||||
|
||||
mask = AD4695_REG_CONFIG_IN_MODE;
|
||||
val = FIELD_PREP(AD4695_REG_CONFIG_IN_MODE, cfg->bipolar ? 1 : 0);
|
||||
|
||||
mask |= AD4695_REG_CONFIG_IN_PAIR;
|
||||
val |= FIELD_PREP(AD4695_REG_CONFIG_IN_PAIR, cfg->pin_pairing);
|
||||
|
||||
mask |= AD4695_REG_CONFIG_IN_AINHIGHZ_EN;
|
||||
val |= FIELD_PREP(AD4695_REG_CONFIG_IN_AINHIGHZ_EN,
|
||||
cfg->highz_en ? 1 : 0);
|
||||
|
||||
return regmap_update_bits(st->regmap,
|
||||
AD4695_REG_CONFIG_IN(cfg->channel),
|
||||
mask, val);
|
||||
}
|
||||
|
||||
static int ad4695_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad4695_state *st = iio_priv(indio_dev);
|
||||
struct spi_transfer *xfer;
|
||||
u8 temp_chan_bit = st->chip_info->num_voltage_inputs;
|
||||
u32 bit, num_xfer, num_slots;
|
||||
u32 temp_en = 0;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We are using the advanced sequencer since it is the only way to read
|
||||
* multiple channels that allows individual configuration of each
|
||||
* voltage input channel. Slot 0 in the advanced sequencer is used to
|
||||
* account for the gap between trigger polls - we don't read data from
|
||||
* this slot. Each enabled voltage channel is assigned a slot starting
|
||||
* with slot 1.
|
||||
*/
|
||||
num_slots = 1;
|
||||
|
||||
memset(st->buf_read_xfer, 0, sizeof(st->buf_read_xfer));
|
||||
|
||||
/* First xfer is only to trigger conversion of slot 1, so no rx. */
|
||||
xfer = &st->buf_read_xfer[0];
|
||||
xfer->cs_change = 1;
|
||||
xfer->delay.value = st->chip_info->t_acq_ns;
|
||||
xfer->delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
xfer->cs_change_delay.value = AD4695_T_CONVERT_NS;
|
||||
xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
num_xfer = 1;
|
||||
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
xfer = &st->buf_read_xfer[num_xfer];
|
||||
xfer->bits_per_word = 16;
|
||||
xfer->rx_buf = &st->buf[(num_xfer - 1) * 2];
|
||||
xfer->len = 2;
|
||||
xfer->cs_change = 1;
|
||||
xfer->cs_change_delay.value = AD4695_T_CONVERT_NS;
|
||||
xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
|
||||
if (bit == temp_chan_bit) {
|
||||
temp_en = 1;
|
||||
} else {
|
||||
ret = regmap_write(st->regmap,
|
||||
AD4695_REG_AS_SLOT(num_slots),
|
||||
FIELD_PREP(AD4695_REG_AS_SLOT_INX, bit));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
num_slots++;
|
||||
}
|
||||
|
||||
num_xfer++;
|
||||
}
|
||||
|
||||
/*
|
||||
* The advanced sequencer requires that at least 2 slots are enabled.
|
||||
* Since slot 0 is always used for other purposes, we need only 1
|
||||
* enabled voltage channel to meet this requirement. If the temperature
|
||||
* channel is the only enabled channel, we need to add one more slot
|
||||
* in the sequence but not read from it.
|
||||
*/
|
||||
if (num_slots < 2) {
|
||||
/* move last xfer so we can insert one more xfer before it */
|
||||
st->buf_read_xfer[num_xfer] = *xfer;
|
||||
num_xfer++;
|
||||
|
||||
/* modify 2nd to last xfer for extra slot */
|
||||
memset(xfer, 0, sizeof(*xfer));
|
||||
xfer->cs_change = 1;
|
||||
xfer->delay.value = st->chip_info->t_acq_ns;
|
||||
xfer->delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
xfer->cs_change_delay.value = AD4695_T_CONVERT_NS;
|
||||
xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
xfer++;
|
||||
|
||||
/* and add the extra slot in the sequencer */
|
||||
ret = regmap_write(st->regmap,
|
||||
AD4695_REG_AS_SLOT(num_slots),
|
||||
FIELD_PREP(AD4695_REG_AS_SLOT_INX, 0));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
num_slots++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't keep CS asserted after last xfer. Also triggers conversion of
|
||||
* slot 0.
|
||||
*/
|
||||
xfer->cs_change = 0;
|
||||
|
||||
/*
|
||||
* Temperature channel isn't included in the sequence, but rather
|
||||
* controlled by setting a bit in the TEMP_CTRL register.
|
||||
*/
|
||||
|
||||
ret = regmap_update_bits(st->regmap, AD4695_REG_TEMP_CTRL,
|
||||
AD4695_REG_TEMP_CTRL_TEMP_EN,
|
||||
FIELD_PREP(AD4695_REG_TEMP_CTRL_TEMP_EN, temp_en));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spi_message_init_with_transfers(&st->buf_read_msg, st->buf_read_xfer,
|
||||
num_xfer);
|
||||
|
||||
ret = spi_optimize_message(st->spi, &st->buf_read_msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* This triggers conversion of slot 0. */
|
||||
ret = ad4695_enter_advanced_sequencer_mode(st, num_slots);
|
||||
if (ret)
|
||||
spi_unoptimize_message(&st->buf_read_msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad4695_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad4695_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = ad4695_exit_conversion_mode(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spi_unoptimize_message(&st->buf_read_msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops ad4695_buffer_setup_ops = {
|
||||
.preenable = ad4695_buffer_preenable,
|
||||
.postdisable = ad4695_buffer_postdisable,
|
||||
};
|
||||
|
||||
static irqreturn_t ad4695_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct ad4695_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = spi_sync(st->spi, &st->buf_read_msg);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->buf, pf->timestamp);
|
||||
|
||||
out:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* ad4695_read_one_sample - Read a single sample using single-cycle mode
|
||||
* @st: The AD4695 state
|
||||
* @address: The address of the channel to read
|
||||
*
|
||||
* Upon successful return, the sample will be stored in `st->raw_data`.
|
||||
*
|
||||
* Context: can sleep, must be called with iio_device_claim_direct held
|
||||
* Return: 0 on success, a negative error code on failure
|
||||
*/
|
||||
static int ad4695_read_one_sample(struct ad4695_state *st, unsigned int address)
|
||||
{
|
||||
struct spi_transfer xfer[2] = { };
|
||||
int ret, i = 0;
|
||||
|
||||
ret = ad4695_set_single_cycle_mode(st, address);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Setting the first channel to the temperature channel isn't supported
|
||||
* in single-cycle mode, so we have to do an extra xfer to read the
|
||||
* temperature.
|
||||
*/
|
||||
if (address == AD4695_CMD_TEMP_CHAN) {
|
||||
/* We aren't reading, so we can make this a short xfer. */
|
||||
st->cnv_cmd2 = AD4695_CMD_TEMP_CHAN << 3;
|
||||
xfer[0].tx_buf = &st->cnv_cmd2;
|
||||
xfer[0].len = 1;
|
||||
xfer[0].cs_change = 1;
|
||||
xfer[0].cs_change_delay.value = AD4695_T_CONVERT_NS;
|
||||
xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
|
||||
i = 1;
|
||||
}
|
||||
|
||||
/* Then read the result and exit conversion mode. */
|
||||
st->cnv_cmd = AD4695_CMD_EXIT_CNV_MODE << 11;
|
||||
xfer[i].bits_per_word = 16;
|
||||
xfer[i].tx_buf = &st->cnv_cmd;
|
||||
xfer[i].rx_buf = &st->raw_data;
|
||||
xfer[i].len = 2;
|
||||
|
||||
return spi_sync_transfer(st->spi, xfer, i + 1);
|
||||
}
|
||||
|
||||
static int ad4695_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct ad4695_state *st = iio_priv(indio_dev);
|
||||
struct ad4695_channel_config *cfg = &st->channels_cfg[chan->scan_index];
|
||||
u8 realbits = chan->scan_type.realbits;
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
|
||||
ret = ad4695_read_one_sample(st, chan->address);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (chan->scan_type.sign == 's')
|
||||
*val = sign_extend32(st->raw_data, realbits - 1);
|
||||
else
|
||||
*val = st->raw_data;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
unreachable();
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
*val = st->vref_mv;
|
||||
*val2 = chan->scan_type.realbits;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
case IIO_TEMP:
|
||||
/* T_scale (°C) = raw * V_REF (mV) / (-1.8 mV/°C * 2^16) */
|
||||
*val = st->vref_mv * -556;
|
||||
*val2 = 16;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
if (cfg->pin_pairing == AD4695_IN_PAIR_COM)
|
||||
*val = st->com_mv * (1 << realbits) / st->vref_mv;
|
||||
else if (cfg->pin_pairing == AD4695_IN_PAIR_EVEN_ODD)
|
||||
*val = cfg->common_mode_mv * (1 << realbits) / st->vref_mv;
|
||||
else
|
||||
*val = 0;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_TEMP:
|
||||
/* T_offset (°C) = -725 mV / (-1.8 mV/°C) */
|
||||
/* T_offset (raw) = T_offset (°C) * (-1.8 mV/°C) * 2^16 / V_REF (mV) */
|
||||
*val = -47513600;
|
||||
*val2 = st->vref_mv;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad4695_debugfs_reg_access(struct iio_dev *indio_dev,
|
||||
unsigned int reg,
|
||||
unsigned int writeval,
|
||||
unsigned int *readval)
|
||||
{
|
||||
struct ad4695_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
|
||||
if (readval)
|
||||
return regmap_read(st->regmap, reg, readval);
|
||||
|
||||
return regmap_write(st->regmap, reg, writeval);
|
||||
}
|
||||
|
||||
unreachable();
|
||||
}
|
||||
|
||||
static const struct iio_info ad4695_info = {
|
||||
.read_raw = &ad4695_read_raw,
|
||||
.debugfs_reg_access = &ad4695_debugfs_reg_access,
|
||||
};
|
||||
|
||||
static int ad4695_parse_channel_cfg(struct ad4695_state *st)
|
||||
{
|
||||
struct device *dev = &st->spi->dev;
|
||||
struct ad4695_channel_config *chan_cfg;
|
||||
struct iio_chan_spec *iio_chan;
|
||||
int ret, i;
|
||||
|
||||
/* populate defaults */
|
||||
for (i = 0; i < st->chip_info->num_voltage_inputs; i++) {
|
||||
chan_cfg = &st->channels_cfg[i];
|
||||
iio_chan = &st->iio_chan[i];
|
||||
|
||||
chan_cfg->highz_en = true;
|
||||
chan_cfg->channel = i;
|
||||
|
||||
*iio_chan = ad4695_channel_template;
|
||||
iio_chan->channel = i;
|
||||
iio_chan->scan_index = i;
|
||||
iio_chan->address = AD4695_CMD_VOLTAGE_CHAN(i);
|
||||
}
|
||||
|
||||
/* modify based on firmware description */
|
||||
device_for_each_child_node_scoped(dev, child) {
|
||||
u32 reg, val;
|
||||
|
||||
ret = fwnode_property_read_u32(child, "reg", ®);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to read reg property (%s)\n",
|
||||
fwnode_get_name(child));
|
||||
|
||||
if (reg >= st->chip_info->num_voltage_inputs)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"reg out of range (%s)\n",
|
||||
fwnode_get_name(child));
|
||||
|
||||
iio_chan = &st->iio_chan[reg];
|
||||
chan_cfg = &st->channels_cfg[reg];
|
||||
|
||||
chan_cfg->highz_en =
|
||||
!fwnode_property_read_bool(child, "adi,no-high-z");
|
||||
chan_cfg->bipolar = fwnode_property_read_bool(child, "bipolar");
|
||||
|
||||
ret = fwnode_property_read_u32(child, "common-mode-channel",
|
||||
&val);
|
||||
if (ret && ret != -EINVAL)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to read common-mode-channel (%s)\n",
|
||||
fwnode_get_name(child));
|
||||
|
||||
if (ret == -EINVAL || val == AD4695_COMMON_MODE_REFGND)
|
||||
chan_cfg->pin_pairing = AD4695_IN_PAIR_REFGND;
|
||||
else if (val == AD4695_COMMON_MODE_COM)
|
||||
chan_cfg->pin_pairing = AD4695_IN_PAIR_COM;
|
||||
else
|
||||
chan_cfg->pin_pairing = AD4695_IN_PAIR_EVEN_ODD;
|
||||
|
||||
if (chan_cfg->pin_pairing == AD4695_IN_PAIR_EVEN_ODD &&
|
||||
val % 2 == 0)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"common-mode-channel must be odd number (%s)\n",
|
||||
fwnode_get_name(child));
|
||||
|
||||
if (chan_cfg->pin_pairing == AD4695_IN_PAIR_EVEN_ODD &&
|
||||
val != reg + 1)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"common-mode-channel must be next consecutive channel (%s)\n",
|
||||
fwnode_get_name(child));
|
||||
|
||||
if (chan_cfg->pin_pairing == AD4695_IN_PAIR_EVEN_ODD) {
|
||||
char name[5];
|
||||
|
||||
snprintf(name, sizeof(name), "in%d", reg + 1);
|
||||
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, name);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to get %s voltage (%s)\n",
|
||||
name, fwnode_get_name(child));
|
||||
|
||||
chan_cfg->common_mode_mv = ret / 1000;
|
||||
}
|
||||
|
||||
if (chan_cfg->bipolar &&
|
||||
chan_cfg->pin_pairing == AD4695_IN_PAIR_REFGND)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"bipolar mode is not available for inputs paired with REFGND (%s).\n",
|
||||
fwnode_get_name(child));
|
||||
|
||||
if (chan_cfg->bipolar)
|
||||
iio_chan->scan_type.sign = 's';
|
||||
|
||||
ret = ad4695_write_chn_cfg(st, chan_cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Temperature channel must be next scan index after voltage channels. */
|
||||
st->iio_chan[i] = ad4695_temp_channel_template;
|
||||
st->iio_chan[i].scan_index = i;
|
||||
i++;
|
||||
|
||||
st->iio_chan[i] = ad4695_soft_timestamp_channel_template;
|
||||
st->iio_chan[i].scan_index = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad4695_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct ad4695_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
struct gpio_desc *cnv_gpio;
|
||||
bool use_internal_ldo_supply;
|
||||
bool use_internal_ref_buffer;
|
||||
int ret;
|
||||
|
||||
cnv_gpio = devm_gpiod_get_optional(dev, "cnv", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(cnv_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(cnv_gpio),
|
||||
"Failed to get CNV GPIO\n");
|
||||
|
||||
/* Driver currently requires CNV pin to be connected to SPI CS */
|
||||
if (cnv_gpio)
|
||||
return dev_err_probe(dev, -ENODEV,
|
||||
"CNV GPIO is not supported\n");
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
st->spi = spi;
|
||||
|
||||
st->chip_info = spi_get_device_match_data(spi);
|
||||
if (!st->chip_info)
|
||||
return -EINVAL;
|
||||
|
||||
/* Registers cannot be read at the max allowable speed */
|
||||
spi->max_speed_hz = AD4695_REG_ACCESS_SCLK_HZ;
|
||||
|
||||
st->regmap = devm_regmap_init_spi(spi, &ad4695_regmap_config);
|
||||
if (IS_ERR(st->regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(st->regmap),
|
||||
"Failed to initialize regmap\n");
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(dev,
|
||||
ARRAY_SIZE(ad4695_power_supplies),
|
||||
ad4695_power_supplies);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to enable power supplies\n");
|
||||
|
||||
/* If LDO_IN supply is present, then we are using internal LDO. */
|
||||
ret = devm_regulator_get_enable_optional(dev, "ldo-in");
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to enable LDO_IN supply\n");
|
||||
|
||||
use_internal_ldo_supply = ret == 0;
|
||||
|
||||
if (!use_internal_ldo_supply) {
|
||||
/* Otherwise we need an external VDD supply. */
|
||||
ret = devm_regulator_get_enable(dev, "vdd");
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to enable VDD supply\n");
|
||||
}
|
||||
|
||||
/* If REFIN supply is given, then we are using internal buffer */
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, "refin");
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret, "Failed to get REFIN voltage\n");
|
||||
|
||||
if (ret != -ENODEV) {
|
||||
st->vref_mv = ret / 1000;
|
||||
use_internal_ref_buffer = true;
|
||||
} else {
|
||||
/* Otherwise, we need an external reference. */
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, "ref");
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to get REF voltage\n");
|
||||
|
||||
st->vref_mv = ret / 1000;
|
||||
use_internal_ref_buffer = false;
|
||||
}
|
||||
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, "com");
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret, "Failed to get COM voltage\n");
|
||||
|
||||
st->com_mv = ret == -ENODEV ? 0 : ret / 1000;
|
||||
|
||||
/*
|
||||
* Reset the device using hardware reset if available or fall back to
|
||||
* software reset.
|
||||
*/
|
||||
|
||||
st->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(st->reset_gpio))
|
||||
return PTR_ERR(st->reset_gpio);
|
||||
|
||||
if (st->reset_gpio) {
|
||||
gpiod_set_value(st->reset_gpio, 0);
|
||||
msleep(AD4695_T_WAKEUP_HW_MS);
|
||||
} else {
|
||||
ret = regmap_write(st->regmap, AD4695_REG_SPI_CONFIG_A,
|
||||
AD4695_REG_SPI_CONFIG_A_SW_RST);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
msleep(AD4695_T_WAKEUP_SW_MS);
|
||||
}
|
||||
|
||||
/* Needed for debugfs since it only access registers 1 byte at a time. */
|
||||
ret = regmap_set_bits(st->regmap, AD4695_REG_SPI_CONFIG_C,
|
||||
AD4695_REG_SPI_CONFIG_C_MB_STRICT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable internal LDO if it isn't needed. */
|
||||
ret = regmap_update_bits(st->regmap, AD4695_REG_SETUP,
|
||||
AD4695_REG_SETUP_LDO_EN,
|
||||
FIELD_PREP(AD4695_REG_SETUP_LDO_EN,
|
||||
use_internal_ldo_supply ? 1 : 0));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* configure reference supply */
|
||||
|
||||
if (device_property_present(dev, "adi,no-ref-current-limit")) {
|
||||
ret = regmap_set_bits(st->regmap, AD4695_REG_REF_CTRL,
|
||||
AD4695_REG_REF_CTRL_OV_MODE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (device_property_present(dev, "adi,no-ref-high-z")) {
|
||||
if (use_internal_ref_buffer)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Cannot disable high-Z mode for internal reference buffer\n");
|
||||
|
||||
ret = regmap_clear_bits(st->regmap, AD4695_REG_REF_CTRL,
|
||||
AD4695_REG_REF_CTRL_REFHIZ_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad4695_set_ref_voltage(st, st->vref_mv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (use_internal_ref_buffer) {
|
||||
ret = regmap_set_bits(st->regmap, AD4695_REG_REF_CTRL,
|
||||
AD4695_REG_REF_CTRL_REFBUF_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Give the capacitor some time to charge up. */
|
||||
msleep(AD4695_T_REFBUF_MS);
|
||||
}
|
||||
|
||||
ret = ad4695_parse_channel_cfg(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->name = st->chip_info->name;
|
||||
indio_dev->info = &ad4695_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = st->iio_chan;
|
||||
indio_dev->num_channels = st->chip_info->num_voltage_inputs + 2;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
ad4695_trigger_handler,
|
||||
&ad4695_buffer_setup_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad4695_spi_id_table[] = {
|
||||
{ .name = "ad4695", .driver_data = (kernel_ulong_t)&ad4695_chip_info },
|
||||
{ .name = "ad4696", .driver_data = (kernel_ulong_t)&ad4696_chip_info },
|
||||
{ .name = "ad4697", .driver_data = (kernel_ulong_t)&ad4697_chip_info },
|
||||
{ .name = "ad4698", .driver_data = (kernel_ulong_t)&ad4698_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad4695_spi_id_table);
|
||||
|
||||
static const struct of_device_id ad4695_of_match_table[] = {
|
||||
{ .compatible = "adi,ad4695", .data = &ad4695_chip_info, },
|
||||
{ .compatible = "adi,ad4696", .data = &ad4696_chip_info, },
|
||||
{ .compatible = "adi,ad4697", .data = &ad4697_chip_info, },
|
||||
{ .compatible = "adi,ad4698", .data = &ad4698_chip_info, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad4695_of_match_table);
|
||||
|
||||
static struct spi_driver ad4695_driver = {
|
||||
.driver = {
|
||||
.name = "ad4695",
|
||||
.of_match_table = ad4695_of_match_table,
|
||||
},
|
||||
.probe = ad4695_probe,
|
||||
.id_table = ad4695_spi_id_table,
|
||||
};
|
||||
module_spi_driver(ad4695_driver);
|
||||
|
||||
MODULE_AUTHOR("Ramona Gradinariu <ramona.gradinariu@analog.com>");
|
||||
MODULE_AUTHOR("David Lechner <dlechner@baylibre.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD4695 ADC driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -159,7 +159,7 @@ static int ad7091r_regmap_bus_reg_write(void *context, unsigned int reg,
|
||||
return spi_write(spi, &st->tx_buf, 2);
|
||||
}
|
||||
|
||||
static struct regmap_bus ad7091r8_regmap_bus = {
|
||||
static const struct regmap_bus ad7091r8_regmap_bus = {
|
||||
.reg_read = ad7091r_regmap_bus_reg_read,
|
||||
.reg_write = ad7091r_regmap_bus_reg_write,
|
||||
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
|
||||
|
@ -378,8 +378,7 @@ static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channe
|
||||
cfg->vref_mv = 2500;
|
||||
st->adc_control &= ~AD7124_ADC_CTRL_REF_EN_MSK;
|
||||
st->adc_control |= AD7124_ADC_CTRL_REF_EN(1);
|
||||
return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL,
|
||||
2, st->adc_control);
|
||||
return 0;
|
||||
default:
|
||||
dev_err(&st->sd.spi->dev, "Invalid reference %d\n", refsel);
|
||||
return -EINVAL;
|
||||
@ -397,24 +396,17 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co
|
||||
|
||||
tmp = (cfg->buf_positive << 1) + cfg->buf_negative;
|
||||
val = AD7124_CONFIG_BIPOLAR(cfg->bipolar) | AD7124_CONFIG_REF_SEL(cfg->refsel) |
|
||||
AD7124_CONFIG_IN_BUFF(tmp);
|
||||
AD7124_CONFIG_IN_BUFF(tmp) | AD7124_CONFIG_PGA(cfg->pga_bits);
|
||||
|
||||
ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(cfg->cfg_slot), 2, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tmp = AD7124_FILTER_TYPE_SEL(cfg->filter_type);
|
||||
ret = ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot), AD7124_FILTER_TYPE_MSK,
|
||||
tmp, 3);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot), AD7124_FILTER_FS_MSK,
|
||||
AD7124_FILTER_FS(cfg->odr_sel_bits), 3);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ad7124_spi_write_mask(st, AD7124_CONFIG(cfg->cfg_slot), AD7124_CONFIG_PGA_MSK,
|
||||
AD7124_CONFIG_PGA(cfg->pga_bits), 2);
|
||||
tmp = AD7124_FILTER_TYPE_SEL(cfg->filter_type) |
|
||||
AD7124_FILTER_FS(cfg->odr_sel_bits);
|
||||
return ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot),
|
||||
AD7124_FILTER_TYPE_MSK | AD7124_FILTER_FS_MSK,
|
||||
tmp, 3);
|
||||
}
|
||||
|
||||
static struct ad7124_channel_config *ad7124_pop_config(struct ad7124_state *st)
|
||||
@ -903,9 +895,9 @@ static int ad7124_setup(struct ad7124_state *st)
|
||||
/* Set the power mode */
|
||||
st->adc_control &= ~AD7124_ADC_CTRL_PWR_MSK;
|
||||
st->adc_control |= AD7124_ADC_CTRL_PWR(power_mode);
|
||||
ret = ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st->adc_control &= ~AD7124_ADC_CTRL_MODE_MSK;
|
||||
st->adc_control |= AD7124_ADC_CTRL_MODE(AD_SD_MODE_IDLE);
|
||||
|
||||
mutex_init(&st->cfgs_lock);
|
||||
INIT_KFIFO(st->live_cfgs_fifo);
|
||||
@ -923,6 +915,10 @@ static int ad7124_setup(struct ad7124_state *st)
|
||||
ad7124_set_channel_odr(st, i, 10);
|
||||
}
|
||||
|
||||
ret = ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
@ -201,6 +202,7 @@ struct ad7192_chip_info {
|
||||
struct ad7192_state {
|
||||
const struct ad7192_chip_info *chip_info;
|
||||
struct clk *mclk;
|
||||
struct clk_hw int_clk_hw;
|
||||
u16 int_vref_mv;
|
||||
u32 aincom_mv;
|
||||
u32 fclk;
|
||||
@ -396,25 +398,162 @@ static inline bool ad7192_valid_external_frequency(u32 freq)
|
||||
freq <= AD7192_EXT_FREQ_MHZ_MAX);
|
||||
}
|
||||
|
||||
static int ad7192_clock_select(struct ad7192_state *st)
|
||||
/*
|
||||
* Position 0 of ad7192_clock_names, xtal, corresponds to clock source
|
||||
* configuration AD7192_CLK_EXT_MCLK1_2 and position 1, mclk, corresponds to
|
||||
* AD7192_CLK_EXT_MCLK2
|
||||
*/
|
||||
static const char *const ad7192_clock_names[] = {
|
||||
"xtal",
|
||||
"mclk"
|
||||
};
|
||||
|
||||
static struct ad7192_state *clk_hw_to_ad7192(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct ad7192_state, int_clk_hw);
|
||||
}
|
||||
|
||||
static unsigned long ad7192_clk_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return AD7192_INT_FREQ_MHZ;
|
||||
}
|
||||
|
||||
static int ad7192_clk_output_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct ad7192_state *st = clk_hw_to_ad7192(hw);
|
||||
|
||||
return st->clock_sel == AD7192_CLK_INT_CO;
|
||||
}
|
||||
|
||||
static int ad7192_clk_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct ad7192_state *st = clk_hw_to_ad7192(hw);
|
||||
int ret;
|
||||
|
||||
st->mode &= ~AD7192_MODE_CLKSRC_MASK;
|
||||
st->mode |= AD7192_CLK_INT_CO;
|
||||
|
||||
ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->clock_sel = AD7192_CLK_INT_CO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ad7192_clk_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct ad7192_state *st = clk_hw_to_ad7192(hw);
|
||||
int ret;
|
||||
|
||||
st->mode &= ~AD7192_MODE_CLKSRC_MASK;
|
||||
st->mode |= AD7192_CLK_INT;
|
||||
|
||||
ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
st->clock_sel = AD7192_CLK_INT;
|
||||
}
|
||||
|
||||
static const struct clk_ops ad7192_int_clk_ops = {
|
||||
.recalc_rate = ad7192_clk_recalc_rate,
|
||||
.is_enabled = ad7192_clk_output_is_enabled,
|
||||
.prepare = ad7192_clk_prepare,
|
||||
.unprepare = ad7192_clk_unprepare,
|
||||
};
|
||||
|
||||
static int ad7192_register_clk_provider(struct ad7192_state *st)
|
||||
{
|
||||
struct device *dev = &st->sd.spi->dev;
|
||||
unsigned int clock_sel;
|
||||
struct clk_init_data init = {};
|
||||
int ret;
|
||||
|
||||
clock_sel = AD7192_CLK_INT;
|
||||
if (!IS_ENABLED(CONFIG_COMMON_CLK))
|
||||
return 0;
|
||||
|
||||
/* use internal clock */
|
||||
if (!st->mclk) {
|
||||
if (device_property_read_bool(dev, "adi,int-clock-output-enable"))
|
||||
clock_sel = AD7192_CLK_INT_CO;
|
||||
} else {
|
||||
if (device_property_read_bool(dev, "adi,clock-xtal"))
|
||||
clock_sel = AD7192_CLK_EXT_MCLK1_2;
|
||||
else
|
||||
clock_sel = AD7192_CLK_EXT_MCLK2;
|
||||
if (!device_property_present(dev, "#clock-cells"))
|
||||
return 0;
|
||||
|
||||
init.name = devm_kasprintf(dev, GFP_KERNEL, "%s-clk",
|
||||
fwnode_get_name(dev_fwnode(dev)));
|
||||
if (!init.name)
|
||||
return -ENOMEM;
|
||||
|
||||
init.ops = &ad7192_int_clk_ops;
|
||||
|
||||
st->int_clk_hw.init = &init;
|
||||
ret = devm_clk_hw_register(dev, &st->int_clk_hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
|
||||
&st->int_clk_hw);
|
||||
}
|
||||
|
||||
static int ad7192_clock_setup(struct ad7192_state *st)
|
||||
{
|
||||
struct device *dev = &st->sd.spi->dev;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The following two if branches are kept for backward compatibility but
|
||||
* the use of the two devicetree properties is highly discouraged. Clock
|
||||
* configuration should be done according to the bindings.
|
||||
*/
|
||||
|
||||
if (device_property_read_bool(dev, "adi,int-clock-output-enable")) {
|
||||
st->clock_sel = AD7192_CLK_INT_CO;
|
||||
st->fclk = AD7192_INT_FREQ_MHZ;
|
||||
dev_warn(dev, "Property adi,int-clock-output-enable is deprecated! Check bindings!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return clock_sel;
|
||||
if (device_property_read_bool(dev, "adi,clock-xtal")) {
|
||||
st->clock_sel = AD7192_CLK_EXT_MCLK1_2;
|
||||
st->mclk = devm_clk_get_enabled(dev, "mclk");
|
||||
if (IS_ERR(st->mclk))
|
||||
return dev_err_probe(dev, PTR_ERR(st->mclk),
|
||||
"Failed to get mclk\n");
|
||||
|
||||
st->fclk = clk_get_rate(st->mclk);
|
||||
if (!ad7192_valid_external_frequency(st->fclk))
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"External clock frequency out of bounds\n");
|
||||
|
||||
dev_warn(dev, "Property adi,clock-xtal is deprecated! Check bindings!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = device_property_match_property_string(dev, "clock-names",
|
||||
ad7192_clock_names,
|
||||
ARRAY_SIZE(ad7192_clock_names));
|
||||
if (ret < 0) {
|
||||
st->clock_sel = AD7192_CLK_INT;
|
||||
st->fclk = AD7192_INT_FREQ_MHZ;
|
||||
|
||||
ret = ad7192_register_clk_provider(st);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to register clock provider\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
st->clock_sel = AD7192_CLK_EXT_MCLK1_2 + ret;
|
||||
|
||||
st->mclk = devm_clk_get_enabled(dev, ad7192_clock_names[ret]);
|
||||
if (IS_ERR(st->mclk))
|
||||
return dev_err_probe(dev, PTR_ERR(st->mclk),
|
||||
"Failed to get clock source\n");
|
||||
|
||||
st->fclk = clk_get_rate(st->mclk);
|
||||
if (!ad7192_valid_external_frequency(st->fclk))
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"External clock frequency out of bounds\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev)
|
||||
@ -1275,21 +1414,9 @@ static int ad7192_probe(struct spi_device *spi)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->fclk = AD7192_INT_FREQ_MHZ;
|
||||
|
||||
st->mclk = devm_clk_get_optional_enabled(dev, "mclk");
|
||||
if (IS_ERR(st->mclk))
|
||||
return PTR_ERR(st->mclk);
|
||||
|
||||
st->clock_sel = ad7192_clock_select(st);
|
||||
|
||||
if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 ||
|
||||
st->clock_sel == AD7192_CLK_EXT_MCLK2) {
|
||||
st->fclk = clk_get_rate(st->mclk);
|
||||
if (!ad7192_valid_external_frequency(st->fclk))
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"External clock frequency out of bounds\n");
|
||||
}
|
||||
ret = ad7192_clock_setup(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad7192_setup(indio_dev, dev);
|
||||
if (ret)
|
||||
|
@ -123,7 +123,8 @@ static int ad7266_update_scan_mode(struct iio_dev *indio_dev,
|
||||
const unsigned long *scan_mask)
|
||||
{
|
||||
struct ad7266_state *st = iio_priv(indio_dev);
|
||||
unsigned int nr = find_first_bit(scan_mask, indio_dev->masklength);
|
||||
unsigned int nr = find_first_bit(scan_mask,
|
||||
iio_get_masklength(indio_dev));
|
||||
|
||||
ad7266_select_input(st, nr);
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/crc8.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
@ -803,16 +804,16 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct ad7280_state *st = iio_priv(indio_dev);
|
||||
unsigned int *channels;
|
||||
int i, ret;
|
||||
|
||||
channels = kcalloc(st->scan_cnt, sizeof(*channels), GFP_KERNEL);
|
||||
unsigned int *channels __free(kfree) = kcalloc(st->scan_cnt, sizeof(*channels),
|
||||
GFP_KERNEL);
|
||||
if (!channels)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
ret = ad7280_read_all_channels(st, st->scan_cnt, channels);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return IRQ_HANDLED;
|
||||
|
||||
for (i = 0; i < st->scan_cnt; i++) {
|
||||
unsigned int val;
|
||||
@ -852,9 +853,6 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(channels);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,8 @@ static int ad7298_update_scan_mode(struct iio_dev *indio_dev,
|
||||
int scan_count;
|
||||
|
||||
/* Now compute overall size */
|
||||
scan_count = bitmap_weight(active_scan_mask, indio_dev->masklength);
|
||||
scan_count = bitmap_weight(active_scan_mask,
|
||||
iio_get_masklength(indio_dev));
|
||||
|
||||
command = AD7298_WRITE | st->ext_ref;
|
||||
|
||||
|
@ -8,9 +8,11 @@
|
||||
* Datasheets of supported parts:
|
||||
* ad7380/1 : https://www.analog.com/media/en/technical-documentation/data-sheets/AD7380-7381.pdf
|
||||
* ad7383/4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-7384.pdf
|
||||
* ad7386/7/8 : https://www.analog.com/media/en/technical-documentation/data-sheets/AD7386-7387-7388.pdf
|
||||
* ad7380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7380-4.pdf
|
||||
* ad7381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7381-4.pdf
|
||||
* ad7383/4-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-4-ad7384-4.pdf
|
||||
* ad7386/7/8-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7386-4-7387-4-7388-4.pdf
|
||||
*/
|
||||
|
||||
#include <linux/align.h>
|
||||
@ -31,7 +33,7 @@
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define MAX_NUM_CHANNELS 4
|
||||
#define MAX_NUM_CHANNELS 8
|
||||
/* 2.5V internal reference voltage */
|
||||
#define AD7380_INTERNAL_REF_MV 2500
|
||||
|
||||
@ -49,6 +51,8 @@
|
||||
#define AD7380_REG_ADDR_ALERT_LOW_TH 0x4
|
||||
#define AD7380_REG_ADDR_ALERT_HIGH_TH 0x5
|
||||
|
||||
#define AD7380_CONFIG1_CH BIT(11)
|
||||
#define AD7380_CONFIG1_SEQ BIT(10)
|
||||
#define AD7380_CONFIG1_OS_MODE BIT(9)
|
||||
#define AD7380_CONFIG1_OSR GENMASK(8, 6)
|
||||
#define AD7380_CONFIG1_CRC_W BIT(5)
|
||||
@ -80,6 +84,8 @@ struct ad7380_chip_info {
|
||||
const char *name;
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned int num_channels;
|
||||
unsigned int num_simult_channels;
|
||||
bool has_mux;
|
||||
const char * const *vcm_supplies;
|
||||
unsigned int num_vcm_supplies;
|
||||
const unsigned long *available_scan_masks;
|
||||
@ -91,82 +97,151 @@ enum {
|
||||
AD7380_SCAN_TYPE_RESOLUTION_BOOST,
|
||||
};
|
||||
|
||||
/* Extended scan types for 14-bit chips. */
|
||||
static const struct iio_scan_type ad7380_scan_type_14[] = {
|
||||
/* Extended scan types for 12-bit unsigned chips. */
|
||||
static const struct iio_scan_type ad7380_scan_type_12_u[] = {
|
||||
[AD7380_SCAN_TYPE_NORMAL] = {
|
||||
.sign = 'u',
|
||||
.realbits = 12,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
[AD7380_SCAN_TYPE_RESOLUTION_BOOST] = {
|
||||
.sign = 'u',
|
||||
.realbits = 14,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
};
|
||||
|
||||
/* Extended scan types for 14-bit signed chips. */
|
||||
static const struct iio_scan_type ad7380_scan_type_14_s[] = {
|
||||
[AD7380_SCAN_TYPE_NORMAL] = {
|
||||
.sign = 's',
|
||||
.realbits = 14,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
[AD7380_SCAN_TYPE_RESOLUTION_BOOST] = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
};
|
||||
|
||||
/* Extended scan types for 16-bit chips. */
|
||||
static const struct iio_scan_type ad7380_scan_type_16[] = {
|
||||
/* Extended scan types for 14-bit unsigned chips. */
|
||||
static const struct iio_scan_type ad7380_scan_type_14_u[] = {
|
||||
[AD7380_SCAN_TYPE_NORMAL] = {
|
||||
.sign = 'u',
|
||||
.realbits = 14,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
[AD7380_SCAN_TYPE_RESOLUTION_BOOST] = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
};
|
||||
|
||||
/* Extended scan types for 16-bit signed_chips. */
|
||||
static const struct iio_scan_type ad7380_scan_type_16_s[] = {
|
||||
[AD7380_SCAN_TYPE_NORMAL] = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
[AD7380_SCAN_TYPE_RESOLUTION_BOOST] = {
|
||||
.sign = 's',
|
||||
.realbits = 18,
|
||||
.storagebits = 32,
|
||||
.endianness = IIO_CPU
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
};
|
||||
|
||||
#define AD7380_CHANNEL(index, bits, diff) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
|
||||
.info_mask_shared_by_type_available = \
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
|
||||
.indexed = 1, \
|
||||
.differential = (diff), \
|
||||
.channel = (diff) ? (2 * (index)) : (index), \
|
||||
.channel2 = (diff) ? (2 * (index) + 1) : 0, \
|
||||
.scan_index = (index), \
|
||||
.has_ext_scan_type = 1, \
|
||||
.ext_scan_type = ad7380_scan_type_##bits, \
|
||||
.num_ext_scan_type = ARRAY_SIZE(ad7380_scan_type_##bits),\
|
||||
/* Extended scan types for 16-bit unsigned chips. */
|
||||
static const struct iio_scan_type ad7380_scan_type_16_u[] = {
|
||||
[AD7380_SCAN_TYPE_NORMAL] = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
[AD7380_SCAN_TYPE_RESOLUTION_BOOST] = {
|
||||
.sign = 'u',
|
||||
.realbits = 18,
|
||||
.storagebits = 32,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
};
|
||||
|
||||
#define AD7380_CHANNEL(index, bits, diff, sign) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
|
||||
.info_mask_shared_by_type_available = \
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
|
||||
.indexed = 1, \
|
||||
.differential = (diff), \
|
||||
.channel = (diff) ? (2 * (index)) : (index), \
|
||||
.channel2 = (diff) ? (2 * (index) + 1) : 0, \
|
||||
.scan_index = (index), \
|
||||
.has_ext_scan_type = 1, \
|
||||
.ext_scan_type = ad7380_scan_type_##bits##_##sign, \
|
||||
.num_ext_scan_type = ARRAY_SIZE(ad7380_scan_type_##bits##_##sign), \
|
||||
}
|
||||
|
||||
#define DEFINE_AD7380_2_CHANNEL(name, bits, diff) \
|
||||
#define DEFINE_AD7380_2_CHANNEL(name, bits, diff, sign) \
|
||||
static const struct iio_chan_spec name[] = { \
|
||||
AD7380_CHANNEL(0, bits, diff), \
|
||||
AD7380_CHANNEL(1, bits, diff), \
|
||||
AD7380_CHANNEL(0, bits, diff, sign), \
|
||||
AD7380_CHANNEL(1, bits, diff, sign), \
|
||||
IIO_CHAN_SOFT_TIMESTAMP(2), \
|
||||
}
|
||||
|
||||
#define DEFINE_AD7380_4_CHANNEL(name, bits, diff) \
|
||||
#define DEFINE_AD7380_4_CHANNEL(name, bits, diff, sign) \
|
||||
static const struct iio_chan_spec name[] = { \
|
||||
AD7380_CHANNEL(0, bits, diff), \
|
||||
AD7380_CHANNEL(1, bits, diff), \
|
||||
AD7380_CHANNEL(2, bits, diff), \
|
||||
AD7380_CHANNEL(3, bits, diff), \
|
||||
AD7380_CHANNEL(0, bits, diff, sign), \
|
||||
AD7380_CHANNEL(1, bits, diff, sign), \
|
||||
AD7380_CHANNEL(2, bits, diff, sign), \
|
||||
AD7380_CHANNEL(3, bits, diff, sign), \
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4), \
|
||||
}
|
||||
|
||||
#define DEFINE_AD7380_8_CHANNEL(name, bits, diff, sign) \
|
||||
static const struct iio_chan_spec name[] = { \
|
||||
AD7380_CHANNEL(0, bits, diff, sign), \
|
||||
AD7380_CHANNEL(1, bits, diff, sign), \
|
||||
AD7380_CHANNEL(2, bits, diff, sign), \
|
||||
AD7380_CHANNEL(3, bits, diff, sign), \
|
||||
AD7380_CHANNEL(4, bits, diff, sign), \
|
||||
AD7380_CHANNEL(5, bits, diff, sign), \
|
||||
AD7380_CHANNEL(6, bits, diff, sign), \
|
||||
AD7380_CHANNEL(7, bits, diff, sign), \
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8), \
|
||||
}
|
||||
|
||||
/* fully differential */
|
||||
DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1);
|
||||
DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1);
|
||||
DEFINE_AD7380_4_CHANNEL(ad7380_4_channels, 16, 1);
|
||||
DEFINE_AD7380_4_CHANNEL(ad7381_4_channels, 14, 1);
|
||||
DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1, s);
|
||||
DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1, s);
|
||||
DEFINE_AD7380_4_CHANNEL(ad7380_4_channels, 16, 1, s);
|
||||
DEFINE_AD7380_4_CHANNEL(ad7381_4_channels, 14, 1, s);
|
||||
/* pseudo differential */
|
||||
DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0);
|
||||
DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0);
|
||||
DEFINE_AD7380_4_CHANNEL(ad7383_4_channels, 16, 0);
|
||||
DEFINE_AD7380_4_CHANNEL(ad7384_4_channels, 14, 0);
|
||||
DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0, s);
|
||||
DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0, s);
|
||||
DEFINE_AD7380_4_CHANNEL(ad7383_4_channels, 16, 0, s);
|
||||
DEFINE_AD7380_4_CHANNEL(ad7384_4_channels, 14, 0, s);
|
||||
|
||||
/* Single ended */
|
||||
DEFINE_AD7380_4_CHANNEL(ad7386_channels, 16, 0, u);
|
||||
DEFINE_AD7380_4_CHANNEL(ad7387_channels, 14, 0, u);
|
||||
DEFINE_AD7380_4_CHANNEL(ad7388_channels, 12, 0, u);
|
||||
DEFINE_AD7380_8_CHANNEL(ad7386_4_channels, 16, 0, u);
|
||||
DEFINE_AD7380_8_CHANNEL(ad7387_4_channels, 14, 0, u);
|
||||
DEFINE_AD7380_8_CHANNEL(ad7388_4_channels, 12, 0, u);
|
||||
|
||||
static const char * const ad7380_2_channel_vcm_supplies[] = {
|
||||
"aina", "ainb",
|
||||
@ -187,6 +262,60 @@ static const unsigned long ad7380_4_channel_scan_masks[] = {
|
||||
0
|
||||
};
|
||||
|
||||
/*
|
||||
* Single ended parts have a 2:1 multiplexer in front of each ADC.
|
||||
*
|
||||
* From an IIO point of view, all inputs are exported, i.e ad7386/7/8
|
||||
* export 4 channels and ad7386-4/7-4/8-4 export 8 channels.
|
||||
*
|
||||
* Inputs AinX0 of multiplexers correspond to the first half of IIO channels
|
||||
* (i.e 0-1 or 0-3) and inputs AinX1 correspond to second half (i.e 2-3 or
|
||||
* 4-7). Example for AD7386/7/8 (2 channels parts):
|
||||
*
|
||||
* IIO | AD7386/7/8
|
||||
* | +----------------------------
|
||||
* | | _____ ______
|
||||
* | | | | | |
|
||||
* voltage0 | AinA0 --|--->| | | |
|
||||
* | | | mux |----->| ADCA |---
|
||||
* voltage2 | AinA1 --|--->| | | |
|
||||
* | | |_____| |_____ |
|
||||
* | | _____ ______
|
||||
* | | | | | |
|
||||
* voltage1 | AinB0 --|--->| | | |
|
||||
* | | | mux |----->| ADCB |---
|
||||
* voltage3 | AinB1 --|--->| | | |
|
||||
* | | |_____| |______|
|
||||
* | |
|
||||
* | +----------------------------
|
||||
*
|
||||
* Since this is simultaneous sampling for AinX0 OR AinX1 we have two separate
|
||||
* scan masks.
|
||||
* When sequencer mode is enabled, chip automatically cycles through
|
||||
* AinX0 and AinX1 channels. From an IIO point of view, we ca enable all
|
||||
* channels, at the cost of an extra read, thus dividing the maximum rate by
|
||||
* two.
|
||||
*/
|
||||
enum {
|
||||
AD7380_SCAN_MASK_CH_0,
|
||||
AD7380_SCAN_MASK_CH_1,
|
||||
AD7380_SCAN_MASK_SEQ,
|
||||
};
|
||||
|
||||
static const unsigned long ad7380_2x2_channel_scan_masks[] = {
|
||||
[AD7380_SCAN_MASK_CH_0] = GENMASK(1, 0),
|
||||
[AD7380_SCAN_MASK_CH_1] = GENMASK(3, 2),
|
||||
[AD7380_SCAN_MASK_SEQ] = GENMASK(3, 0),
|
||||
0
|
||||
};
|
||||
|
||||
static const unsigned long ad7380_2x4_channel_scan_masks[] = {
|
||||
[AD7380_SCAN_MASK_CH_0] = GENMASK(3, 0),
|
||||
[AD7380_SCAN_MASK_CH_1] = GENMASK(7, 4),
|
||||
[AD7380_SCAN_MASK_SEQ] = GENMASK(7, 0),
|
||||
0
|
||||
};
|
||||
|
||||
static const struct ad7380_timing_specs ad7380_timing = {
|
||||
.t_csh_ns = 10,
|
||||
};
|
||||
@ -208,6 +337,7 @@ static const struct ad7380_chip_info ad7380_chip_info = {
|
||||
.name = "ad7380",
|
||||
.channels = ad7380_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7380_channels),
|
||||
.num_simult_channels = 2,
|
||||
.available_scan_masks = ad7380_2_channel_scan_masks,
|
||||
.timing_specs = &ad7380_timing,
|
||||
};
|
||||
@ -216,6 +346,7 @@ static const struct ad7380_chip_info ad7381_chip_info = {
|
||||
.name = "ad7381",
|
||||
.channels = ad7381_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7381_channels),
|
||||
.num_simult_channels = 2,
|
||||
.available_scan_masks = ad7380_2_channel_scan_masks,
|
||||
.timing_specs = &ad7380_timing,
|
||||
};
|
||||
@ -224,6 +355,7 @@ static const struct ad7380_chip_info ad7383_chip_info = {
|
||||
.name = "ad7383",
|
||||
.channels = ad7383_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7383_channels),
|
||||
.num_simult_channels = 2,
|
||||
.vcm_supplies = ad7380_2_channel_vcm_supplies,
|
||||
.num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
|
||||
.available_scan_masks = ad7380_2_channel_scan_masks,
|
||||
@ -234,16 +366,48 @@ static const struct ad7380_chip_info ad7384_chip_info = {
|
||||
.name = "ad7384",
|
||||
.channels = ad7384_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7384_channels),
|
||||
.num_simult_channels = 2,
|
||||
.vcm_supplies = ad7380_2_channel_vcm_supplies,
|
||||
.num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
|
||||
.available_scan_masks = ad7380_2_channel_scan_masks,
|
||||
.timing_specs = &ad7380_timing,
|
||||
};
|
||||
|
||||
static const struct ad7380_chip_info ad7386_chip_info = {
|
||||
.name = "ad7386",
|
||||
.channels = ad7386_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7386_channels),
|
||||
.num_simult_channels = 2,
|
||||
.has_mux = true,
|
||||
.available_scan_masks = ad7380_2x2_channel_scan_masks,
|
||||
.timing_specs = &ad7380_timing,
|
||||
};
|
||||
|
||||
static const struct ad7380_chip_info ad7387_chip_info = {
|
||||
.name = "ad7387",
|
||||
.channels = ad7387_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7387_channels),
|
||||
.num_simult_channels = 2,
|
||||
.has_mux = true,
|
||||
.available_scan_masks = ad7380_2x2_channel_scan_masks,
|
||||
.timing_specs = &ad7380_timing,
|
||||
};
|
||||
|
||||
static const struct ad7380_chip_info ad7388_chip_info = {
|
||||
.name = "ad7388",
|
||||
.channels = ad7388_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7388_channels),
|
||||
.num_simult_channels = 2,
|
||||
.has_mux = true,
|
||||
.available_scan_masks = ad7380_2x2_channel_scan_masks,
|
||||
.timing_specs = &ad7380_timing,
|
||||
};
|
||||
|
||||
static const struct ad7380_chip_info ad7380_4_chip_info = {
|
||||
.name = "ad7380-4",
|
||||
.channels = ad7380_4_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7380_4_channels),
|
||||
.num_simult_channels = 4,
|
||||
.available_scan_masks = ad7380_4_channel_scan_masks,
|
||||
.timing_specs = &ad7380_4_timing,
|
||||
};
|
||||
@ -252,6 +416,7 @@ static const struct ad7380_chip_info ad7381_4_chip_info = {
|
||||
.name = "ad7381-4",
|
||||
.channels = ad7381_4_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7381_4_channels),
|
||||
.num_simult_channels = 4,
|
||||
.available_scan_masks = ad7380_4_channel_scan_masks,
|
||||
.timing_specs = &ad7380_4_timing,
|
||||
};
|
||||
@ -260,6 +425,7 @@ static const struct ad7380_chip_info ad7383_4_chip_info = {
|
||||
.name = "ad7383-4",
|
||||
.channels = ad7383_4_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7383_4_channels),
|
||||
.num_simult_channels = 4,
|
||||
.vcm_supplies = ad7380_4_channel_vcm_supplies,
|
||||
.num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
|
||||
.available_scan_masks = ad7380_4_channel_scan_masks,
|
||||
@ -270,23 +436,58 @@ static const struct ad7380_chip_info ad7384_4_chip_info = {
|
||||
.name = "ad7384-4",
|
||||
.channels = ad7384_4_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7384_4_channels),
|
||||
.num_simult_channels = 4,
|
||||
.vcm_supplies = ad7380_4_channel_vcm_supplies,
|
||||
.num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
|
||||
.available_scan_masks = ad7380_4_channel_scan_masks,
|
||||
.timing_specs = &ad7380_4_timing,
|
||||
};
|
||||
|
||||
static const struct ad7380_chip_info ad7386_4_chip_info = {
|
||||
.name = "ad7386-4",
|
||||
.channels = ad7386_4_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7386_4_channels),
|
||||
.num_simult_channels = 4,
|
||||
.has_mux = true,
|
||||
.available_scan_masks = ad7380_2x4_channel_scan_masks,
|
||||
.timing_specs = &ad7380_4_timing,
|
||||
};
|
||||
|
||||
static const struct ad7380_chip_info ad7387_4_chip_info = {
|
||||
.name = "ad7387-4",
|
||||
.channels = ad7387_4_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7387_4_channels),
|
||||
.num_simult_channels = 4,
|
||||
.has_mux = true,
|
||||
.available_scan_masks = ad7380_2x4_channel_scan_masks,
|
||||
.timing_specs = &ad7380_4_timing,
|
||||
};
|
||||
|
||||
static const struct ad7380_chip_info ad7388_4_chip_info = {
|
||||
.name = "ad7388-4",
|
||||
.channels = ad7388_4_channels,
|
||||
.num_channels = ARRAY_SIZE(ad7388_4_channels),
|
||||
.num_simult_channels = 4,
|
||||
.has_mux = true,
|
||||
.available_scan_masks = ad7380_2x4_channel_scan_masks,
|
||||
.timing_specs = &ad7380_4_timing,
|
||||
};
|
||||
|
||||
struct ad7380_state {
|
||||
const struct ad7380_chip_info *chip_info;
|
||||
struct spi_device *spi;
|
||||
struct regmap *regmap;
|
||||
unsigned int oversampling_ratio;
|
||||
bool resolution_boost_enabled;
|
||||
unsigned int ch;
|
||||
bool seq;
|
||||
unsigned int vref_mv;
|
||||
unsigned int vcm_mv[MAX_NUM_CHANNELS];
|
||||
/* xfers, message an buffer for reading sample data */
|
||||
struct spi_transfer xfer[2];
|
||||
struct spi_message msg;
|
||||
struct spi_transfer normal_xfer[2];
|
||||
struct spi_message normal_msg;
|
||||
struct spi_transfer seq_xfer[4];
|
||||
struct spi_message seq_msg;
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires the transfer buffers
|
||||
* to live in their own cache lines.
|
||||
@ -379,6 +580,43 @@ static int ad7380_debugfs_reg_access(struct iio_dev *indio_dev, u32 reg,
|
||||
unreachable();
|
||||
}
|
||||
|
||||
/*
|
||||
* When switching channel, the ADC require an additional settling time.
|
||||
* According to the datasheet, data is value on the third CS low. We already
|
||||
* have an extra toggle before each read (either direct reads or buffered reads)
|
||||
* to sample correct data, so we just add a single CS toggle at the end of the
|
||||
* register write.
|
||||
*/
|
||||
static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch)
|
||||
{
|
||||
struct spi_transfer xfer = {
|
||||
.delay = {
|
||||
.value = T_CONVERT_NS,
|
||||
.unit = SPI_DELAY_UNIT_NSECS,
|
||||
}
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (st->ch == ch)
|
||||
return 0;
|
||||
|
||||
ret = regmap_update_bits(st->regmap,
|
||||
AD7380_REG_ADDR_CONFIG1,
|
||||
AD7380_CONFIG1_CH,
|
||||
FIELD_PREP(AD7380_CONFIG1_CH, ch));
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->ch = ch;
|
||||
|
||||
if (st->oversampling_ratio > 1)
|
||||
xfer.delay.value = T_CONVERT_0_NS +
|
||||
T_CONVERT_X_NS * (st->oversampling_ratio - 1);
|
||||
|
||||
return spi_sync_transfer(st->spi, &xfer, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* ad7380_update_xfers - update the SPI transfers base on the current scan type
|
||||
* @st: device instance specific state
|
||||
@ -387,33 +625,47 @@ static int ad7380_debugfs_reg_access(struct iio_dev *indio_dev, u32 reg,
|
||||
static void ad7380_update_xfers(struct ad7380_state *st,
|
||||
const struct iio_scan_type *scan_type)
|
||||
{
|
||||
struct spi_transfer *xfer = st->seq ? st->seq_xfer : st->normal_xfer;
|
||||
unsigned int t_convert = T_CONVERT_NS;
|
||||
|
||||
/*
|
||||
* First xfer only triggers conversion and has to be long enough for
|
||||
* all conversions to complete, which can be multiple conversion in the
|
||||
* case of oversampling. Technically T_CONVERT_X_NS is lower for some
|
||||
* chips, but we use the maximum value for simplicity for now.
|
||||
* In the case of oversampling, conversion time is higher than in normal
|
||||
* mode. Technically T_CONVERT_X_NS is lower for some chips, but we use
|
||||
* the maximum value for simplicity for now.
|
||||
*/
|
||||
if (st->oversampling_ratio > 1)
|
||||
st->xfer[0].delay.value = T_CONVERT_0_NS + T_CONVERT_X_NS *
|
||||
(st->oversampling_ratio - 1);
|
||||
else
|
||||
st->xfer[0].delay.value = T_CONVERT_NS;
|
||||
t_convert = T_CONVERT_0_NS + T_CONVERT_X_NS *
|
||||
(st->oversampling_ratio - 1);
|
||||
|
||||
st->xfer[0].delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
|
||||
/*
|
||||
* Second xfer reads all channels. Data size depends on if resolution
|
||||
* boost is enabled or not.
|
||||
*/
|
||||
st->xfer[1].bits_per_word = scan_type->realbits;
|
||||
st->xfer[1].len = BITS_TO_BYTES(scan_type->storagebits) *
|
||||
(st->chip_info->num_channels - 1);
|
||||
if (st->seq) {
|
||||
xfer[0].delay.value = xfer[1].delay.value = t_convert;
|
||||
xfer[0].delay.unit = xfer[1].delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
xfer[2].bits_per_word = xfer[3].bits_per_word =
|
||||
scan_type->realbits;
|
||||
xfer[2].len = xfer[3].len =
|
||||
BITS_TO_BYTES(scan_type->storagebits) *
|
||||
st->chip_info->num_simult_channels;
|
||||
xfer[3].rx_buf = xfer[2].rx_buf + xfer[2].len;
|
||||
/* Additional delay required here when oversampling is enabled */
|
||||
if (st->oversampling_ratio > 1)
|
||||
xfer[2].delay.value = t_convert;
|
||||
else
|
||||
xfer[2].delay.value = 0;
|
||||
xfer[2].delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
} else {
|
||||
xfer[0].delay.value = t_convert;
|
||||
xfer[0].delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
xfer[1].bits_per_word = scan_type->realbits;
|
||||
xfer[1].len = BITS_TO_BYTES(scan_type->storagebits) *
|
||||
st->chip_info->num_simult_channels;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad7380_triggered_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad7380_state *st = iio_priv(indio_dev);
|
||||
const struct iio_scan_type *scan_type;
|
||||
struct spi_message *msg = &st->normal_msg;
|
||||
|
||||
/*
|
||||
* Currently, we always read all channels at the same time. The scan_type
|
||||
@ -423,16 +675,63 @@ static int ad7380_triggered_buffer_preenable(struct iio_dev *indio_dev)
|
||||
if (IS_ERR(scan_type))
|
||||
return PTR_ERR(scan_type);
|
||||
|
||||
if (st->chip_info->has_mux) {
|
||||
unsigned int index;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Depending on the requested scan_mask and current state,
|
||||
* we need to either change CH bit, or enable sequencer mode
|
||||
* to sample correct data.
|
||||
* Sequencer mode is enabled if active mask corresponds to all
|
||||
* IIO channels enabled. Otherwise, CH bit is set.
|
||||
*/
|
||||
ret = iio_active_scan_mask_index(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
index = ret;
|
||||
if (index == AD7380_SCAN_MASK_SEQ) {
|
||||
ret = regmap_update_bits(st->regmap,
|
||||
AD7380_REG_ADDR_CONFIG1,
|
||||
AD7380_CONFIG1_SEQ,
|
||||
FIELD_PREP(AD7380_CONFIG1_SEQ, 1));
|
||||
if (ret)
|
||||
return ret;
|
||||
msg = &st->seq_msg;
|
||||
st->seq = true;
|
||||
} else {
|
||||
ret = ad7380_set_ch(st, index);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ad7380_update_xfers(st, scan_type);
|
||||
|
||||
return spi_optimize_message(st->spi, &st->msg);
|
||||
return spi_optimize_message(st->spi, msg);
|
||||
}
|
||||
|
||||
static int ad7380_triggered_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad7380_state *st = iio_priv(indio_dev);
|
||||
struct spi_message *msg = &st->normal_msg;
|
||||
int ret;
|
||||
|
||||
spi_unoptimize_message(&st->msg);
|
||||
if (st->seq) {
|
||||
ret = regmap_update_bits(st->regmap,
|
||||
AD7380_REG_ADDR_CONFIG1,
|
||||
AD7380_CONFIG1_SEQ,
|
||||
FIELD_PREP(AD7380_CONFIG1_SEQ, 0));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
msg = &st->seq_msg;
|
||||
st->seq = false;
|
||||
}
|
||||
|
||||
spi_unoptimize_message(msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -447,9 +746,10 @@ static irqreturn_t ad7380_trigger_handler(int irq, void *p)
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct ad7380_state *st = iio_priv(indio_dev);
|
||||
struct spi_message *msg = st->seq ? &st->seq_msg : &st->normal_msg;
|
||||
int ret;
|
||||
|
||||
ret = spi_sync(st->spi, &st->msg);
|
||||
ret = spi_sync(st->spi, msg);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@ -465,20 +765,43 @@ out:
|
||||
static int ad7380_read_direct(struct ad7380_state *st, unsigned int scan_index,
|
||||
const struct iio_scan_type *scan_type, int *val)
|
||||
{
|
||||
unsigned int index = scan_index;
|
||||
int ret;
|
||||
|
||||
if (st->chip_info->has_mux) {
|
||||
unsigned int ch = 0;
|
||||
|
||||
if (index >= st->chip_info->num_simult_channels) {
|
||||
index -= st->chip_info->num_simult_channels;
|
||||
ch = 1;
|
||||
}
|
||||
|
||||
ret = ad7380_set_ch(st, ch);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ad7380_update_xfers(st, scan_type);
|
||||
|
||||
ret = spi_sync(st->spi, &st->msg);
|
||||
ret = spi_sync(st->spi, &st->normal_msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (scan_type->storagebits > 16)
|
||||
*val = sign_extend32(*(u32 *)(st->scan_data + 4 * scan_index),
|
||||
scan_type->realbits - 1);
|
||||
else
|
||||
*val = sign_extend32(*(u16 *)(st->scan_data + 2 * scan_index),
|
||||
scan_type->realbits - 1);
|
||||
if (scan_type->storagebits > 16) {
|
||||
if (scan_type->sign == 's')
|
||||
*val = sign_extend32(*(u32 *)(st->scan_data + 4 * index),
|
||||
scan_type->realbits - 1);
|
||||
else
|
||||
*val = *(u32 *)(st->scan_data + 4 * index) &
|
||||
GENMASK(scan_type->realbits - 1, 0);
|
||||
} else {
|
||||
if (scan_type->sign == 's')
|
||||
*val = sign_extend32(*(u16 *)(st->scan_data + 2 * index),
|
||||
scan_type->realbits - 1);
|
||||
else
|
||||
*val = *(u16 *)(st->scan_data + 2 * index) &
|
||||
GENMASK(scan_type->realbits - 1, 0);
|
||||
}
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
@ -655,6 +978,8 @@ static int ad7380_init(struct ad7380_state *st, struct regulator *vref)
|
||||
|
||||
/* This is the default value after reset. */
|
||||
st->oversampling_ratio = 1;
|
||||
st->ch = 0;
|
||||
st->seq = false;
|
||||
|
||||
/* SPI 1-wire mode */
|
||||
return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
|
||||
@ -756,21 +1081,45 @@ static int ad7380_probe(struct spi_device *spi)
|
||||
"failed to allocate register map\n");
|
||||
|
||||
/*
|
||||
* Setting up a low latency read for getting sample data. Used for both
|
||||
* direct read an triggered buffer. Additional fields will be set up in
|
||||
* ad7380_update_xfers() based on the current state of the driver at the
|
||||
* time of the read.
|
||||
* Setting up xfer structures for both normal and sequence mode. These
|
||||
* struct are used for both direct read and triggered buffer. Additional
|
||||
* fields will be set up in ad7380_update_xfers() based on the current
|
||||
* state of the driver at the time of the read.
|
||||
*/
|
||||
|
||||
/* toggle CS (no data xfer) to trigger a conversion */
|
||||
st->xfer[0].cs_change = 1;
|
||||
st->xfer[0].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
|
||||
st->xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
/*
|
||||
* In normal mode a read is composed of two steps:
|
||||
* - first, toggle CS (no data xfer) to trigger a conversion
|
||||
* - then, read data
|
||||
*/
|
||||
st->normal_xfer[0].cs_change = 1;
|
||||
st->normal_xfer[0].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
|
||||
st->normal_xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
st->normal_xfer[1].rx_buf = st->scan_data;
|
||||
|
||||
/* then do a second xfer to read the data */
|
||||
st->xfer[1].rx_buf = st->scan_data;
|
||||
spi_message_init_with_transfers(&st->normal_msg, st->normal_xfer,
|
||||
ARRAY_SIZE(st->normal_xfer));
|
||||
/*
|
||||
* In sequencer mode a read is composed of four steps:
|
||||
* - CS toggle (no data xfer) to get the right point in the sequence
|
||||
* - CS toggle (no data xfer) to trigger a conversion of AinX0 and
|
||||
* acquisition of AinX1
|
||||
* - 2 data reads, to read AinX0 and AinX1
|
||||
*/
|
||||
st->seq_xfer[0].cs_change = 1;
|
||||
st->seq_xfer[0].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
|
||||
st->seq_xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
st->seq_xfer[1].cs_change = 1;
|
||||
st->seq_xfer[1].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
|
||||
st->seq_xfer[1].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
|
||||
spi_message_init_with_transfers(&st->msg, st->xfer, ARRAY_SIZE(st->xfer));
|
||||
st->seq_xfer[2].rx_buf = st->scan_data;
|
||||
st->seq_xfer[2].cs_change = 1;
|
||||
st->seq_xfer[2].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
|
||||
st->seq_xfer[2].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
|
||||
spi_message_init_with_transfers(&st->seq_msg, st->seq_xfer,
|
||||
ARRAY_SIZE(st->seq_xfer));
|
||||
|
||||
indio_dev->channels = st->chip_info->channels;
|
||||
indio_dev->num_channels = st->chip_info->num_channels;
|
||||
@ -798,10 +1147,16 @@ static const struct of_device_id ad7380_of_match_table[] = {
|
||||
{ .compatible = "adi,ad7381", .data = &ad7381_chip_info },
|
||||
{ .compatible = "adi,ad7383", .data = &ad7383_chip_info },
|
||||
{ .compatible = "adi,ad7384", .data = &ad7384_chip_info },
|
||||
{ .compatible = "adi,ad7386", .data = &ad7386_chip_info },
|
||||
{ .compatible = "adi,ad7387", .data = &ad7387_chip_info },
|
||||
{ .compatible = "adi,ad7388", .data = &ad7388_chip_info },
|
||||
{ .compatible = "adi,ad7380-4", .data = &ad7380_4_chip_info },
|
||||
{ .compatible = "adi,ad7381-4", .data = &ad7381_4_chip_info },
|
||||
{ .compatible = "adi,ad7383-4", .data = &ad7383_4_chip_info },
|
||||
{ .compatible = "adi,ad7384-4", .data = &ad7384_4_chip_info },
|
||||
{ .compatible = "adi,ad7386-4", .data = &ad7386_4_chip_info },
|
||||
{ .compatible = "adi,ad7387-4", .data = &ad7387_4_chip_info },
|
||||
{ .compatible = "adi,ad7388-4", .data = &ad7388_4_chip_info },
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -810,10 +1165,16 @@ static const struct spi_device_id ad7380_id_table[] = {
|
||||
{ "ad7381", (kernel_ulong_t)&ad7381_chip_info },
|
||||
{ "ad7383", (kernel_ulong_t)&ad7383_chip_info },
|
||||
{ "ad7384", (kernel_ulong_t)&ad7384_chip_info },
|
||||
{ "ad7386", (kernel_ulong_t)&ad7386_chip_info },
|
||||
{ "ad7387", (kernel_ulong_t)&ad7387_chip_info },
|
||||
{ "ad7388", (kernel_ulong_t)&ad7388_chip_info },
|
||||
{ "ad7380-4", (kernel_ulong_t)&ad7380_4_chip_info },
|
||||
{ "ad7381-4", (kernel_ulong_t)&ad7381_4_chip_info },
|
||||
{ "ad7383-4", (kernel_ulong_t)&ad7383_4_chip_info },
|
||||
{ "ad7384-4", (kernel_ulong_t)&ad7384_4_chip_info },
|
||||
{ "ad7386-4", (kernel_ulong_t)&ad7386_4_chip_info },
|
||||
{ "ad7387-4", (kernel_ulong_t)&ad7387_4_chip_info },
|
||||
{ "ad7388-4", (kernel_ulong_t)&ad7388_4_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7380_id_table);
|
||||
|
@ -69,19 +69,17 @@ static int ad7606_reg_access(struct iio_dev *indio_dev,
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
if (readval) {
|
||||
ret = st->bops->reg_read(st, reg);
|
||||
if (ret < 0)
|
||||
goto err_unlock;
|
||||
return ret;
|
||||
*readval = ret;
|
||||
ret = 0;
|
||||
return 0;
|
||||
} else {
|
||||
ret = st->bops->reg_write(st, reg, writeval);
|
||||
return st->bops->reg_write(st, reg, writeval);
|
||||
}
|
||||
err_unlock:
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7606_read_samples(struct ad7606_state *st)
|
||||
@ -124,19 +122,19 @@ static irqreturn_t ad7606_trigger_handler(int irq, void *p)
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
ret = ad7606_read_samples(st);
|
||||
if (ret == 0)
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->data,
|
||||
iio_get_time_ns(indio_dev));
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->data,
|
||||
iio_get_time_ns(indio_dev));
|
||||
error_ret:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
/* The rising edge of the CONVST signal starts a new conversion. */
|
||||
gpiod_set_value(st->gpio_convst, 1);
|
||||
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -236,9 +234,9 @@ static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val)
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
DECLARE_BITMAP(values, 3);
|
||||
|
||||
values[0] = val;
|
||||
values[0] = val & GENMASK(2, 0);
|
||||
|
||||
gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc,
|
||||
gpiod_set_array_value(st->gpio_os->ndescs, st->gpio_os->desc,
|
||||
st->gpio_os->info, values);
|
||||
|
||||
/* AD7616 requires a reset to update value */
|
||||
@ -257,19 +255,17 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
int i, ret, ch = 0;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
mutex_lock(&st->lock);
|
||||
i = find_closest(val2, st->scale_avail, st->num_scales);
|
||||
if (st->sw_mode_en)
|
||||
ch = chan->address;
|
||||
ret = st->write_scale(indio_dev, ch, i);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&st->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
st->range[ch] = i;
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return 0;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
@ -277,14 +273,9 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
|
||||
return -EINVAL;
|
||||
i = find_closest(val, st->oversampling_avail,
|
||||
st->num_os_ratios);
|
||||
mutex_lock(&st->lock);
|
||||
ret = st->write_os(indio_dev, i);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&st->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
st->oversampling = st->oversampling_avail[i];
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return 0;
|
||||
default:
|
||||
@ -443,7 +434,7 @@ static int ad7606_request_gpios(struct ad7606_state *st)
|
||||
return PTR_ERR(st->gpio_range);
|
||||
|
||||
st->gpio_standby = devm_gpiod_get_optional(dev, "standby",
|
||||
GPIOD_OUT_HIGH);
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->gpio_standby))
|
||||
return PTR_ERR(st->gpio_standby);
|
||||
|
||||
@ -686,7 +677,7 @@ static int ad7606_suspend(struct device *dev)
|
||||
|
||||
if (st->gpio_standby) {
|
||||
gpiod_set_value(st->gpio_range, 1);
|
||||
gpiod_set_value(st->gpio_standby, 0);
|
||||
gpiod_set_value(st->gpio_standby, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -249,8 +249,9 @@ static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
|
||||
static int ad7606B_sw_mode_config(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
unsigned long os[3] = {1};
|
||||
DECLARE_BITMAP(os, 3);
|
||||
|
||||
bitmap_fill(os, 3);
|
||||
/*
|
||||
* Software mode is enabled when all three oversampling
|
||||
* pins are set to high. If oversampling gpios are defined
|
||||
@ -258,7 +259,7 @@ static int ad7606B_sw_mode_config(struct iio_dev *indio_dev)
|
||||
* otherwise, they must be hardwired to VDD
|
||||
*/
|
||||
if (st->gpio_os) {
|
||||
gpiod_set_array_value(ARRAY_SIZE(os),
|
||||
gpiod_set_array_value(st->gpio_os->ndescs,
|
||||
st->gpio_os->desc, st->gpio_os->info, os);
|
||||
}
|
||||
/* OS of 128 and 256 are available only in software mode */
|
||||
|
@ -544,13 +544,10 @@ static int ad7768_set_channel_label(struct iio_dev *indio_dev,
|
||||
{
|
||||
struct ad7768_state *st = iio_priv(indio_dev);
|
||||
struct device *device = indio_dev->dev.parent;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct fwnode_handle *child;
|
||||
const char *label;
|
||||
int crt_ch = 0;
|
||||
|
||||
fwnode = dev_fwnode(device);
|
||||
fwnode_for_each_child_node(fwnode, child) {
|
||||
device_for_each_child_node_scoped(device, child) {
|
||||
if (fwnode_property_read_u32(child, "reg", &crt_ch))
|
||||
continue;
|
||||
|
||||
|
@ -237,7 +237,8 @@ static int ad799x_update_scan_mode(struct iio_dev *indio_dev,
|
||||
if (!st->rx_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2;
|
||||
st->transfer_size = bitmap_weight(scan_mask,
|
||||
iio_get_masklength(indio_dev)) * 2;
|
||||
|
||||
switch (st->id) {
|
||||
case ad7992:
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
@ -104,7 +105,30 @@
|
||||
#define AD9467_DEF_OUTPUT_MODE 0x08
|
||||
#define AD9467_REG_VREF_MASK 0x0F
|
||||
|
||||
/*
|
||||
* Analog Devices AD9643 14-Bit, 170/210/250 MSPS ADC
|
||||
*/
|
||||
|
||||
#define CHIPID_AD9643 0x82
|
||||
#define AD9643_REG_VREF_MASK 0x1F
|
||||
|
||||
/*
|
||||
* Analog Devices AD9652 16-bit 310 MSPS ADC
|
||||
*/
|
||||
|
||||
#define CHIPID_AD9652 0xC1
|
||||
#define AD9652_REG_VREF_MASK 0xC0
|
||||
|
||||
/*
|
||||
* Analog Devices AD9649 14-bit 20/40/65/80 MSPS ADC
|
||||
*/
|
||||
|
||||
#define CHIPID_AD9649 0x6F
|
||||
#define AD9649_TEST_POINTS 8
|
||||
|
||||
#define AD9647_MAX_TEST_POINTS 32
|
||||
#define AD9467_CAN_INVERT(st) \
|
||||
(!(st)->info->has_dco || (st)->info->has_dco_invert)
|
||||
|
||||
struct ad9467_chip_info {
|
||||
const char *name;
|
||||
@ -113,12 +137,23 @@ struct ad9467_chip_info {
|
||||
unsigned int num_channels;
|
||||
const unsigned int (*scale_table)[2];
|
||||
int num_scales;
|
||||
unsigned long test_mask;
|
||||
unsigned int test_mask_len;
|
||||
unsigned long max_rate;
|
||||
unsigned int default_output_mode;
|
||||
unsigned int vref_mask;
|
||||
unsigned int num_lanes;
|
||||
unsigned int dco_en;
|
||||
unsigned int test_points;
|
||||
/* data clock output */
|
||||
bool has_dco;
|
||||
bool has_dco_invert;
|
||||
};
|
||||
|
||||
struct ad9467_chan_test_mode {
|
||||
struct ad9467_state *st;
|
||||
unsigned int idx;
|
||||
u8 mode;
|
||||
};
|
||||
|
||||
struct ad9467_state {
|
||||
@ -126,6 +161,8 @@ struct ad9467_state {
|
||||
struct iio_backend *back;
|
||||
struct spi_device *spi;
|
||||
struct clk *clk;
|
||||
/* used for debugfs */
|
||||
struct ad9467_chan_test_mode *chan_test;
|
||||
unsigned int output_mode;
|
||||
unsigned int (*scales)[2];
|
||||
/*
|
||||
@ -138,6 +175,8 @@ struct ad9467_state {
|
||||
* at the io delay control section.
|
||||
*/
|
||||
DECLARE_BITMAP(calib_map, AD9647_MAX_TEST_POINTS * 2);
|
||||
/* number of bits of the map */
|
||||
unsigned int calib_map_size;
|
||||
struct gpio_desc *pwrdown_gpio;
|
||||
/* ensure consistent state obtained on multiple related accesses */
|
||||
struct mutex lock;
|
||||
@ -211,6 +250,24 @@ static const unsigned int ad9467_scale_table[][2] = {
|
||||
{2300, 8}, {2400, 9}, {2500, 10},
|
||||
};
|
||||
|
||||
static const unsigned int ad9643_scale_table[][2] = {
|
||||
{2087, 0x0F}, {2065, 0x0E}, {2042, 0x0D}, {2020, 0x0C}, {1997, 0x0B},
|
||||
{1975, 0x0A}, {1952, 0x09}, {1930, 0x08}, {1907, 0x07}, {1885, 0x06},
|
||||
{1862, 0x05}, {1840, 0x04}, {1817, 0x03}, {1795, 0x02}, {1772, 0x01},
|
||||
{1750, 0x00}, {1727, 0x1F}, {1704, 0x1E}, {1681, 0x1D}, {1658, 0x1C},
|
||||
{1635, 0x1B}, {1612, 0x1A}, {1589, 0x19}, {1567, 0x18}, {1544, 0x17},
|
||||
{1521, 0x16}, {1498, 0x15}, {1475, 0x14}, {1452, 0x13}, {1429, 0x12},
|
||||
{1406, 0x11}, {1383, 0x10},
|
||||
};
|
||||
|
||||
static const unsigned int ad9649_scale_table[][2] = {
|
||||
{2000, 0},
|
||||
};
|
||||
|
||||
static const unsigned int ad9652_scale_table[][2] = {
|
||||
{1250, 0}, {1125, 1}, {1200, 2}, {1250, 3}, {1000, 5},
|
||||
};
|
||||
|
||||
static void __ad9467_get_scale(struct ad9467_state *st, int index,
|
||||
unsigned int *val, unsigned int *val2)
|
||||
{
|
||||
@ -224,14 +281,14 @@ static void __ad9467_get_scale(struct ad9467_state *st, int index,
|
||||
*val2 = tmp % 1000000;
|
||||
}
|
||||
|
||||
#define AD9467_CHAN(_chan, _si, _bits, _sign) \
|
||||
#define AD9467_CHAN(_chan, avai_mask, _si, _bits, _sign) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = _chan, \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_type_available = avai_mask, \
|
||||
.scan_index = _si, \
|
||||
.scan_type = { \
|
||||
.sign = _sign, \
|
||||
@ -241,11 +298,42 @@ static void __ad9467_get_scale(struct ad9467_state *st, int index,
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec ad9434_channels[] = {
|
||||
AD9467_CHAN(0, 0, 12, 's'),
|
||||
AD9467_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 0, 12, 's'),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad9467_channels[] = {
|
||||
AD9467_CHAN(0, 0, 16, 's'),
|
||||
AD9467_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 0, 16, 's'),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad9643_channels[] = {
|
||||
AD9467_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 0, 14, 's'),
|
||||
AD9467_CHAN(1, BIT(IIO_CHAN_INFO_SCALE), 1, 14, 's'),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad9649_channels[] = {
|
||||
AD9467_CHAN(0, 0, 0, 14, 's'),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad9652_channels[] = {
|
||||
AD9467_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 0, 16, 's'),
|
||||
AD9467_CHAN(1, BIT(IIO_CHAN_INFO_SCALE), 1, 16, 's'),
|
||||
};
|
||||
|
||||
static const char * const ad9467_test_modes[] = {
|
||||
[AN877_ADC_TESTMODE_OFF] = "off",
|
||||
[AN877_ADC_TESTMODE_MIDSCALE_SHORT] = "midscale_short",
|
||||
[AN877_ADC_TESTMODE_POS_FULLSCALE] = "pos_fullscale",
|
||||
[AN877_ADC_TESTMODE_NEG_FULLSCALE] = "neg_fullscale",
|
||||
[AN877_ADC_TESTMODE_ALT_CHECKERBOARD] = "checkerboard",
|
||||
[AN877_ADC_TESTMODE_PN23_SEQ] = "prbs23",
|
||||
[AN877_ADC_TESTMODE_PN9_SEQ] = "prbs9",
|
||||
[AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE] = "one_zero_toggle",
|
||||
[AN877_ADC_TESTMODE_USER] = "user",
|
||||
[AN877_ADC_TESTMODE_BIT_TOGGLE] = "bit_toggle",
|
||||
[AN877_ADC_TESTMODE_SYNC] = "sync",
|
||||
[AN877_ADC_TESTMODE_ONE_BIT_HIGH] = "one_bit_high",
|
||||
[AN877_ADC_TESTMODE_MIXED_BIT_FREQUENCY] = "mixed_bit_frequency",
|
||||
[AN877_ADC_TESTMODE_RAMP] = "ramp",
|
||||
};
|
||||
|
||||
static const struct ad9467_chip_info ad9467_chip_tbl = {
|
||||
@ -256,6 +344,10 @@ static const struct ad9467_chip_info ad9467_chip_tbl = {
|
||||
.num_scales = ARRAY_SIZE(ad9467_scale_table),
|
||||
.channels = ad9467_channels,
|
||||
.num_channels = ARRAY_SIZE(ad9467_channels),
|
||||
.test_points = AD9647_MAX_TEST_POINTS,
|
||||
.test_mask = GENMASK(AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE,
|
||||
AN877_ADC_TESTMODE_OFF),
|
||||
.test_mask_len = AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE + 1,
|
||||
.default_output_mode = AD9467_DEF_OUTPUT_MODE,
|
||||
.vref_mask = AD9467_REG_VREF_MASK,
|
||||
.num_lanes = 8,
|
||||
@ -269,6 +361,9 @@ static const struct ad9467_chip_info ad9434_chip_tbl = {
|
||||
.num_scales = ARRAY_SIZE(ad9434_scale_table),
|
||||
.channels = ad9434_channels,
|
||||
.num_channels = ARRAY_SIZE(ad9434_channels),
|
||||
.test_points = AD9647_MAX_TEST_POINTS,
|
||||
.test_mask = GENMASK(AN877_ADC_TESTMODE_USER, AN877_ADC_TESTMODE_OFF),
|
||||
.test_mask_len = AN877_ADC_TESTMODE_USER + 1,
|
||||
.default_output_mode = AD9434_DEF_OUTPUT_MODE,
|
||||
.vref_mask = AD9434_REG_VREF_MASK,
|
||||
.num_lanes = 6,
|
||||
@ -282,17 +377,78 @@ static const struct ad9467_chip_info ad9265_chip_tbl = {
|
||||
.num_scales = ARRAY_SIZE(ad9265_scale_table),
|
||||
.channels = ad9467_channels,
|
||||
.num_channels = ARRAY_SIZE(ad9467_channels),
|
||||
.test_points = AD9647_MAX_TEST_POINTS,
|
||||
.test_mask = GENMASK(AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE,
|
||||
AN877_ADC_TESTMODE_OFF),
|
||||
.test_mask_len = AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE + 1,
|
||||
.default_output_mode = AD9265_DEF_OUTPUT_MODE,
|
||||
.vref_mask = AD9265_REG_VREF_MASK,
|
||||
.has_dco = true,
|
||||
.has_dco_invert = true,
|
||||
};
|
||||
|
||||
static const struct ad9467_chip_info ad9643_chip_tbl = {
|
||||
.name = "ad9643",
|
||||
.id = CHIPID_AD9643,
|
||||
.max_rate = 250000000UL,
|
||||
.scale_table = ad9643_scale_table,
|
||||
.num_scales = ARRAY_SIZE(ad9643_scale_table),
|
||||
.channels = ad9643_channels,
|
||||
.num_channels = ARRAY_SIZE(ad9643_channels),
|
||||
.test_points = AD9647_MAX_TEST_POINTS,
|
||||
.test_mask = BIT(AN877_ADC_TESTMODE_RAMP) |
|
||||
GENMASK(AN877_ADC_TESTMODE_MIXED_BIT_FREQUENCY, AN877_ADC_TESTMODE_OFF),
|
||||
.test_mask_len = AN877_ADC_TESTMODE_RAMP + 1,
|
||||
.vref_mask = AD9643_REG_VREF_MASK,
|
||||
.has_dco = true,
|
||||
.has_dco_invert = true,
|
||||
.dco_en = AN877_ADC_DCO_DELAY_ENABLE,
|
||||
};
|
||||
|
||||
static const struct ad9467_chip_info ad9649_chip_tbl = {
|
||||
.name = "ad9649",
|
||||
.id = CHIPID_AD9649,
|
||||
.max_rate = 80000000UL,
|
||||
.scale_table = ad9649_scale_table,
|
||||
.num_scales = ARRAY_SIZE(ad9649_scale_table),
|
||||
.channels = ad9649_channels,
|
||||
.num_channels = ARRAY_SIZE(ad9649_channels),
|
||||
.test_points = AD9649_TEST_POINTS,
|
||||
.test_mask = GENMASK(AN877_ADC_TESTMODE_MIXED_BIT_FREQUENCY,
|
||||
AN877_ADC_TESTMODE_OFF),
|
||||
.test_mask_len = AN877_ADC_TESTMODE_MIXED_BIT_FREQUENCY + 1,
|
||||
.has_dco = true,
|
||||
.has_dco_invert = true,
|
||||
.dco_en = AN877_ADC_DCO_DELAY_ENABLE,
|
||||
};
|
||||
|
||||
static const struct ad9467_chip_info ad9652_chip_tbl = {
|
||||
.name = "ad9652",
|
||||
.id = CHIPID_AD9652,
|
||||
.max_rate = 310000000UL,
|
||||
.scale_table = ad9652_scale_table,
|
||||
.num_scales = ARRAY_SIZE(ad9652_scale_table),
|
||||
.channels = ad9652_channels,
|
||||
.num_channels = ARRAY_SIZE(ad9652_channels),
|
||||
.test_points = AD9647_MAX_TEST_POINTS,
|
||||
.test_mask = GENMASK(AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE,
|
||||
AN877_ADC_TESTMODE_OFF),
|
||||
.test_mask_len = AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE + 1,
|
||||
.vref_mask = AD9652_REG_VREF_MASK,
|
||||
.has_dco = true,
|
||||
};
|
||||
|
||||
static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2)
|
||||
{
|
||||
const struct ad9467_chip_info *info = st->info;
|
||||
unsigned int i, vref_val;
|
||||
unsigned int vref_val;
|
||||
unsigned int i = 0;
|
||||
int ret;
|
||||
|
||||
/* nothing to read if we only have one possible scale */
|
||||
if (info->num_scales == 1)
|
||||
goto out_get_scale;
|
||||
|
||||
ret = ad9467_spi_read(st, AN877_ADC_REG_VREF);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -307,6 +463,7 @@ static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2)
|
||||
if (i == info->num_scales)
|
||||
return -ERANGE;
|
||||
|
||||
out_get_scale:
|
||||
__ad9467_get_scale(st, i, val, val2);
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
@ -321,6 +478,8 @@ static int ad9467_set_scale(struct ad9467_state *st, int val, int val2)
|
||||
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
if (info->num_scales == 1)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (i = 0; i < info->num_scales; i++) {
|
||||
__ad9467_get_scale(st, i, &scale_val[0], &scale_val[1]);
|
||||
@ -352,40 +511,96 @@ static int ad9467_outputmode_set(struct ad9467_state *st, unsigned int mode)
|
||||
AN877_ADC_TRANSFER_SYNC);
|
||||
}
|
||||
|
||||
static int ad9647_calibrate_prepare(struct ad9467_state *st)
|
||||
static int ad9467_testmode_set(struct ad9467_state *st, unsigned int chan,
|
||||
unsigned int test_mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (st->info->num_channels > 1) {
|
||||
/* so that the test mode is only applied to one channel */
|
||||
ret = ad9467_spi_write(st, AN877_ADC_REG_CHAN_INDEX, BIT(chan));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO, test_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (st->info->num_channels > 1) {
|
||||
/* go to default state where all channels get write commands */
|
||||
ret = ad9467_spi_write(st, AN877_ADC_REG_CHAN_INDEX,
|
||||
GENMASK(st->info->num_channels - 1, 0));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
|
||||
AN877_ADC_TRANSFER_SYNC);
|
||||
}
|
||||
|
||||
static int ad9467_backend_testmode_on(struct ad9467_state *st,
|
||||
unsigned int chan,
|
||||
enum iio_backend_test_pattern pattern)
|
||||
{
|
||||
struct iio_backend_data_fmt data = {
|
||||
.enable = false,
|
||||
};
|
||||
unsigned int c;
|
||||
int ret;
|
||||
|
||||
ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO,
|
||||
AN877_ADC_TESTMODE_PN9_SEQ);
|
||||
ret = iio_backend_data_format_set(st->back, chan, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
|
||||
AN877_ADC_TRANSFER_SYNC);
|
||||
ret = iio_backend_test_pattern_set(st->back, chan, pattern);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return iio_backend_chan_enable(st->back, chan);
|
||||
}
|
||||
|
||||
static int ad9467_backend_testmode_off(struct ad9467_state *st,
|
||||
unsigned int chan)
|
||||
{
|
||||
struct iio_backend_data_fmt data = {
|
||||
.enable = true,
|
||||
.sign_extend = true,
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = iio_backend_chan_disable(st->back, chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_backend_test_pattern_set(st->back, chan,
|
||||
IIO_BACKEND_NO_TEST_PATTERN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return iio_backend_data_format_set(st->back, chan, &data);
|
||||
}
|
||||
|
||||
static int ad9647_calibrate_prepare(struct ad9467_state *st)
|
||||
{
|
||||
unsigned int c;
|
||||
int ret;
|
||||
|
||||
ret = ad9467_outputmode_set(st, st->info->default_output_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (c = 0; c < st->info->num_channels; c++) {
|
||||
ret = iio_backend_data_format_set(st->back, c, &data);
|
||||
ret = ad9467_testmode_set(st, c, AN877_ADC_TESTMODE_PN9_SEQ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad9467_backend_testmode_on(st, c,
|
||||
IIO_BACKEND_ADI_PRBS_9A);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_backend_test_pattern_set(st->back, 0,
|
||||
IIO_BACKEND_ADI_PRBS_9A);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return iio_backend_chan_enable(st->back, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad9647_calibrate_polarity_set(struct ad9467_state *st,
|
||||
@ -442,7 +657,7 @@ static int ad9467_calibrate_apply(struct ad9467_state *st, unsigned int val)
|
||||
|
||||
if (st->info->has_dco) {
|
||||
ret = ad9467_spi_write(st, AN877_ADC_REG_OUTPUT_DELAY,
|
||||
val);
|
||||
val | st->info->dco_en);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -461,57 +676,38 @@ static int ad9467_calibrate_apply(struct ad9467_state *st, unsigned int val)
|
||||
|
||||
static int ad9647_calibrate_stop(struct ad9467_state *st)
|
||||
{
|
||||
struct iio_backend_data_fmt data = {
|
||||
.sign_extend = true,
|
||||
.enable = true,
|
||||
};
|
||||
unsigned int c, mode;
|
||||
int ret;
|
||||
|
||||
ret = iio_backend_chan_disable(st->back, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_backend_test_pattern_set(st->back, 0,
|
||||
IIO_BACKEND_NO_TEST_PATTERN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (c = 0; c < st->info->num_channels; c++) {
|
||||
ret = iio_backend_data_format_set(st->back, c, &data);
|
||||
ret = ad9467_backend_testmode_off(st, c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad9467_testmode_set(st, c, AN877_ADC_TESTMODE_OFF);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
|
||||
ret = ad9467_outputmode_set(st, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO,
|
||||
AN877_ADC_TESTMODE_OFF);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
|
||||
AN877_ADC_TRANSFER_SYNC);
|
||||
return ad9467_outputmode_set(st, mode);
|
||||
}
|
||||
|
||||
static int ad9467_calibrate(struct ad9467_state *st)
|
||||
{
|
||||
unsigned int point, val, inv_val, cnt, inv_cnt = 0;
|
||||
unsigned int point, val, inv_val, cnt, inv_cnt = 0, c;
|
||||
/*
|
||||
* Half of the bitmap is for the inverted signal. The number of test
|
||||
* points is the same though...
|
||||
*/
|
||||
unsigned int test_points = AD9647_MAX_TEST_POINTS;
|
||||
unsigned int test_points = st->info->test_points;
|
||||
unsigned long sample_rate = clk_get_rate(st->clk);
|
||||
struct device *dev = &st->spi->dev;
|
||||
bool invert = false, stat;
|
||||
int ret;
|
||||
|
||||
/* all points invalid */
|
||||
bitmap_fill(st->calib_map, BITS_PER_TYPE(st->calib_map));
|
||||
bitmap_fill(st->calib_map, st->calib_map_size);
|
||||
|
||||
ret = ad9647_calibrate_prepare(st);
|
||||
if (ret)
|
||||
@ -521,16 +717,31 @@ retune:
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (point = 0; point < test_points; point++) {
|
||||
for (point = 0; point < st->info->test_points; point++) {
|
||||
ret = ad9467_calibrate_apply(st, point);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_backend_chan_status(st->back, 0, &stat);
|
||||
if (ret)
|
||||
return ret;
|
||||
for (c = 0; c < st->info->num_channels; c++) {
|
||||
ret = iio_backend_chan_status(st->back, c, &stat);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
__assign_bit(point + invert * test_points, st->calib_map, stat);
|
||||
/*
|
||||
* A point is considered valid if all channels report no
|
||||
* error. If one reports an error, then we consider the
|
||||
* point as invalid and we can break the loop right away.
|
||||
*/
|
||||
if (stat) {
|
||||
dev_dbg(dev, "Invalid point(%u, inv:%u) for CH:%u\n",
|
||||
point, invert, c);
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == st->info->num_channels - 1)
|
||||
__clear_bit(point + invert * test_points,
|
||||
st->calib_map);
|
||||
}
|
||||
}
|
||||
|
||||
if (!invert) {
|
||||
@ -541,8 +752,13 @@ retune:
|
||||
* a row.
|
||||
*/
|
||||
if (cnt < 3) {
|
||||
invert = true;
|
||||
goto retune;
|
||||
if (AD9467_CAN_INVERT(st)) {
|
||||
invert = true;
|
||||
goto retune;
|
||||
}
|
||||
|
||||
if (!cnt)
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
inv_cnt = ad9467_find_optimal_point(st->calib_map, test_points,
|
||||
@ -679,7 +895,7 @@ static int ad9467_update_scan_mode(struct iio_dev *indio_dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_info ad9467_info = {
|
||||
static struct iio_info ad9467_info = {
|
||||
.read_raw = ad9467_read_raw,
|
||||
.write_raw = ad9467_write_raw,
|
||||
.update_scan_mode = ad9467_update_scan_mode,
|
||||
@ -762,12 +978,134 @@ static int ad9467_iio_backend_get(struct ad9467_state *st)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int ad9467_test_mode_available_show(struct seq_file *s, void *ignored)
|
||||
{
|
||||
struct ad9467_state *st = s->private;
|
||||
unsigned int bit;
|
||||
|
||||
for_each_set_bit(bit, &st->info->test_mask, st->info->test_mask_len)
|
||||
seq_printf(s, "%s\n", ad9467_test_modes[bit]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(ad9467_test_mode_available);
|
||||
|
||||
static ssize_t ad9467_chan_test_mode_read(struct file *file,
|
||||
char __user *userbuf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct ad9467_chan_test_mode *chan = file->private_data;
|
||||
struct ad9467_state *st = chan->st;
|
||||
char buf[128] = {0};
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
if (chan->mode == AN877_ADC_TESTMODE_PN9_SEQ ||
|
||||
chan->mode == AN877_ADC_TESTMODE_PN23_SEQ) {
|
||||
len = scnprintf(buf, sizeof(buf), "Running \"%s\" Test:\n\t",
|
||||
ad9467_test_modes[chan->mode]);
|
||||
|
||||
ret = iio_backend_debugfs_print_chan_status(st->back, chan->idx,
|
||||
buf + len,
|
||||
sizeof(buf) - len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret;
|
||||
} else if (chan->mode == AN877_ADC_TESTMODE_OFF) {
|
||||
len = scnprintf(buf, sizeof(buf), "No test Running...\n");
|
||||
} else {
|
||||
len = scnprintf(buf, sizeof(buf), "Running \"%s\" Test on CH:%u\n",
|
||||
ad9467_test_modes[chan->mode], chan->idx);
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t ad9467_chan_test_mode_write(struct file *file,
|
||||
const char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ad9467_chan_test_mode *chan = file->private_data;
|
||||
struct ad9467_state *st = chan->st;
|
||||
char test_mode[32] = {0};
|
||||
unsigned int mode;
|
||||
int ret;
|
||||
|
||||
ret = simple_write_to_buffer(test_mode, sizeof(test_mode) - 1, ppos,
|
||||
userbuf, count);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for_each_set_bit(mode, &st->info->test_mask, st->info->test_mask_len) {
|
||||
if (sysfs_streq(test_mode, ad9467_test_modes[mode]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (mode == st->info->test_mask_len)
|
||||
return -EINVAL;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
if (mode == AN877_ADC_TESTMODE_OFF) {
|
||||
unsigned int out_mode;
|
||||
|
||||
if (chan->mode == AN877_ADC_TESTMODE_PN9_SEQ ||
|
||||
chan->mode == AN877_ADC_TESTMODE_PN23_SEQ) {
|
||||
ret = ad9467_backend_testmode_off(st, chan->idx);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad9467_testmode_set(st, chan->idx, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
out_mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
|
||||
ret = ad9467_outputmode_set(st, out_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
ret = ad9467_outputmode_set(st, st->info->default_output_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad9467_testmode_set(st, chan->idx, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* some patterns have a backend matching monitoring block */
|
||||
if (mode == AN877_ADC_TESTMODE_PN9_SEQ) {
|
||||
ret = ad9467_backend_testmode_on(st, chan->idx,
|
||||
IIO_BACKEND_ADI_PRBS_9A);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (mode == AN877_ADC_TESTMODE_PN23_SEQ) {
|
||||
ret = ad9467_backend_testmode_on(st, chan->idx,
|
||||
IIO_BACKEND_ADI_PRBS_23A);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
chan->mode = mode;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ad9467_chan_test_mode_fops = {
|
||||
.open = simple_open,
|
||||
.read = ad9467_chan_test_mode_read,
|
||||
.write = ad9467_chan_test_mode_write,
|
||||
.llseek = default_llseek,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static ssize_t ad9467_dump_calib_table(struct file *file,
|
||||
char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ad9467_state *st = file->private_data;
|
||||
unsigned int bit, size = BITS_PER_TYPE(st->calib_map);
|
||||
unsigned int bit;
|
||||
/* +2 for the newline and +1 for the string termination */
|
||||
unsigned char map[AD9647_MAX_TEST_POINTS * 2 + 3];
|
||||
ssize_t len = 0;
|
||||
@ -776,8 +1114,8 @@ static ssize_t ad9467_dump_calib_table(struct file *file,
|
||||
if (*ppos)
|
||||
goto out_read;
|
||||
|
||||
for (bit = 0; bit < size; bit++) {
|
||||
if (bit == size / 2)
|
||||
for (bit = 0; bit < st->calib_map_size; bit++) {
|
||||
if (AD9467_CAN_INVERT(st) && bit == st->calib_map_size / 2)
|
||||
len += scnprintf(map + len, sizeof(map) - len, "\n");
|
||||
|
||||
len += scnprintf(map + len, sizeof(map) - len, "%c",
|
||||
@ -800,12 +1138,33 @@ static void ad9467_debugfs_init(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct dentry *d = iio_get_debugfs_dentry(indio_dev);
|
||||
struct ad9467_state *st = iio_priv(indio_dev);
|
||||
char attr_name[32];
|
||||
unsigned int chan;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DEBUG_FS))
|
||||
return;
|
||||
|
||||
st->chan_test = devm_kcalloc(&st->spi->dev, st->info->num_channels,
|
||||
sizeof(*st->chan_test), GFP_KERNEL);
|
||||
if (!st->chan_test)
|
||||
return;
|
||||
|
||||
debugfs_create_file("calibration_table_dump", 0400, d, st,
|
||||
&ad9467_calib_table_fops);
|
||||
|
||||
for (chan = 0; chan < st->info->num_channels; chan++) {
|
||||
snprintf(attr_name, sizeof(attr_name), "in_voltage%u_test_mode",
|
||||
chan);
|
||||
st->chan_test[chan].idx = chan;
|
||||
st->chan_test[chan].st = st;
|
||||
debugfs_create_file(attr_name, 0600, d, &st->chan_test[chan],
|
||||
&ad9467_chan_test_mode_fops);
|
||||
}
|
||||
|
||||
debugfs_create_file("in_voltage_test_mode_available", 0400, d, st,
|
||||
&ad9467_test_mode_available_fops);
|
||||
|
||||
iio_backend_debugfs_add(st->back, indio_dev);
|
||||
}
|
||||
|
||||
static int ad9467_probe(struct spi_device *spi)
|
||||
@ -826,6 +1185,10 @@ static int ad9467_probe(struct spi_device *spi)
|
||||
if (!st->info)
|
||||
return -ENODEV;
|
||||
|
||||
st->calib_map_size = st->info->test_points;
|
||||
if (AD9467_CAN_INVERT(st))
|
||||
st->calib_map_size *= 2;
|
||||
|
||||
st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk");
|
||||
if (IS_ERR(st->clk))
|
||||
return PTR_ERR(st->clk);
|
||||
@ -850,6 +1213,8 @@ static int ad9467_probe(struct spi_device *spi)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (st->info->num_scales > 1)
|
||||
ad9467_info.read_avail = ad9467_read_avail;
|
||||
indio_dev->name = st->info->name;
|
||||
indio_dev->channels = st->info->channels;
|
||||
indio_dev->num_channels = st->info->num_channels;
|
||||
@ -884,6 +1249,9 @@ static const struct of_device_id ad9467_of_match[] = {
|
||||
{ .compatible = "adi,ad9265", .data = &ad9265_chip_tbl, },
|
||||
{ .compatible = "adi,ad9434", .data = &ad9434_chip_tbl, },
|
||||
{ .compatible = "adi,ad9467", .data = &ad9467_chip_tbl, },
|
||||
{ .compatible = "adi,ad9643", .data = &ad9643_chip_tbl, },
|
||||
{ .compatible = "adi,ad9649", .data = &ad9649_chip_tbl, },
|
||||
{ .compatible = "adi,ad9652", .data = &ad9652_chip_tbl, },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad9467_of_match);
|
||||
@ -892,6 +1260,9 @@ static const struct spi_device_id ad9467_ids[] = {
|
||||
{ "ad9265", (kernel_ulong_t)&ad9265_chip_tbl },
|
||||
{ "ad9434", (kernel_ulong_t)&ad9434_chip_tbl },
|
||||
{ "ad9467", (kernel_ulong_t)&ad9467_chip_tbl },
|
||||
{ "ad9643", (kernel_ulong_t)&ad9643_chip_tbl },
|
||||
{ "ad9649", (kernel_ulong_t)&ad9649_chip_tbl, },
|
||||
{ "ad9652", (kernel_ulong_t)&ad9652_chip_tbl, },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad9467_ids);
|
||||
|
@ -351,7 +351,7 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
|
||||
|
||||
if (sigma_delta->num_slots == 1) {
|
||||
channel = find_first_bit(indio_dev->active_scan_mask,
|
||||
indio_dev->masklength);
|
||||
iio_get_masklength(indio_dev));
|
||||
ret = ad_sigma_delta_set_channel(sigma_delta,
|
||||
indio_dev->channels[channel].address);
|
||||
if (ret)
|
||||
@ -364,7 +364,7 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
|
||||
* implementation is mandatory.
|
||||
*/
|
||||
slot = 0;
|
||||
for_each_set_bit(i, indio_dev->active_scan_mask, indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, i) {
|
||||
sigma_delta->slots[slot] = indio_dev->channels[i].address;
|
||||
slot++;
|
||||
}
|
||||
@ -526,7 +526,7 @@ static bool ad_sd_validate_scan_mask(struct iio_dev *indio_dev, const unsigned l
|
||||
{
|
||||
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
|
||||
|
||||
return bitmap_weight(mask, indio_dev->masklength) <= sigma_delta->num_slots;
|
||||
return bitmap_weight(mask, iio_get_masklength(indio_dev)) <= sigma_delta->num_slots;
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = {
|
||||
|
@ -61,6 +61,10 @@
|
||||
|
||||
#define ADI_AXI_ADC_REG_CHAN_STATUS(c) (0x0404 + (c) * 0x40)
|
||||
#define ADI_AXI_ADC_CHAN_STAT_PN_MASK GENMASK(2, 1)
|
||||
/* out of sync */
|
||||
#define ADI_AXI_ADC_CHAN_STAT_PN_OOS BIT(1)
|
||||
/* spurious out of sync */
|
||||
#define ADI_AXI_ADC_CHAN_STAT_PN_ERR BIT(2)
|
||||
|
||||
#define ADI_AXI_ADC_REG_CHAN_CTRL_3(c) (0x0418 + (c) * 0x40)
|
||||
#define ADI_AXI_ADC_CHAN_PN_SEL_MASK GENMASK(19, 16)
|
||||
@ -199,17 +203,19 @@ static int axi_adc_test_pattern_set(struct iio_backend *back,
|
||||
return regmap_update_bits(st->regmap, ADI_AXI_ADC_REG_CHAN_CTRL_3(chan),
|
||||
ADI_AXI_ADC_CHAN_PN_SEL_MASK,
|
||||
FIELD_PREP(ADI_AXI_ADC_CHAN_PN_SEL_MASK, 0));
|
||||
case IIO_BACKEND_ADI_PRBS_23A:
|
||||
return regmap_update_bits(st->regmap, ADI_AXI_ADC_REG_CHAN_CTRL_3(chan),
|
||||
ADI_AXI_ADC_CHAN_PN_SEL_MASK,
|
||||
FIELD_PREP(ADI_AXI_ADC_CHAN_PN_SEL_MASK, 1));
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_adc_chan_status(struct iio_backend *back, unsigned int chan,
|
||||
bool *error)
|
||||
static int axi_adc_read_chan_status(struct adi_axi_adc_state *st, unsigned int chan,
|
||||
unsigned int *status)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
/* reset test bits by setting them */
|
||||
@ -221,7 +227,18 @@ static int axi_adc_chan_status(struct iio_backend *back, unsigned int chan,
|
||||
/* let's give enough time to validate or erroring the incoming pattern */
|
||||
fsleep(1000);
|
||||
|
||||
ret = regmap_read(st->regmap, ADI_AXI_ADC_REG_CHAN_STATUS(chan), &val);
|
||||
return regmap_read(st->regmap, ADI_AXI_ADC_REG_CHAN_STATUS(chan),
|
||||
status);
|
||||
}
|
||||
|
||||
static int axi_adc_chan_status(struct iio_backend *back, unsigned int chan,
|
||||
bool *error)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = axi_adc_read_chan_status(st, chan, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -233,6 +250,30 @@ static int axi_adc_chan_status(struct iio_backend *back, unsigned int chan,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axi_adc_debugfs_print_chan_status(struct iio_backend *back,
|
||||
unsigned int chan, char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = axi_adc_read_chan_status(st, chan, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* PN_ERR is cleared in case out of sync is set. Hence, no point in
|
||||
* checking both bits.
|
||||
*/
|
||||
if (val & ADI_AXI_ADC_CHAN_STAT_PN_OOS)
|
||||
return scnprintf(buf, len, "CH%u: Out of Sync.\n", chan);
|
||||
if (val & ADI_AXI_ADC_CHAN_STAT_PN_ERR)
|
||||
return scnprintf(buf, len, "CH%u: Spurious Out of Sync.\n", chan);
|
||||
|
||||
return scnprintf(buf, len, "CH%u: OK.\n", chan);
|
||||
}
|
||||
|
||||
static int axi_adc_chan_enable(struct iio_backend *back, unsigned int chan)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
@ -267,13 +308,24 @@ static void axi_adc_free_buffer(struct iio_backend *back,
|
||||
iio_dmaengine_buffer_free(buffer);
|
||||
}
|
||||
|
||||
static int axi_adc_reg_access(struct iio_backend *back, unsigned int reg,
|
||||
unsigned int writeval, unsigned int *readval)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
|
||||
if (readval)
|
||||
return regmap_read(st->regmap, reg, readval);
|
||||
|
||||
return regmap_write(st->regmap, reg, writeval);
|
||||
}
|
||||
|
||||
static const struct regmap_config axi_adc_regmap_config = {
|
||||
.val_bits = 32,
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
static const struct iio_backend_ops adi_axi_adc_generic = {
|
||||
static const struct iio_backend_ops adi_axi_adc_ops = {
|
||||
.enable = axi_adc_enable,
|
||||
.disable = axi_adc_disable,
|
||||
.data_format_set = axi_adc_data_format_set,
|
||||
@ -285,6 +337,13 @@ static const struct iio_backend_ops adi_axi_adc_generic = {
|
||||
.iodelay_set = axi_adc_iodelays_set,
|
||||
.test_pattern_set = axi_adc_test_pattern_set,
|
||||
.chan_status = axi_adc_chan_status,
|
||||
.debugfs_reg_access = iio_backend_debugfs_ptr(axi_adc_reg_access),
|
||||
.debugfs_print_chan_status = iio_backend_debugfs_ptr(axi_adc_debugfs_print_chan_status),
|
||||
};
|
||||
|
||||
static const struct iio_backend_info adi_axi_adc_generic = {
|
||||
.name = "axi-adc",
|
||||
.ops = &adi_axi_adc_ops,
|
||||
};
|
||||
|
||||
static int adi_axi_adc_probe(struct platform_device *pdev)
|
||||
|
@ -555,8 +555,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (of_find_property(data->dev->of_node, "aspeed,battery-sensing",
|
||||
NULL)) {
|
||||
if (of_property_present(data->dev->of_node, "aspeed,battery-sensing")) {
|
||||
if (data->model_data->bat_sense_sup) {
|
||||
data->battery_sensing = 1;
|
||||
if (readl(data->base + ASPEED_REG_ENGINE_CONTROL) &
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
@ -268,9 +269,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
|
||||
struct iio_chan_spec const *chan;
|
||||
int i, j = 0;
|
||||
|
||||
for (i = 0; i < idev->masklength; i++) {
|
||||
if (!test_bit(i, idev->active_scan_mask))
|
||||
continue;
|
||||
iio_for_each_active_channel(idev, i) {
|
||||
chan = idev->channels + i;
|
||||
st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, chan->channel));
|
||||
j++;
|
||||
@ -543,22 +542,18 @@ static int at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
|
||||
int i;
|
||||
|
||||
for (i = 0; i < st->caps->trigger_number; i++) {
|
||||
char *name = kasprintf(GFP_KERNEL,
|
||||
"%s-dev%d-%s",
|
||||
idev->name,
|
||||
iio_device_id(idev),
|
||||
triggers[i].name);
|
||||
char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s-dev%d-%s",
|
||||
idev->name,
|
||||
iio_device_id(idev),
|
||||
triggers[i].name);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
if (strcmp(trigger_name, name) == 0) {
|
||||
kfree(name);
|
||||
if (triggers[i].value == 0)
|
||||
return -EINVAL;
|
||||
return triggers[i].value;
|
||||
}
|
||||
|
||||
kfree(name);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
@ -157,9 +157,7 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p)
|
||||
|
||||
i = 0;
|
||||
sample_invalid = false;
|
||||
for_each_set_bit(scan_idx, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
|
||||
iio_for_each_active_channel(indio_dev, scan_idx) {
|
||||
channel = indio_dev->channels[scan_idx].channel;
|
||||
cc10001_adc_start(adc_dev, channel);
|
||||
|
||||
|
@ -108,7 +108,7 @@ static void dln2_adc_update_demux(struct dln2_adc *dln2)
|
||||
dln2->demux_count = 0;
|
||||
|
||||
/* Optimize all 8-channels case */
|
||||
if (indio_dev->masklength &&
|
||||
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;
|
||||
@ -117,9 +117,7 @@ static void dln2_adc_update_demux(struct dln2_adc *dln2)
|
||||
}
|
||||
|
||||
/* Build demux table from fixed 8-channels to active_scan_mask */
|
||||
for_each_set_bit(out_ind,
|
||||
indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, out_ind) {
|
||||
/* Handle timestamp separately */
|
||||
if (out_ind == DLN2_ADC_MAX_CHANNELS)
|
||||
break;
|
||||
@ -541,7 +539,7 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
|
||||
|
||||
/* Assign trigger channel based on first enabled channel */
|
||||
trigger_chan = find_first_bit(indio_dev->active_scan_mask,
|
||||
indio_dev->masklength);
|
||||
iio_get_masklength(indio_dev));
|
||||
if (trigger_chan < DLN2_ADC_MAX_CHANNELS) {
|
||||
dln2->trigger_chan = trigger_chan;
|
||||
ret = dln2_adc_set_chan_period(dln2, dln2->trigger_chan,
|
||||
|
@ -363,10 +363,7 @@ static irqreturn_t hx711_trigger(int irq, void *p)
|
||||
|
||||
memset(hx711_data->buffer, 0, sizeof(hx711_data->buffer));
|
||||
|
||||
for (i = 0; i < indio_dev->masklength; i++) {
|
||||
if (!test_bit(i, indio_dev->active_scan_mask))
|
||||
continue;
|
||||
|
||||
iio_for_each_active_channel(indio_dev, i) {
|
||||
hx711_data->buffer[j] = hx711_reset_read(hx711_data,
|
||||
indio_dev->channels[i].channel);
|
||||
j++;
|
||||
|
@ -755,8 +755,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
|
||||
* Single register reads: bulk_read will not work with ina226/219
|
||||
* as there is no auto-increment of the register pointer.
|
||||
*/
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
unsigned int val;
|
||||
|
||||
ret = regmap_read(chip->regmap,
|
||||
|
@ -174,8 +174,7 @@ static irqreturn_t max1118_trigger_handler(int irq, void *p)
|
||||
|
||||
mutex_lock(&adc->lock);
|
||||
|
||||
for_each_set_bit(scan_index, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, scan_index) {
|
||||
const struct iio_chan_spec *scan_chan =
|
||||
&indio_dev->channels[scan_index];
|
||||
int ret = max1118_read(indio_dev, scan_chan->channel);
|
||||
|
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sysfs.h>
|
||||
@ -818,7 +819,6 @@ static int max1363_read_event_config(struct iio_dev *indio_dev,
|
||||
|
||||
static int max1363_monitor_mode_update(struct max1363_state *st, int enabled)
|
||||
{
|
||||
u8 *tx_buf;
|
||||
int ret, i = 3, j;
|
||||
unsigned long numelements;
|
||||
int len;
|
||||
@ -850,11 +850,10 @@ static int max1363_monitor_mode_update(struct max1363_state *st, int enabled)
|
||||
}
|
||||
numelements = bitmap_weight(modemask, MAX1363_MAX_CHANNELS);
|
||||
len = 3 * numelements + 3;
|
||||
tx_buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!tx_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
u8 *tx_buf __free(kfree) = kmalloc(len, GFP_KERNEL);
|
||||
if (!tx_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
tx_buf[0] = st->configbyte;
|
||||
tx_buf[1] = st->setupbyte;
|
||||
tx_buf[2] = (st->monitor_speed << 1);
|
||||
@ -893,11 +892,9 @@ static int max1363_monitor_mode_update(struct max1363_state *st, int enabled)
|
||||
|
||||
ret = st->send(st->client, tx_buf, len);
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
if (ret != len) {
|
||||
ret = -EIO;
|
||||
goto error_ret;
|
||||
}
|
||||
return ret;
|
||||
if (ret != len)
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* Now that we hopefully have sensible thresholds in place it is
|
||||
@ -910,18 +907,13 @@ static int max1363_monitor_mode_update(struct max1363_state *st, int enabled)
|
||||
tx_buf[1] = MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0;
|
||||
ret = st->send(st->client, tx_buf, 2);
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
if (ret != 2) {
|
||||
ret = -EIO;
|
||||
goto error_ret;
|
||||
}
|
||||
ret = 0;
|
||||
return ret;
|
||||
if (ret != 2)
|
||||
return -EIO;
|
||||
|
||||
st->monitor_on = true;
|
||||
error_ret:
|
||||
|
||||
kfree(tx_buf);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -349,8 +349,6 @@ struct mcp3564_chip_info {
|
||||
* struct mcp3564_state - working data for a ADC device
|
||||
* @chip_info: chip specific data
|
||||
* @spi: SPI device structure
|
||||
* @vref: the regulator device used as a voltage reference in case
|
||||
* external voltage reference is used
|
||||
* @vref_mv: voltage reference value in miliVolts
|
||||
* @lock: synchronize access to driver's state members
|
||||
* @dev_addr: hardware device address
|
||||
@ -369,7 +367,6 @@ struct mcp3564_chip_info {
|
||||
struct mcp3564_state {
|
||||
const struct mcp3564_chip_info *chip_info;
|
||||
struct spi_device *spi;
|
||||
struct regulator *vref;
|
||||
unsigned short vref_mv;
|
||||
struct mutex lock; /* Synchronize access to driver's state members */
|
||||
u8 dev_addr;
|
||||
@ -1085,11 +1082,6 @@ static int mcp3564_parse_fw_children(struct iio_dev *indio_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mcp3564_disable_reg(void *reg)
|
||||
{
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static void mcp3564_fill_scale_tbls(struct mcp3564_state *adc)
|
||||
{
|
||||
unsigned int pow = adc->chip_info->resolution - 1;
|
||||
@ -1110,7 +1102,7 @@ static void mcp3564_fill_scale_tbls(struct mcp3564_state *adc)
|
||||
}
|
||||
}
|
||||
|
||||
static int mcp3564_config(struct iio_dev *indio_dev)
|
||||
static int mcp3564_config(struct iio_dev *indio_dev, bool *use_internal_vref_attr)
|
||||
{
|
||||
struct mcp3564_state *adc = iio_priv(indio_dev);
|
||||
struct device *dev = &adc->spi->dev;
|
||||
@ -1119,6 +1111,7 @@ static int mcp3564_config(struct iio_dev *indio_dev)
|
||||
enum mcp3564_ids ids;
|
||||
int ret = 0;
|
||||
unsigned int tmp = 0x01;
|
||||
bool internal_vref;
|
||||
bool err = false;
|
||||
|
||||
/*
|
||||
@ -1218,36 +1211,22 @@ static int mcp3564_config(struct iio_dev *indio_dev)
|
||||
|
||||
dev_dbg(dev, "Found %s chip\n", adc->chip_info->name);
|
||||
|
||||
adc->vref = devm_regulator_get_optional(dev, "vref");
|
||||
if (IS_ERR(adc->vref)) {
|
||||
if (PTR_ERR(adc->vref) != -ENODEV)
|
||||
return dev_err_probe(dev, PTR_ERR(adc->vref),
|
||||
"failed to get regulator\n");
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, "vref");
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret, "Failed to get vref voltage\n");
|
||||
|
||||
internal_vref = ret == -ENODEV;
|
||||
adc->vref_mv = internal_vref ? MCP3564R_INT_VREF_MV : ret / MILLI;
|
||||
*use_internal_vref_attr = internal_vref;
|
||||
|
||||
if (internal_vref) {
|
||||
/* Check if chip has internal vref */
|
||||
if (!adc->have_vref)
|
||||
return dev_err_probe(dev, PTR_ERR(adc->vref),
|
||||
"Unknown Vref\n");
|
||||
adc->vref = NULL;
|
||||
return dev_err_probe(dev, -ENODEV, "Unknown Vref\n");
|
||||
|
||||
dev_dbg(dev, "%s: Using internal Vref\n", __func__);
|
||||
} else {
|
||||
ret = regulator_enable(adc->vref);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, mcp3564_disable_reg,
|
||||
adc->vref);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_dbg(dev, "%s: Using External Vref\n", __func__);
|
||||
|
||||
ret = regulator_get_voltage(adc->vref);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to read vref regulator\n");
|
||||
|
||||
adc->vref_mv = ret / MILLI;
|
||||
}
|
||||
|
||||
ret = mcp3564_parse_fw_children(indio_dev);
|
||||
@ -1350,10 +1329,8 @@ static int mcp3564_config(struct iio_dev *indio_dev)
|
||||
tmp_reg |= FIELD_PREP(MCP3564_CONFIG0_CLK_SEL_MASK, MCP3564_CONFIG0_USE_INT_CLK);
|
||||
tmp_reg |= MCP3456_CONFIG0_BIT6_DEFAULT;
|
||||
|
||||
if (!adc->vref) {
|
||||
if (internal_vref)
|
||||
tmp_reg |= FIELD_PREP(MCP3456_CONFIG0_VREF_MASK, 1);
|
||||
adc->vref_mv = MCP3564R_INT_VREF_MV;
|
||||
}
|
||||
|
||||
ret = mcp3564_write_8bits(adc, MCP3564_CONFIG0_REG, tmp_reg);
|
||||
|
||||
@ -1412,6 +1389,7 @@ static int mcp3564_probe(struct spi_device *spi)
|
||||
int ret;
|
||||
struct iio_dev *indio_dev;
|
||||
struct mcp3564_state *adc;
|
||||
bool use_internal_vref_attr;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
|
||||
if (!indio_dev)
|
||||
@ -1428,7 +1406,7 @@ static int mcp3564_probe(struct spi_device *spi)
|
||||
* enable/disable certain channels
|
||||
* change the sampling rate to the requested value
|
||||
*/
|
||||
ret = mcp3564_config(indio_dev);
|
||||
ret = mcp3564_config(indio_dev, &use_internal_vref_attr);
|
||||
if (ret)
|
||||
return dev_err_probe(&spi->dev, ret,
|
||||
"Can't configure MCP356X device\n");
|
||||
@ -1440,7 +1418,7 @@ static int mcp3564_probe(struct spi_device *spi)
|
||||
indio_dev->name = adc->chip_info->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
if (!adc->vref)
|
||||
if (use_internal_vref_attr)
|
||||
indio_dev->info = &mcp3564r_info;
|
||||
else
|
||||
indio_dev->info = &mcp3564_info;
|
||||
|
@ -103,7 +103,7 @@ struct mcp3911_chip_info {
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned int num_channels;
|
||||
|
||||
int (*config)(struct mcp3911 *adc);
|
||||
int (*config)(struct mcp3911 *adc, bool external_vref);
|
||||
int (*get_osr)(struct mcp3911 *adc, u32 *val);
|
||||
int (*set_osr)(struct mcp3911 *adc, u32 val);
|
||||
int (*enable_offset)(struct mcp3911 *adc, bool enable);
|
||||
@ -115,7 +115,6 @@ struct mcp3911_chip_info {
|
||||
struct mcp3911 {
|
||||
struct spi_device *spi;
|
||||
struct mutex lock;
|
||||
struct regulator *vref;
|
||||
struct clk *clki;
|
||||
u32 dev_addr;
|
||||
struct iio_trigger *trig;
|
||||
@ -385,23 +384,11 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static int mcp3911_calc_scale_table(struct mcp3911 *adc)
|
||||
static int mcp3911_calc_scale_table(u32 vref_mv)
|
||||
{
|
||||
struct device *dev = &adc->spi->dev;
|
||||
u32 ref = MCP3911_INT_VREF_MV;
|
||||
u32 div;
|
||||
int ret;
|
||||
u64 tmp;
|
||||
|
||||
if (adc->vref) {
|
||||
ret = regulator_get_voltage(adc->vref);
|
||||
if (ret < 0) {
|
||||
return dev_err_probe(dev, ret, "failed to get vref voltage\n");
|
||||
}
|
||||
|
||||
ref = ret / 1000;
|
||||
}
|
||||
|
||||
/*
|
||||
* For 24-bit Conversion
|
||||
* Raw = ((Voltage)/(Vref) * 2^23 * Gain * 1.5
|
||||
@ -412,7 +399,7 @@ static int mcp3911_calc_scale_table(struct mcp3911 *adc)
|
||||
*/
|
||||
for (int i = 0; i < MCP3911_NUM_SCALES; i++) {
|
||||
div = 12582912 * BIT(i);
|
||||
tmp = div_s64((s64)ref * 1000000000LL, div);
|
||||
tmp = div_s64((s64)vref_mv * 1000000000LL, div);
|
||||
|
||||
mcp3911_scale_table[i][0] = 0;
|
||||
mcp3911_scale_table[i][1] = tmp;
|
||||
@ -523,7 +510,7 @@ static irqreturn_t mcp3911_trigger_handler(int irq, void *p)
|
||||
goto out;
|
||||
}
|
||||
|
||||
for_each_set_bit(scan_index, indio_dev->active_scan_mask, indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, scan_index) {
|
||||
const struct iio_chan_spec *scan_chan = &indio_dev->channels[scan_index];
|
||||
|
||||
adc->scan.channels[i] = get_unaligned_be24(&adc->rx_buf[scan_chan->channel * 3]);
|
||||
@ -544,7 +531,7 @@ static const struct iio_info mcp3911_info = {
|
||||
.write_raw_get_fmt = mcp3911_write_raw_get_fmt,
|
||||
};
|
||||
|
||||
static int mcp3911_config(struct mcp3911 *adc)
|
||||
static int mcp3911_config(struct mcp3911 *adc, bool external_vref)
|
||||
{
|
||||
struct device *dev = &adc->spi->dev;
|
||||
u32 regval;
|
||||
@ -555,7 +542,7 @@ static int mcp3911_config(struct mcp3911 *adc)
|
||||
return ret;
|
||||
|
||||
regval &= ~MCP3911_CONFIG_VREFEXT;
|
||||
if (adc->vref) {
|
||||
if (external_vref) {
|
||||
dev_dbg(dev, "use external voltage reference\n");
|
||||
regval |= FIELD_PREP(MCP3911_CONFIG_VREFEXT, 1);
|
||||
} else {
|
||||
@ -610,7 +597,7 @@ static int mcp3911_config(struct mcp3911 *adc)
|
||||
return mcp3911_write(adc, MCP3911_REG_GAIN, regval, 1);
|
||||
}
|
||||
|
||||
static int mcp3910_config(struct mcp3911 *adc)
|
||||
static int mcp3910_config(struct mcp3911 *adc, bool external_vref)
|
||||
{
|
||||
struct device *dev = &adc->spi->dev;
|
||||
u32 regval;
|
||||
@ -621,7 +608,7 @@ static int mcp3910_config(struct mcp3911 *adc)
|
||||
return ret;
|
||||
|
||||
regval &= ~MCP3910_CONFIG1_VREFEXT;
|
||||
if (adc->vref) {
|
||||
if (external_vref) {
|
||||
dev_dbg(dev, "use external voltage reference\n");
|
||||
regval |= FIELD_PREP(MCP3910_CONFIG1_VREFEXT, 1);
|
||||
} else {
|
||||
@ -677,11 +664,6 @@ static int mcp3910_config(struct mcp3911 *adc)
|
||||
return adc->chip->enable_offset(adc, 0);
|
||||
}
|
||||
|
||||
static void mcp3911_cleanup_regulator(void *vref)
|
||||
{
|
||||
regulator_disable(vref);
|
||||
}
|
||||
|
||||
static int mcp3911_set_trigger_state(struct iio_trigger *trig, bool enable)
|
||||
{
|
||||
struct mcp3911 *adc = iio_trigger_get_drvdata(trig);
|
||||
@ -704,6 +686,8 @@ static int mcp3911_probe(struct spi_device *spi)
|
||||
struct device *dev = &spi->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct mcp3911 *adc;
|
||||
bool external_vref;
|
||||
u32 vref_mv;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
|
||||
@ -714,23 +698,12 @@ static int mcp3911_probe(struct spi_device *spi)
|
||||
adc->spi = spi;
|
||||
adc->chip = spi_get_device_match_data(spi);
|
||||
|
||||
adc->vref = devm_regulator_get_optional(dev, "vref");
|
||||
if (IS_ERR(adc->vref)) {
|
||||
if (PTR_ERR(adc->vref) == -ENODEV) {
|
||||
adc->vref = NULL;
|
||||
} else {
|
||||
return dev_err_probe(dev, PTR_ERR(adc->vref), "failed to get regulator\n");
|
||||
}
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, "vref");
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret, "failed to get vref voltage\n");
|
||||
|
||||
} else {
|
||||
ret = regulator_enable(adc->vref);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, mcp3911_cleanup_regulator, adc->vref);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
external_vref = ret != -ENODEV;
|
||||
vref_mv = external_vref ? ret / 1000 : MCP3911_INT_VREF_MV;
|
||||
|
||||
adc->clki = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(adc->clki)) {
|
||||
@ -755,11 +728,11 @@ static int mcp3911_probe(struct spi_device *spi)
|
||||
}
|
||||
dev_dbg(dev, "use device address %i\n", adc->dev_addr);
|
||||
|
||||
ret = adc->chip->config(adc);
|
||||
ret = adc->chip->config(adc, external_vref);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mcp3911_calc_scale_table(adc);
|
||||
ret = mcp3911_calc_scale_table(vref_mv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -268,7 +268,7 @@ static irqreturn_t mt6360_adc_trigger_handler(int irq, void *p)
|
||||
int i = 0, bit, val, ret;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
ret = mt6360_adc_read_channel(mad, bit, &val);
|
||||
if (ret < 0) {
|
||||
dev_warn(&indio_dev->dev, "Failed to get channel %d conversion val\n", bit);
|
||||
|
1261
drivers/iio/adc/pac1921.c
Normal file
1261
drivers/iio/adc/pac1921.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -370,7 +370,7 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
for_each_set_bit(i, i_dev->active_scan_mask, i_dev->masklength) {
|
||||
iio_for_each_active_channel(i_dev, i) {
|
||||
const struct iio_chan_spec *chan = &i_dev->channels[i];
|
||||
|
||||
ret = rockchip_saradc_conversion(info, chan);
|
||||
|
@ -643,7 +643,7 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p)
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
unsigned int addr = rtq6056_channels[bit].address;
|
||||
|
||||
ret = regmap_read(priv->regmap, addr, &raw);
|
||||
|
@ -6,11 +6,14 @@
|
||||
* Author: Arnaud Pouliquen <arnaud.pouliquen@st.com>.
|
||||
*/
|
||||
|
||||
#include <linux/iio/backend.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
static const struct iio_info iio_sd_mod_iio_info;
|
||||
|
||||
@ -24,7 +27,59 @@ static const struct iio_chan_spec iio_sd_mod_ch = {
|
||||
},
|
||||
};
|
||||
|
||||
static int iio_sd_mod_probe(struct platform_device *pdev)
|
||||
struct iio_sd_backend_priv {
|
||||
struct regulator *vref;
|
||||
int vref_mv;
|
||||
};
|
||||
|
||||
static int iio_sd_mod_enable(struct iio_backend *backend)
|
||||
{
|
||||
struct iio_sd_backend_priv *priv = iio_backend_get_priv(backend);
|
||||
|
||||
if (priv->vref)
|
||||
return regulator_enable(priv->vref);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static void iio_sd_mod_disable(struct iio_backend *backend)
|
||||
{
|
||||
struct iio_sd_backend_priv *priv = iio_backend_get_priv(backend);
|
||||
|
||||
if (priv->vref)
|
||||
regulator_disable(priv->vref);
|
||||
};
|
||||
|
||||
static int iio_sd_mod_read(struct iio_backend *backend, struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct iio_sd_backend_priv *priv = iio_backend_get_priv(backend);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = priv->vref_mv;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = 0;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
};
|
||||
|
||||
static const struct iio_backend_ops sd_backend_ops = {
|
||||
.enable = iio_sd_mod_enable,
|
||||
.disable = iio_sd_mod_disable,
|
||||
.read_raw = iio_sd_mod_read,
|
||||
};
|
||||
|
||||
static const struct iio_backend_info sd_backend_info = {
|
||||
.name = "sd-modulator",
|
||||
.ops = &sd_backend_ops,
|
||||
};
|
||||
|
||||
static int iio_sd_mod_register(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct iio_dev *iio;
|
||||
@ -45,6 +100,45 @@ static int iio_sd_mod_probe(struct platform_device *pdev)
|
||||
return devm_iio_device_register(&pdev->dev, iio);
|
||||
}
|
||||
|
||||
static int iio_sd_mod_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct regulator *vref;
|
||||
struct iio_sd_backend_priv *priv;
|
||||
int ret;
|
||||
|
||||
/* If sd modulator is not defined as an IIO backend device, fallback to legacy */
|
||||
if (!device_property_present(dev, "#io-backend-cells"))
|
||||
return iio_sd_mod_register(pdev);
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Get regulator reference if any, but don't enable regulator right now.
|
||||
* Rely on enable and disable callbacks to manage regulator power.
|
||||
*/
|
||||
vref = devm_regulator_get_optional(dev, "vref");
|
||||
if (IS_ERR(vref)) {
|
||||
if (PTR_ERR(vref) != -ENODEV)
|
||||
return dev_err_probe(dev, PTR_ERR(vref), "Failed to get vref\n");
|
||||
} else {
|
||||
/*
|
||||
* Retrieve voltage right now, as regulator_get_voltage() provides it whatever
|
||||
* the state of the regulator.
|
||||
*/
|
||||
ret = regulator_get_voltage(vref);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->vref = vref;
|
||||
priv->vref_mv = ret / 1000;
|
||||
}
|
||||
|
||||
return devm_iio_backend_register(&pdev->dev, &sd_backend_info, priv);
|
||||
};
|
||||
|
||||
static const struct of_device_id sd_adc_of_match[] = {
|
||||
{ .compatible = "sd-modulator" },
|
||||
{ .compatible = "ads1201" },
|
||||
@ -65,3 +159,4 @@ module_platform_driver(iio_sd_mod_adc);
|
||||
MODULE_DESCRIPTION("Basic sigma delta modulator");
|
||||
MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_IMPORT_NS(IIO_BACKEND);
|
||||
|
@ -1261,7 +1261,7 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev,
|
||||
stm32_adc_writel(adc, adc->cfg->regs->smpr[0], adc->smpr_val[0]);
|
||||
stm32_adc_writel(adc, adc->cfg->regs->smpr[1], adc->smpr_val[1]);
|
||||
|
||||
for_each_set_bit(bit, scan_mask, indio_dev->masklength) {
|
||||
for_each_set_bit(bit, scan_mask, iio_get_masklength(indio_dev)) {
|
||||
chan = indio_dev->channels + bit;
|
||||
/*
|
||||
* Assign one channel per SQ entry in regular
|
||||
@ -1619,7 +1619,7 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
adc->num_conv = bitmap_weight(scan_mask, indio_dev->masklength);
|
||||
adc->num_conv = bitmap_weight(scan_mask, iio_get_masklength(indio_dev));
|
||||
|
||||
ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/iio/adc/stm32-dfsdm-adc.h>
|
||||
#include <linux/iio/backend.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/hw-consumer.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -78,6 +79,7 @@ struct stm32_dfsdm_adc {
|
||||
/* ADC specific */
|
||||
unsigned int oversamp;
|
||||
struct iio_hw_consumer *hwc;
|
||||
struct iio_backend **backend;
|
||||
struct completion completion;
|
||||
u32 *buffer;
|
||||
|
||||
@ -666,6 +668,74 @@ static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_generic_channel_parse_of(struct stm32_dfsdm *dfsdm,
|
||||
struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *ch,
|
||||
struct fwnode_handle *node)
|
||||
{
|
||||
struct stm32_dfsdm_channel *df_ch;
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
struct iio_backend *backend;
|
||||
const char *of_str;
|
||||
int ret, val;
|
||||
|
||||
ret = fwnode_property_read_u32(node, "reg", &ch->channel);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Missing channel index %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ch->channel >= dfsdm->num_chs) {
|
||||
dev_err(&indio_dev->dev, " Error bad channel number %d (max = %d)\n",
|
||||
ch->channel, dfsdm->num_chs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = fwnode_property_read_string(node, "label", &ch->datasheet_name);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev,
|
||||
" Error parsing 'label' for idx %d\n", ch->channel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
df_ch = &dfsdm->ch_list[ch->channel];
|
||||
df_ch->id = ch->channel;
|
||||
|
||||
ret = fwnode_property_read_string(node, "st,adc-channel-type", &of_str);
|
||||
if (!ret) {
|
||||
val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_type);
|
||||
if (val < 0)
|
||||
return val;
|
||||
} else {
|
||||
val = 0;
|
||||
}
|
||||
df_ch->type = val;
|
||||
|
||||
ret = fwnode_property_read_string(node, "st,adc-channel-clk-src", &of_str);
|
||||
if (!ret) {
|
||||
val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_src);
|
||||
if (val < 0)
|
||||
return val;
|
||||
} else {
|
||||
val = 0;
|
||||
}
|
||||
df_ch->src = val;
|
||||
|
||||
ret = fwnode_property_read_u32(node, "st,adc-alt-channel", &df_ch->alt_si);
|
||||
if (ret != -EINVAL)
|
||||
df_ch->alt_si = 0;
|
||||
|
||||
if (adc->dev_data->type == DFSDM_IIO) {
|
||||
backend = devm_iio_backend_fwnode_get(&indio_dev->dev, NULL, node);
|
||||
if (IS_ERR(backend))
|
||||
return dev_err_probe(&indio_dev->dev, PTR_ERR(backend),
|
||||
"Failed to get backend\n");
|
||||
adc->backend[ch->scan_index] = backend;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev,
|
||||
uintptr_t priv,
|
||||
const struct iio_chan_spec *chan,
|
||||
@ -987,7 +1057,7 @@ static int stm32_dfsdm_update_scan_mode(struct iio_dev *indio_dev,
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
adc->nconv = bitmap_weight(scan_mask, indio_dev->masklength);
|
||||
adc->nconv = bitmap_weight(scan_mask, iio_get_masklength(indio_dev));
|
||||
adc->smask = *scan_mask;
|
||||
|
||||
dev_dbg(&indio_dev->dev, "nconv=%d mask=%lx\n", adc->nconv, *scan_mask);
|
||||
@ -998,6 +1068,7 @@ static int stm32_dfsdm_update_scan_mode(struct iio_dev *indio_dev,
|
||||
static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
int i = 0;
|
||||
int ret;
|
||||
|
||||
/* Reset adc buffer index */
|
||||
@ -1009,6 +1080,15 @@ static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (adc->backend) {
|
||||
while (adc->backend[i]) {
|
||||
ret = iio_backend_enable(adc->backend[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
ret = stm32_dfsdm_start_dfsdm(adc->dfsdm);
|
||||
if (ret < 0)
|
||||
goto err_stop_hwc;
|
||||
@ -1041,6 +1121,7 @@ err_stop_hwc:
|
||||
static int stm32_dfsdm_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
int i = 0;
|
||||
|
||||
stm32_dfsdm_stop_conv(indio_dev);
|
||||
|
||||
@ -1048,6 +1129,13 @@ static int stm32_dfsdm_predisable(struct iio_dev *indio_dev)
|
||||
|
||||
stm32_dfsdm_stop_dfsdm(adc->dfsdm);
|
||||
|
||||
if (adc->backend) {
|
||||
while (adc->backend[i]) {
|
||||
iio_backend_disable(adc->backend[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (adc->hwc)
|
||||
iio_hw_consumer_disable(adc->hwc);
|
||||
|
||||
@ -1220,14 +1308,25 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
|
||||
struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast];
|
||||
u32 max = flo->max << (flo->lshift - chan->scan_type.shift);
|
||||
int idx = chan->scan_index;
|
||||
int ret;
|
||||
|
||||
if (flo->lshift < chan->scan_type.shift)
|
||||
max = flo->max >> (chan->scan_type.shift - flo->lshift);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = iio_hw_consumer_enable(adc->hwc);
|
||||
if (adc->hwc)
|
||||
ret = iio_hw_consumer_enable(adc->hwc);
|
||||
if (adc->backend)
|
||||
ret = iio_backend_enable(adc->backend[idx]);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"%s: IIO enable failed (channel %d)\n",
|
||||
@ -1236,7 +1335,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
}
|
||||
ret = stm32_dfsdm_single_conv(indio_dev, chan, val);
|
||||
iio_hw_consumer_disable(adc->hwc);
|
||||
if (adc->hwc)
|
||||
iio_hw_consumer_disable(adc->hwc);
|
||||
if (adc->backend)
|
||||
iio_backend_disable(adc->backend[idx]);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"%s: Conversion failed (channel %d)\n",
|
||||
@ -1256,6 +1358,50 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
|
||||
*val = adc->sample_freq;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
/*
|
||||
* Scale is expressed in mV.
|
||||
* When fast mode is disabled, actual resolution may be lower
|
||||
* than 2^n, where n = realbits - 1.
|
||||
* This leads to underestimating the input voltage.
|
||||
* To compensate this deviation, the voltage reference can be
|
||||
* corrected with a factor = realbits resolution / actual max
|
||||
*/
|
||||
if (adc->backend) {
|
||||
ret = iio_backend_read_scale(adc->backend[idx], chan, val, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = div_u64((u64)*val * (u64)BIT(DFSDM_DATA_RES - 1), max);
|
||||
*val2 = chan->scan_type.realbits;
|
||||
if (chan->differential)
|
||||
*val *= 2;
|
||||
}
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
/*
|
||||
* DFSDM output data are in the range [-2^n, 2^n],
|
||||
* with n = realbits - 1.
|
||||
* - Differential modulator:
|
||||
* Offset correspond to SD modulator offset.
|
||||
* - Single ended modulator:
|
||||
* Input is in [0V, Vref] range,
|
||||
* where 0V corresponds to -2^n, and Vref to 2^n.
|
||||
* Add 2^n to offset. (i.e. middle of input range)
|
||||
* offset = offset(sd) * vref / res(sd) * max / vref.
|
||||
*/
|
||||
if (adc->backend) {
|
||||
ret = iio_backend_read_offset(adc->backend[idx], chan, val, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = div_u64((u64)max * *val, BIT(*val2 - 1));
|
||||
if (!chan->differential)
|
||||
*val += max;
|
||||
}
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
@ -1362,15 +1508,18 @@ static int stm32_dfsdm_dma_request(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *ch)
|
||||
static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, struct iio_chan_spec *ch,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = stm32_dfsdm_channel_parse_of(adc->dfsdm, indio_dev, ch);
|
||||
if (child)
|
||||
ret = stm32_dfsdm_generic_channel_parse_of(adc->dfsdm, indio_dev, ch, child);
|
||||
else /* Legacy binding */
|
||||
ret = stm32_dfsdm_channel_parse_of(adc->dfsdm, indio_dev, ch);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return dev_err_probe(&indio_dev->dev, ret, "Failed to parse channel\n");
|
||||
|
||||
ch->type = IIO_VOLTAGE;
|
||||
ch->indexed = 1;
|
||||
@ -1379,12 +1528,21 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
|
||||
* IIO_CHAN_INFO_RAW: used to compute regular conversion
|
||||
* IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling
|
||||
*/
|
||||
ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
|
||||
if (child) {
|
||||
ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET);
|
||||
} else {
|
||||
/* Legacy. Scaling not supported */
|
||||
ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
|
||||
}
|
||||
|
||||
ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ);
|
||||
|
||||
if (adc->dev_data->type == DFSDM_AUDIO) {
|
||||
ch->ext_info = dfsdm_adc_audio_ext_info;
|
||||
ch->scan_index = 0;
|
||||
} else {
|
||||
ch->scan_type.shift = 8;
|
||||
}
|
||||
@ -1396,20 +1554,67 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
|
||||
&adc->dfsdm->ch_list[ch->channel]);
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_chan_init(struct iio_dev *indio_dev, struct iio_chan_spec *channels)
|
||||
{
|
||||
int num_ch = indio_dev->num_channels;
|
||||
int chan_idx = 0;
|
||||
int ret;
|
||||
|
||||
for (chan_idx = 0; chan_idx < num_ch; chan_idx++) {
|
||||
channels[chan_idx].scan_index = chan_idx;
|
||||
ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &channels[chan_idx], NULL);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&indio_dev->dev, ret, "Channels init failed\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_generic_chan_init(struct iio_dev *indio_dev, struct iio_chan_spec *channels)
|
||||
{
|
||||
int chan_idx = 0, ret;
|
||||
|
||||
device_for_each_child_node_scoped(&indio_dev->dev, child) {
|
||||
/* Skip DAI node in DFSDM audio nodes */
|
||||
if (fwnode_property_present(child, "compatible"))
|
||||
continue;
|
||||
|
||||
channels[chan_idx].scan_index = chan_idx;
|
||||
ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &channels[chan_idx], child);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&indio_dev->dev, ret, "Channels init failed\n");
|
||||
|
||||
chan_idx++;
|
||||
}
|
||||
|
||||
return chan_idx;
|
||||
}
|
||||
|
||||
static int stm32_dfsdm_audio_init(struct device *dev, struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_chan_spec *ch;
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
struct stm32_dfsdm_channel *d_ch;
|
||||
int ret;
|
||||
bool legacy = false;
|
||||
int num_ch, ret;
|
||||
|
||||
/* If st,adc-channels is defined legacy binding is used. Else assume generic binding. */
|
||||
num_ch = of_property_count_u32_elems(indio_dev->dev.of_node, "st,adc-channels");
|
||||
if (num_ch == 1)
|
||||
legacy = true;
|
||||
|
||||
ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL);
|
||||
if (!ch)
|
||||
return -ENOMEM;
|
||||
|
||||
ch->scan_index = 0;
|
||||
indio_dev->num_channels = 1;
|
||||
indio_dev->channels = ch;
|
||||
|
||||
if (legacy)
|
||||
ret = stm32_dfsdm_chan_init(indio_dev, ch);
|
||||
else
|
||||
ret = stm32_dfsdm_generic_chan_init(indio_dev, ch);
|
||||
|
||||
ret = stm32_dfsdm_adc_chan_init_one(indio_dev, ch);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Channels init failed\n");
|
||||
return ret;
|
||||
@ -1420,9 +1625,6 @@ static int stm32_dfsdm_audio_init(struct device *dev, struct iio_dev *indio_dev)
|
||||
if (d_ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL)
|
||||
adc->spi_freq = adc->dfsdm->spi_master_freq;
|
||||
|
||||
indio_dev->num_channels = 1;
|
||||
indio_dev->channels = ch;
|
||||
|
||||
return stm32_dfsdm_dma_request(dev, indio_dev);
|
||||
}
|
||||
|
||||
@ -1430,43 +1632,61 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_chan_spec *ch;
|
||||
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
|
||||
int num_ch;
|
||||
int ret, chan_idx;
|
||||
int num_ch, ret;
|
||||
bool legacy = false;
|
||||
|
||||
adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING;
|
||||
ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
num_ch = of_property_count_u32_elems(indio_dev->dev.of_node,
|
||||
"st,adc-channels");
|
||||
if (num_ch < 0 || num_ch > adc->dfsdm->num_chs) {
|
||||
dev_err(&indio_dev->dev, "Bad st,adc-channels\n");
|
||||
return num_ch < 0 ? num_ch : -EINVAL;
|
||||
num_ch = device_get_child_node_count(&indio_dev->dev);
|
||||
if (!num_ch) {
|
||||
/* No channels nodes found. Assume legacy binding */
|
||||
num_ch = of_property_count_u32_elems(indio_dev->dev.of_node, "st,adc-channels");
|
||||
if (num_ch < 0) {
|
||||
dev_err(&indio_dev->dev, "Bad st,adc-channels\n");
|
||||
return num_ch;
|
||||
}
|
||||
|
||||
legacy = true;
|
||||
}
|
||||
|
||||
/* Bind to SD modulator IIO device */
|
||||
adc->hwc = devm_iio_hw_consumer_alloc(&indio_dev->dev);
|
||||
if (IS_ERR(adc->hwc))
|
||||
return -EPROBE_DEFER;
|
||||
if (num_ch > adc->dfsdm->num_chs) {
|
||||
dev_err(&indio_dev->dev, "Number of channel [%d] exceeds [%d]\n",
|
||||
num_ch, adc->dfsdm->num_chs);
|
||||
return -EINVAL;
|
||||
}
|
||||
indio_dev->num_channels = num_ch;
|
||||
|
||||
ch = devm_kcalloc(&indio_dev->dev, num_ch, sizeof(*ch),
|
||||
GFP_KERNEL);
|
||||
if (legacy) {
|
||||
/* Bind to SD modulator IIO device. */
|
||||
adc->hwc = devm_iio_hw_consumer_alloc(&indio_dev->dev);
|
||||
if (IS_ERR(adc->hwc))
|
||||
return dev_err_probe(&indio_dev->dev, -EPROBE_DEFER,
|
||||
"waiting for SD modulator\n");
|
||||
} else {
|
||||
/* Generic binding. SD modulator IIO device not used. Use SD modulator backend. */
|
||||
adc->hwc = NULL;
|
||||
|
||||
adc->backend = devm_kcalloc(&indio_dev->dev, num_ch, sizeof(*adc->backend),
|
||||
GFP_KERNEL);
|
||||
if (!adc->backend)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ch = devm_kcalloc(&indio_dev->dev, num_ch, sizeof(*ch), GFP_KERNEL);
|
||||
if (!ch)
|
||||
return -ENOMEM;
|
||||
|
||||
for (chan_idx = 0; chan_idx < num_ch; chan_idx++) {
|
||||
ch[chan_idx].scan_index = chan_idx;
|
||||
ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Channels init failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
indio_dev->num_channels = num_ch;
|
||||
indio_dev->channels = ch;
|
||||
|
||||
if (legacy)
|
||||
ret = stm32_dfsdm_chan_init(indio_dev, ch);
|
||||
else
|
||||
ret = stm32_dfsdm_generic_chan_init(indio_dev, ch);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
init_completion(&adc->completion);
|
||||
|
||||
/* Optionally request DMA */
|
||||
@ -1677,3 +1897,4 @@ module_platform_driver(stm32_dfsdm_adc_driver);
|
||||
MODULE_DESCRIPTION("STM32 sigma delta ADC");
|
||||
MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_IMPORT_NS(IIO_BACKEND);
|
||||
|
@ -211,8 +211,7 @@ static irqreturn_t adc0832_trigger_handler(int irq, void *p)
|
||||
|
||||
mutex_lock(&adc->lock);
|
||||
|
||||
for_each_set_bit(scan_index, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
iio_for_each_active_channel(indio_dev, scan_index) {
|
||||
const struct iio_chan_spec *scan_chan =
|
||||
&indio_dev->channels[scan_index];
|
||||
int ret = adc0832_adc_conversion(adc, scan_chan->channel,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user