First set of new device support, features and cleanup for IIO in 5.10 cycle, take 2
A few changes to how I write this cover letter. * Started to use manufacturer prefixes to group changes better. * Stop list minor formatting etc changes. * Whilst I appreciate those changes, we don't need to call them out here. New device support: * adi,adxrs290 - New driver for this gyroscope with dt bindings. One fix follows. * ams,as73211 - New driver for this colour sensor with dt bindings. Also includes docs for XYZ modifiers as used for the CIE colour space. Sysfs docs. * atlas,atlas-ezo-sensor - Support O_2 sensor, includes new modifier for concentration. - Support humidity sensor. * ti,hdc2010 - New driver support hdc2010 and hdc2080 humidity sensors. Includes dt bindings. Cleanup, minor fixes and features * core - Make the trigger related stub functions static inline, avoiding some build warnings. - buffer-dmaengine. Allow adjusting bytes_used with residue info. * dev_error_probe to replace open coded equivalent in many drivers. * docs and comment fixes - Fix some typos, doubled words, capitalisation and punctuation. * dt binding conversions to yaml - lltc,ltc2497 - lltc,ltc2632 - maxim,max11100 - maxim,max1118 - maxim,max9611 - microchip,mcp3201 - microchip,mcp342x (add to trivial devices) - ti,adc0832 - ti,adc108s102 - ti,adc128s052 - ti,adc161s626 - ti,ads8344 - ti,tlc4541 (includes adding an accidentally dropped original binding doc) * adi,adi-axi-adc - Use kobj_to_dev instead of open coding. * adi,ad5686 - Constify iio_chan_spec * adi,ad8366 - Add HMC1119 to kconfig help text as the driver supports it. * adi,ad9523 - Use devm for reset of probe and drop remove. * adi,adxl372 - Tidy up alignment - Add OF table - Add peak mode support with some docs. * bosch,bma220 (general tidy up) - Fix some return codes. - Use read_avail callback rather than open coding attrs. - Use dev_get_drvdata rather than dance via to_spi_device() - Mark PM functions as __maybe_unused rather than #ifdef fun. - Drop ACPI_PTR protections and ifdefs. - Tidy up header ordering. - BIT and GENMASK * broadcom,bcm_iproc - Drop of_match_ptr protection and switch to mod_devicetable.h Part of general move to get this anti-pattern out of IIO. * melexis,mlx90614 - Simplify some calculations. - Add some kernel_doc - Use regmap poll loop rather than open coding. - Add extended calibration option. * sensortec,sx9310, wide ranging set of fixes and cleanups. - Document dt-binding. - Rename some macros to align better with spec sheet - Fix some issues with irq handling. - Drop of_match_ptr and ACPI_PTR macros to avoid unused warnings etc. - Switch to probe_new - Fix memory alignment for iio_push_to_buffers_with_timestamp() - Use long for bitmaps to allow use of for_each_bit_set() - Use regmap_read_poll instead of opencoding. - Simplify error paths - Enabled regulators at probe. - Use trigger flags from firmware rather than forcing them in the driver. * ti,adc081c - Drop ACPI IDs that are not likely to be official ones and we don't believe anyone is using. * ti,adc108s102 - Drop CONFIG_OF and of_match_ptr protections. * ti,adc128s052 - Drop of_match_ptr protection and include mod_devicetable.h * ti,dac5571 - Support powerdown for mutlichannel usecases. * xpowers,axp20x - Convert from OF to generic fw / device properties. Unlikely anyone will use this with anything other than devicetree, but this is part of a general move across IIO. -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAl9U+zMRHGppYzIzQGtl cm5lbC5vcmcACgkQVIU0mcT0Foj3yg/9HEDBSqrl8ETvQaUTvik4v53wpm/NqbXe ykfNhOrir8uTxDt9WT7cQeg6uRRJetUy7w17H3we+wCVNlJYXZ7dMuLC6uABGWLx SBV4iGb6E/yVtnreqbvotoHQwIRvRHE55pU4CgzNjB/VU1lSRvFtKMrVgSCwQtPE wavTF6TN5WOrp17nRWuit/WXqBMZZZgh5RRELzSTDbsKrJg6d6Qc8wzFotajIsng hqgd/RF0y1d1cj2b21J5tHtG5SIrzc8g//jtM/5GI4mrpJmVvfjsFc4O8w/8XALk qALvL5j3cnOp8dmq/i6vBAazkt3y2+5yRYAa7S0NUgTdfgzRxOIwhDrY7iOc0kWQ /fbrs+WVRDkOdQaA1XRNiOLax8R+5cZwOwALKUJXB+KXbsh7LABUd31mDRHZrtXa uArwOVz2+3Cs2BtdtGyL90xWpzq+b6NzcRpr5BODsW3dKXpgVGXH6A5AHjFFt8tp 9XDiQ/4rhWqwrDh0HTUqOYFVZJiRW/+rEz9gBhgJjmBpBBw8GonilVPtB5s/rl4b /WoFKeXSGldc1qibej2xL1M7isKBTeu1FyVpXULP7XgM64+6qygY7OpUR0tjcu8o BPpgjuk/AlMkEC7M90ZylZvrVc7ClnDz4z3Kk9DHlg5ozoNNw/9/umvAn64A4Ysv JtfjSnONhBM= =7Vzn -----END PGP SIGNATURE----- Merge tag 'iio-for-5.10a-take2' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: First set of new device support, features and cleanup for IIO in 5.10 cycle, take 2 A few changes to how I write this cover letter. * Started to use manufacturer prefixes to group changes better. * Stop list minor formatting etc changes. * Whilst I appreciate those changes, we don't need to call them out here. New device support: * adi,adxrs290 - New driver for this gyroscope with dt bindings. One fix follows. * ams,as73211 - New driver for this colour sensor with dt bindings. Also includes docs for XYZ modifiers as used for the CIE colour space. Sysfs docs. * atlas,atlas-ezo-sensor - Support O_2 sensor, includes new modifier for concentration. - Support humidity sensor. * ti,hdc2010 - New driver support hdc2010 and hdc2080 humidity sensors. Includes dt bindings. Cleanup, minor fixes and features * core - Make the trigger related stub functions static inline, avoiding some build warnings. - buffer-dmaengine. Allow adjusting bytes_used with residue info. * dev_error_probe to replace open coded equivalent in many drivers. * docs and comment fixes - Fix some typos, doubled words, capitalisation and punctuation. * dt binding conversions to yaml - lltc,ltc2497 - lltc,ltc2632 - maxim,max11100 - maxim,max1118 - maxim,max9611 - microchip,mcp3201 - microchip,mcp342x (add to trivial devices) - ti,adc0832 - ti,adc108s102 - ti,adc128s052 - ti,adc161s626 - ti,ads8344 - ti,tlc4541 (includes adding an accidentally dropped original binding doc) * adi,adi-axi-adc - Use kobj_to_dev instead of open coding. * adi,ad5686 - Constify iio_chan_spec * adi,ad8366 - Add HMC1119 to kconfig help text as the driver supports it. * adi,ad9523 - Use devm for reset of probe and drop remove. * adi,adxl372 - Tidy up alignment - Add OF table - Add peak mode support with some docs. * bosch,bma220 (general tidy up) - Fix some return codes. - Use read_avail callback rather than open coding attrs. - Use dev_get_drvdata rather than dance via to_spi_device() - Mark PM functions as __maybe_unused rather than #ifdef fun. - Drop ACPI_PTR protections and ifdefs. - Tidy up header ordering. - BIT and GENMASK * broadcom,bcm_iproc - Drop of_match_ptr protection and switch to mod_devicetable.h Part of general move to get this anti-pattern out of IIO. * melexis,mlx90614 - Simplify some calculations. - Add some kernel_doc - Use regmap poll loop rather than open coding. - Add extended calibration option. * sensortec,sx9310, wide ranging set of fixes and cleanups. - Document dt-binding. - Rename some macros to align better with spec sheet - Fix some issues with irq handling. - Drop of_match_ptr and ACPI_PTR macros to avoid unused warnings etc. - Switch to probe_new - Fix memory alignment for iio_push_to_buffers_with_timestamp() - Use long for bitmaps to allow use of for_each_bit_set() - Use regmap_read_poll instead of opencoding. - Simplify error paths - Enabled regulators at probe. - Use trigger flags from firmware rather than forcing them in the driver. * ti,adc081c - Drop ACPI IDs that are not likely to be official ones and we don't believe anyone is using. * ti,adc108s102 - Drop CONFIG_OF and of_match_ptr protections. * ti,adc128s052 - Drop of_match_ptr protection and include mod_devicetable.h * ti,dac5571 - Support powerdown for mutlichannel usecases. * xpowers,axp20x - Convert from OF to generic fw / device properties. Unlikely anyone will use this with anything other than devicetree, but this is part of a general move across IIO. * tag 'iio-for-5.10a-take2' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (96 commits) drivers/iio/humidity/hdc2010.c:305:2-3: Unneeded semicolon iio: accel: bma220: Remove unneeded blank lines iio: accel: bma220: Use BIT() and GENMASK() macros iio: accel: bma220: Group IIO headers together iio: accel: bma220: Drop ACPI_PTR() and accompanying ifdeffery iio: accel: bma220: Mark PM functions as __maybe_unused iio: accel: bma220: Use dev_get_drvdata() directly iio: accel: bma220: Convert to use ->read_avail() iio: accel: bma220: Fix returned codes from bma220_init(), bma220_deinit() dt-bindings: iio: adc: microchip,mcp3201 yaml conversion. iio: buffer-dmaengine: adjust `bytes_used` with residue info dt-bindings: iio: adc: ti,tlc4541 binding conversion dt-bindings: iio: adc: tlc4541 - recover accidentally dropped binding doc dt-bindings: iio: adc: ti,ads8344 yaml conversion dt-bindings: iio: adc: ti,adc128s052 yaml conversion. dt-bindings: iio: adc: ti,adc0832 yaml conversion. dt-bindings: iio: adc: ti,adc161s626 yaml conversion. dt-bindings: iio: adc: lltc,ltc2497 yaml conversion. dt-bindings: iio: adc: ti,adc108s102 yaml conversion dt-bindings: trivial-devices: Add mcp342x ADCs and drop separate binding doc. ...
This commit is contained in:
commit
e2664d0870
@ -40,6 +40,7 @@ Description:
|
||||
buffered samples and events for device X.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/sampling_frequency
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_sampling_frequency
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/sampling_frequency
|
||||
What: /sys/bus/iio/devices/triggerX/sampling_frequency
|
||||
KernelVersion: 2.6.35
|
||||
@ -49,12 +50,13 @@ Description:
|
||||
resulting sampling frequency. In many devices this
|
||||
parameter has an effect on input filters etc. rather than
|
||||
simply controlling when the input is sampled. As this
|
||||
effects data ready triggers, hardware buffers and the sysfs
|
||||
affects data ready triggers, hardware buffers and the sysfs
|
||||
direct access interfaces, it may be found in any of the
|
||||
relevant directories. If it effects all of the above
|
||||
relevant directories. If it affects all of the above
|
||||
then it is to be found in the base device directory.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/sampling_frequency_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_sampling_frequency_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity_sampling_frequency_available
|
||||
What: /sys/.../iio:deviceX/buffer/sampling_frequency_available
|
||||
What: /sys/bus/iio/devices/triggerX/sampling_frequency_available
|
||||
@ -374,6 +376,9 @@ What: /sys/bus/iio/devices/iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_countY_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_angl_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_x_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_y_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_z_scale
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
@ -401,21 +406,21 @@ Description:
|
||||
Hardware applied calibration offset (assumed to fix production
|
||||
inaccuracies).
|
||||
|
||||
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_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_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_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_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_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_illuminance_calibscale
|
||||
@ -483,7 +488,8 @@ Description:
|
||||
If a discrete set of scale values is available, they
|
||||
are listed in this attribute.
|
||||
|
||||
What /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_hardwaregain
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_red_hardwaregain
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_hardwaregain
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_hardwaregain
|
||||
@ -494,6 +500,13 @@ Description:
|
||||
Hardware applied gain factor. If shared across all channels,
|
||||
<type>_hardwaregain is used.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_hardwaregain_available
|
||||
KernelVersion: 5.10
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Lists all available hardware applied gain factors. Shared across all
|
||||
channels.
|
||||
|
||||
What: /sys/.../in_accel_filter_low_pass_3db_frequency
|
||||
What: /sys/.../in_magn_filter_low_pass_3db_frequency
|
||||
What: /sys/.../in_anglvel_filter_low_pass_3db_frequency
|
||||
@ -750,9 +763,9 @@ What: /sys/.../events/in_voltageY_raw_thresh_falling_value
|
||||
What: /sys/.../events/in_tempY_raw_thresh_rising_value
|
||||
What: /sys/.../events/in_tempY_raw_thresh_falling_value
|
||||
What: /sys/.../events/in_illuminance0_thresh_falling_value
|
||||
what: /sys/.../events/in_illuminance0_thresh_rising_value
|
||||
what: /sys/.../events/in_proximity0_thresh_falling_value
|
||||
what: /sys/.../events/in_proximity0_thresh_rising_value
|
||||
What: /sys/.../events/in_illuminance0_thresh_rising_value
|
||||
What: /sys/.../events/in_proximity0_thresh_falling_value
|
||||
What: /sys/.../events/in_proximity0_thresh_rising_value
|
||||
What: /sys/.../events/in_illuminance_thresh_rising_value
|
||||
What: /sys/.../events/in_illuminance_thresh_falling_value
|
||||
KernelVersion: 2.6.37
|
||||
@ -832,11 +845,11 @@ What: /sys/.../events/in_tempY_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_tempY_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_tempY_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_illuminance0_thresh_falling_hysteresis
|
||||
what: /sys/.../events/in_illuminance0_thresh_rising_hysteresis
|
||||
what: /sys/.../events/in_illuminance0_thresh_either_hysteresis
|
||||
what: /sys/.../events/in_proximity0_thresh_falling_hysteresis
|
||||
what: /sys/.../events/in_proximity0_thresh_rising_hysteresis
|
||||
what: /sys/.../events/in_proximity0_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_illuminance0_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_illuminance0_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_proximity0_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_proximity0_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_proximity0_thresh_either_hysteresis
|
||||
KernelVersion: 3.13
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
@ -1013,7 +1026,7 @@ What: /sys/.../events/in_activity_running_thresh_falling_en
|
||||
KernelVersion: 3.19
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Enables or disables activitity events. Depending on direction
|
||||
Enables or disables activity events. Depending on direction
|
||||
an event is generated when sensor ENTERS or LEAVES a given state.
|
||||
|
||||
What: /sys/.../events/in_activity_still_thresh_rising_value
|
||||
@ -1333,6 +1346,7 @@ Description:
|
||||
standardised CIE Erythemal Action Spectrum. UV index values range
|
||||
from 0 (low) to >=11 (extreme).
|
||||
|
||||
What: /sys/.../iio:deviceX/in_intensity_integration_time
|
||||
What: /sys/.../iio:deviceX/in_intensity_red_integration_time
|
||||
What: /sys/.../iio:deviceX/in_intensity_green_integration_time
|
||||
What: /sys/.../iio:deviceX/in_intensity_blue_integration_time
|
||||
@ -1342,7 +1356,8 @@ KernelVersion: 3.12
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This attribute is used to get/set the integration time in
|
||||
seconds.
|
||||
seconds. If shared across all channels of a given type,
|
||||
<type>_integration_time is used.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_integration_time
|
||||
KernelVersion: 4.0
|
||||
@ -1564,6 +1579,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_concentration_ethanol_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_ethanol_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_h2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_h2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_o2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_o2_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_voc_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_voc_raw
|
||||
KernelVersion: 4.3
|
||||
@ -1740,3 +1757,12 @@ KernelVersion: 5.5
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
One of the following thermocouple types: B, E, J, K, N, R, S, T.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_x_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_y_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_z_raw
|
||||
KernelVersion: 5.10
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Unscaled light intensity according to CIE 1931/DIN 5033 color space.
|
||||
Units after application of scale are nano nanowatts per square meter.
|
||||
|
7
Documentation/ABI/testing/sysfs-bus-iio-accel-adxl372
Normal file
7
Documentation/ABI/testing/sysfs-bus-iio-accel-adxl372
Normal file
@ -0,0 +1,7 @@
|
||||
What: /sys/bus/iio/devices/triggerX/name = "adxl372-devX-peak"
|
||||
KernelVersion:
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
The adxl372 accelerometer kernel module provides an additional trigger,
|
||||
which sets the device in a mode in which it will record only the peak acceleration
|
||||
sensed over the set period of time in the events sysfs.
|
9
Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc2010
Normal file
9
Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc2010
Normal file
@ -0,0 +1,9 @@
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw_available
|
||||
KernelVersion: 5.3.8
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Controls the heater device within the humidity sensor to get
|
||||
rid of excess condensation.
|
||||
|
||||
Valid control values are 0 = OFF, and 1 = ON.
|
44
Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml
Normal file
44
Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml
Normal file
@ -0,0 +1,44 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/lltc,ltc2497.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Linear Technology / Analog Devices LTC2497 ADC
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
|
||||
description: |
|
||||
16bit ADC supporting up to 16 single ended or 8 differential inputs.
|
||||
I2C interface.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const:
|
||||
lltc,ltc2497
|
||||
|
||||
reg: true
|
||||
vref-supply: true
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vref-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@76 {
|
||||
compatible = "lltc,ltc2497";
|
||||
reg = <0x76>;
|
||||
vref-supply = <<c2497_reg>;
|
||||
#io-channel-cells = <1>;
|
||||
};
|
||||
};
|
||||
...
|
@ -1,13 +0,0 @@
|
||||
* Linear Technology / Analog Devices LTC2497 ADC
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "lltc,ltc2497"
|
||||
- reg: Must contain the ADC I2C address
|
||||
- vref-supply: The regulator supply for ADC reference voltage
|
||||
|
||||
Example:
|
||||
ltc2497: adc@76 {
|
||||
compatible = "lltc,ltc2497";
|
||||
reg = <0x76>;
|
||||
vref-supply = <<c2497_reg>;
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
* Maxim max11100 Analog to Digital Converter (ADC)
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "maxim,max11100"
|
||||
- reg: the adc unit address
|
||||
- vref-supply: phandle to the regulator that provides reference voltage
|
||||
|
||||
Optional properties:
|
||||
- spi-max-frequency: SPI maximum frequency
|
||||
|
||||
Example:
|
||||
|
||||
max11100: adc@0 {
|
||||
compatible = "maxim,max11100";
|
||||
reg = <0>;
|
||||
vref-supply = <&adc0_vref>;
|
||||
spi-max-frequency = <240000>;
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
* MAX1117/MAX1118/MAX1119 8-bit, dual-channel ADCs
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of
|
||||
* "maxim,max1117"
|
||||
* "maxim,max1118"
|
||||
* "maxim,max1119"
|
||||
- reg: spi chip select number for the device
|
||||
- (max1118 only) vref-supply: The regulator supply for ADC reference voltage
|
||||
|
||||
Recommended properties:
|
||||
- spi-max-frequency: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
adc@0 {
|
||||
compatible = "maxim,max1118";
|
||||
reg = <0>;
|
||||
vref-supply = <&vdd_supply>;
|
||||
spi-max-frequency = <1000000>;
|
||||
};
|
@ -1,27 +0,0 @@
|
||||
* Maxim max9611/max9612 current sense amplifier with 12-bits ADC interface
|
||||
|
||||
Maxim max9611/max9612 is an high-side current sense amplifier with integrated
|
||||
12-bits ADC communicating over I2c bus.
|
||||
The device node for this driver shall be a child of a I2c controller.
|
||||
|
||||
Required properties
|
||||
- compatible: Should be "maxim,max9611" or "maxim,max9612"
|
||||
- reg: The 7-bits long I2c address of the device
|
||||
- shunt-resistor-micro-ohms: Value, in micro Ohms, of the current sense shunt
|
||||
resistor
|
||||
|
||||
Example:
|
||||
|
||||
&i2c4 {
|
||||
csa: adc@7c {
|
||||
compatible = "maxim,max9611";
|
||||
reg = <0x7c>;
|
||||
|
||||
shunt-resistor-micro-ohms = <5000>;
|
||||
};
|
||||
};
|
||||
|
||||
This device node describes a current sense amplifier sitting on I2c4 bus
|
||||
with address 0x7c (read address is 0xf9, write address is 0xf8).
|
||||
A sense resistor of 0,005 Ohm is installed between RS+ and RS- current-sensing
|
||||
inputs.
|
@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/maxim,max11100.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim MAX11100 ADC
|
||||
|
||||
maintainers:
|
||||
- Jacopo Mondi <jacopo@jmondi.org>
|
||||
|
||||
description: |
|
||||
Single channel 16 bit ADC with SPI interface.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: maxim,max11100
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vref-supply:
|
||||
description: External reference, needed to establish input scaling.
|
||||
|
||||
spi-max-frequency:
|
||||
minimum: 100000
|
||||
maximum: 4800000
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vref-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "maxim,max11100";
|
||||
reg = <0>;
|
||||
vref-supply = <&adc_vref>;
|
||||
spi-max-frequency = <240000>;
|
||||
};
|
||||
};
|
||||
...
|
62
Documentation/devicetree/bindings/iio/adc/maxim,max1118.yaml
Normal file
62
Documentation/devicetree/bindings/iio/adc/maxim,max1118.yaml
Normal file
@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/maxim,max1118.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim MAX1118 and similar ADCs
|
||||
|
||||
maintainers:
|
||||
- Akinobu Mita <akinobu.mita@gmail.com>
|
||||
|
||||
description: |
|
||||
Dual channel 8bit ADCs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- maxim,max1117
|
||||
- maxim,max1118
|
||||
- maxim,max1119
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 5000000
|
||||
|
||||
vref-supply:
|
||||
description: External reference, needed to establish input scaling
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: maxim,max1118
|
||||
then:
|
||||
required:
|
||||
- vref-supply
|
||||
else:
|
||||
properties:
|
||||
vref-supply: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "maxim,max1118";
|
||||
reg = <0>;
|
||||
vref-supply = <&adc_vref>;
|
||||
spi-max-frequency = <1000000>;
|
||||
};
|
||||
};
|
||||
...
|
51
Documentation/devicetree/bindings/iio/adc/maxim,max9611.yaml
Normal file
51
Documentation/devicetree/bindings/iio/adc/maxim,max9611.yaml
Normal file
@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/maxim,max9611.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim MAX9611 and similar current sense amplifiers with integrated ADCs
|
||||
|
||||
maintainers:
|
||||
- Jacopo Mondi <jacopo@jmondi.org>
|
||||
|
||||
description: |
|
||||
These devices combine a high-side current sense amplifier with a 12 bit ADC.
|
||||
They have an i2c interface.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- maxim,max9611
|
||||
- maxim,max9612
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
shunt-resistor-micro-ohms:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Value in micro Ohms of the shunt resistor connected between the RS+ and
|
||||
RS- inputs, across which the current is measured. Value needed to compute
|
||||
the scaling of the measured current.
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- shunt-resistor-micro-ohms
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@7c {
|
||||
compatible = "maxim,max9611";
|
||||
reg = <0x7c>;
|
||||
shunt-resistor-micro-ohms = <5000>;
|
||||
};
|
||||
};
|
||||
...
|
@ -1,57 +0,0 @@
|
||||
* Microchip Analog to Digital Converter (ADC)
|
||||
|
||||
The node for this driver must be a child node of a SPI controller, hence
|
||||
all mandatory properties described in
|
||||
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
must be specified.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be one of the following, depending on the
|
||||
model:
|
||||
"mcp3001" (DEPRECATED)
|
||||
"mcp3002" (DEPRECATED)
|
||||
"mcp3004" (DEPRECATED)
|
||||
"mcp3008" (DEPRECATED)
|
||||
"mcp3201" (DEPRECATED)
|
||||
"mcp3202" (DEPRECATED)
|
||||
"mcp3204" (DEPRECATED)
|
||||
"mcp3208" (DEPRECATED)
|
||||
"mcp3301" (DEPRECATED)
|
||||
|
||||
"microchip,mcp3001"
|
||||
"microchip,mcp3002"
|
||||
"microchip,mcp3004"
|
||||
"microchip,mcp3008"
|
||||
"microchip,mcp3201"
|
||||
"microchip,mcp3202"
|
||||
"microchip,mcp3204"
|
||||
"microchip,mcp3208"
|
||||
"microchip,mcp3301"
|
||||
"microchip,mcp3550-50"
|
||||
"microchip,mcp3550-60"
|
||||
"microchip,mcp3551"
|
||||
"microchip,mcp3553"
|
||||
|
||||
NOTE: The use of the compatibles with no vendor prefix
|
||||
is deprecated and only listed because old DT use them.
|
||||
|
||||
- spi-cpha, spi-cpol (boolean):
|
||||
Either SPI mode (0,0) or (1,1) must be used, so specify
|
||||
none or both of spi-cpha, spi-cpol. The MCP3550/1/3
|
||||
is more efficient in mode (1,1) as only 3 instead of
|
||||
4 bytes need to be read from the ADC, but not all SPI
|
||||
masters support it.
|
||||
|
||||
- vref-supply: Phandle to the external reference voltage supply.
|
||||
|
||||
Examples:
|
||||
spi_controller {
|
||||
mcp3x0x@0 {
|
||||
compatible = "microchip,mcp3002";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
vref-supply = <&vref_reg>;
|
||||
};
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
* Microchip mcp3421/2/3/4/6/7/8 chip family (ADC)
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be
|
||||
"microchip,mcp3421" or
|
||||
"microchip,mcp3422" or
|
||||
"microchip,mcp3423" or
|
||||
"microchip,mcp3424" or
|
||||
"microchip,mcp3425" or
|
||||
"microchip,mcp3426" or
|
||||
"microchip,mcp3427" or
|
||||
"microchip,mcp3428"
|
||||
- reg: I2C address for the device
|
||||
|
||||
Example:
|
||||
adc@0 {
|
||||
compatible = "microchip,mcp3424";
|
||||
reg = <0x68>;
|
||||
};
|
@ -0,0 +1,77 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/microchip,mcp3201.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip mcp3201 and similar ADCs
|
||||
|
||||
maintainers:
|
||||
- Oskar Andero <oskar.andero@gmail.com>
|
||||
|
||||
description: |
|
||||
Family of simple ADCs with an I2C inteface.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- microchip,mcp3001
|
||||
- microchip,mcp3002
|
||||
- microchip,mcp3004
|
||||
- microchip,mcp3008
|
||||
- microchip,mcp3201
|
||||
- microchip,mcp3202
|
||||
- microchip,mcp3204
|
||||
- microchip,mcp3208
|
||||
- microchip,mcp3301
|
||||
- microchip,mcp3550-50
|
||||
- microchip,mcp3550-60
|
||||
- microchip,mcp3551
|
||||
- microchip,mcp3553
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
spi-cpha: true
|
||||
spi-cpol: true
|
||||
|
||||
vref-supply:
|
||||
description: External reference.
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
dependencies:
|
||||
spi-cpol: [ spi-cpha ]
|
||||
spi-cpha: [ spi-cpol ]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vref-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "microchip,mcp3002";
|
||||
reg = <0>;
|
||||
vref-supply = <&vref_reg>;
|
||||
spi-cpha;
|
||||
spi-cpol;
|
||||
#io-channel-cells = <1>;
|
||||
};
|
||||
adc@1 {
|
||||
compatible = "microchip,mcp3002";
|
||||
reg = <1>;
|
||||
vref-supply = <&vref_reg>;
|
||||
spi-max-frequency = <1500000>;
|
||||
};
|
||||
};
|
||||
...
|
56
Documentation/devicetree/bindings/iio/adc/ti,adc0832.yaml
Normal file
56
Documentation/devicetree/bindings/iio/adc/ti,adc0832.yaml
Normal file
@ -0,0 +1,56 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/ti,adc0832.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments ADC0832 and similar ADCs
|
||||
|
||||
maintainers:
|
||||
- Akinobu Mita <akinobu.mita@gmail.com>
|
||||
|
||||
description: |
|
||||
8 bit ADCs with 1, 2, 4 or 8 inputs for single ended or differential
|
||||
conversion.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,adc0831
|
||||
- ti,adc0832
|
||||
- ti,adc0834
|
||||
- ti,adc0838
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vref-supply:
|
||||
description: External reference, needed to establish input scaling
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vref-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "ti,adc0832";
|
||||
reg = <0>;
|
||||
vref-supply = <&vdd_supply>;
|
||||
spi-max-frequency = <200000>;
|
||||
#io-channel-cells = <1>;
|
||||
};
|
||||
};
|
||||
...
|
47
Documentation/devicetree/bindings/iio/adc/ti,adc108s102.yaml
Normal file
47
Documentation/devicetree/bindings/iio/adc/ti,adc108s102.yaml
Normal file
@ -0,0 +1,47 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/ti,adc108s102.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments ADC108S102 and ADC128S102
|
||||
|
||||
maintainers:
|
||||
- Bogdan Pricop <bogdan.pricop@emutex.com>
|
||||
|
||||
description: |
|
||||
Family of 8 channel, 10/12 bit, SPI, single ended ADCs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const:
|
||||
ti,adc108s102
|
||||
|
||||
reg: true
|
||||
vref-supply: true
|
||||
spi-max-frequency: true
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vref-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells= <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "ti,adc108s102";
|
||||
reg = <0>;
|
||||
vref-supply = <&vdd_supply>;
|
||||
spi-max-frequency = <1000000>;
|
||||
#io-channel-cells = <1>;
|
||||
};
|
||||
};
|
||||
...
|
59
Documentation/devicetree/bindings/iio/adc/ti,adc128s052.yaml
Normal file
59
Documentation/devicetree/bindings/iio/adc/ti,adc128s052.yaml
Normal file
@ -0,0 +1,59 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/ti,adc128s052.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments ADC128S052 and similar ADCs
|
||||
|
||||
maintainers:
|
||||
- Angelo Compagnucci <angelo.compagnucci@gmail.com>
|
||||
|
||||
description: |
|
||||
Family of 12 bit SPI ADCs with 2 to 8 channels with a range of different
|
||||
target sample rates.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,adc122s021
|
||||
- ti,adc122s051
|
||||
- ti,adc122s101
|
||||
- ti,adc124s021
|
||||
- ti,adc124s051
|
||||
- ti,adc124s101
|
||||
- ti,adc128s052
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vref-supply: true
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vref-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "ti,adc128s052";
|
||||
reg = <0>;
|
||||
vref-supply = <&vdd_supply>;
|
||||
spi-max-frequency = <1000000>;
|
||||
#io-channel-cells = <1>;
|
||||
};
|
||||
};
|
||||
...
|
51
Documentation/devicetree/bindings/iio/adc/ti,adc161s626.yaml
Normal file
51
Documentation/devicetree/bindings/iio/adc/ti,adc161s626.yaml
Normal file
@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/ti,adc161s626.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments ADC141S626 and ADC161S626 ADCs
|
||||
|
||||
maintainers:
|
||||
- Matt Ranostay <matt.ranostay@konsulko.com>
|
||||
|
||||
description: |
|
||||
Single channel 14/16bit differential ADCs
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,adc141s626
|
||||
- ti,adc161s626
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vdda-supply: true
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "ti,adc161s626";
|
||||
vdda-supply = <&vdda_fixed>;
|
||||
reg = <0>;
|
||||
spi-max-frequency = <4300000>;
|
||||
#io-channel-cells = <1>;
|
||||
};
|
||||
};
|
||||
...
|
51
Documentation/devicetree/bindings/iio/adc/ti,ads8344.yaml
Normal file
51
Documentation/devicetree/bindings/iio/adc/ti,ads8344.yaml
Normal file
@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/ti,ads8344.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments ADS8344 ADC
|
||||
|
||||
maintainers:
|
||||
- Gregory Clement <gregory.clement@bootlin.com>
|
||||
|
||||
description: |
|
||||
16bit 8-channel ADC with single ended inputs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: ti,ads8344
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vref-supply:
|
||||
description: Supply the 2.5V or 5V reference voltage
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vref-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "ti,ads8344";
|
||||
reg = <0>;
|
||||
vref-supply = <&refin_supply>;
|
||||
spi-max-frequency = <10000000>;
|
||||
#io-channel-cells = <1>;
|
||||
};
|
||||
};
|
||||
...
|
52
Documentation/devicetree/bindings/iio/adc/ti,tlc4541.yaml
Normal file
52
Documentation/devicetree/bindings/iio/adc/ti,tlc4541.yaml
Normal file
@ -0,0 +1,52 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/ti,tlc4541.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments TLC4541 and similar ADCs
|
||||
|
||||
maintainers:
|
||||
- Phil Reid <preid@electromag.com.au>
|
||||
|
||||
description: |
|
||||
14/16bit single channel ADC with SPI interface.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,tlc3541
|
||||
- ti,tlc4541
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vref-supply: true
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vref-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "ti,tlc4541";
|
||||
reg = <0>;
|
||||
vref-supply = <&vdd_supply>;
|
||||
spi-max-frequency = <200000>;
|
||||
#io-channel-cells = <1>;
|
||||
};
|
||||
};
|
||||
...
|
@ -1,19 +0,0 @@
|
||||
* Texas Instruments' ADC0831/ADC0832/ADC0832/ADC0838
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of
|
||||
* "ti,adc0831"
|
||||
* "ti,adc0832"
|
||||
* "ti,adc0834"
|
||||
* "ti,adc0838"
|
||||
- reg: spi chip select number for the device
|
||||
- vref-supply: The regulator supply for ADC reference voltage
|
||||
- spi-max-frequency: Max SPI frequency to use (< 400000)
|
||||
|
||||
Example:
|
||||
adc@0 {
|
||||
compatible = "ti,adc0832";
|
||||
reg = <0>;
|
||||
vref-supply = <&vdd_supply>;
|
||||
spi-max-frequency = <200000>;
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
* Texas Instruments' ADC108S102 and ADC128S102 ADC chip
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "ti,adc108s102"
|
||||
- reg: spi chip select number for the device
|
||||
- vref-supply: The regulator supply for ADC reference voltage
|
||||
|
||||
Recommended properties:
|
||||
- spi-max-frequency: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
adc@0 {
|
||||
compatible = "ti,adc108s102";
|
||||
reg = <0>;
|
||||
vref-supply = <&vdd_supply>;
|
||||
spi-max-frequency = <1000000>;
|
||||
};
|
@ -1,25 +0,0 @@
|
||||
* Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of:
|
||||
- "ti,adc128s052"
|
||||
- "ti,adc122s021"
|
||||
- "ti,adc122s051"
|
||||
- "ti,adc122s101"
|
||||
- "ti,adc124s021"
|
||||
- "ti,adc124s051"
|
||||
- "ti,adc124s101"
|
||||
- reg: spi chip select number for the device
|
||||
- vref-supply: The regulator supply for ADC reference voltage
|
||||
|
||||
Recommended properties:
|
||||
- spi-max-frequency: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
adc@0 {
|
||||
compatible = "ti,adc128s052";
|
||||
reg = <0>;
|
||||
vref-supply = <&vdd_supply>;
|
||||
spi-max-frequency = <1000000>;
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
* Texas Instruments ADC141S626 and ADC161S626 chips
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "ti,adc141s626" or "ti,adc161s626"
|
||||
- reg: spi chip select number for the device
|
||||
- vdda-supply: supply voltage to VDDA pin
|
||||
|
||||
Recommended properties:
|
||||
- spi-max-frequency: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
adc@0 {
|
||||
compatible = "ti,adc161s626";
|
||||
vdda-supply = <&vdda_fixed>;
|
||||
reg = <0>;
|
||||
spi-max-frequency = <4300000>;
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
* Texas Instruments ADS8344 A/DC chip
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "ti,ads8344"
|
||||
- reg: SPI chip select number for the device
|
||||
- vref-supply: phandle to a regulator node that supplies the
|
||||
reference voltage
|
||||
|
||||
Recommended properties:
|
||||
- spi-max-frequency: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
adc@0 {
|
||||
compatible = "ti,ads8344";
|
||||
reg = <0>;
|
||||
vref-supply = <&refin_supply>;
|
||||
spi-max-frequency = <10000000>;
|
||||
};
|
@ -19,6 +19,8 @@ description: |
|
||||
http://www.atlas-scientific.com/_files/_datasheets/_oem/pH_oem_datasheet.pdf
|
||||
http://www.atlas-scientific.com/_files/_datasheets/_oem/RTD_oem_datasheet.pdf
|
||||
http://www.atlas-scientific.com/_files/_datasheets/_probe/EZO_CO2_Datasheet.pdf
|
||||
https://www.atlas-scientific.com/files/EZO_O2_datasheet.pdf
|
||||
https://www.atlas-scientific.com/files/EZO_HUM_Datasheet.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -29,6 +31,8 @@ properties:
|
||||
- atlas,ph-sm
|
||||
- atlas,rtd-sm
|
||||
- atlas,co2-ezo
|
||||
- atlas,o2-ezo
|
||||
- atlas,hum-ezo
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
77
Documentation/devicetree/bindings/iio/dac/lltc,ltc2632.yaml
Normal file
77
Documentation/devicetree/bindings/iio/dac/lltc,ltc2632.yaml
Normal file
@ -0,0 +1,77 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/iio/dac/lltc,ltc2632.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Linear Technology LTC263x 12-/10-/8-Bit Rail-to-Rail DAC
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
|
||||
description: |
|
||||
Bindings for the Linear Technology LTC2632/2634/2636 DAC
|
||||
Datasheet can be found here: https://www.analog.com/media/en/technical-documentation/data-sheets/LTC263[246].pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- lltc,ltc2632-l12
|
||||
- lltc,ltc2632-l10
|
||||
- lltc,ltc2632-l8
|
||||
- lltc,ltc2632-h12
|
||||
- lltc,ltc2632-h10
|
||||
- lltc,ltc2632-h8
|
||||
- lltc,ltc2634-l12
|
||||
- lltc,ltc2634-l10
|
||||
- lltc,ltc2634-l8
|
||||
- lltc,ltc2634-h12
|
||||
- lltc,ltc2634-h10
|
||||
- lltc,ltc2634-h8
|
||||
- lltc,ltc2636-l12
|
||||
- lltc,ltc2636-l10
|
||||
- lltc,ltc2636-l8
|
||||
- lltc,ltc2636-h12
|
||||
- lltc,ltc2636-h10
|
||||
- lltc,ltc2636-h8
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 2000000
|
||||
|
||||
vref-supply:
|
||||
description:
|
||||
Phandle to the external reference voltage supply. This should
|
||||
only be set if there is an external reference voltage connected to the VREF
|
||||
pin. If the property is not set the internal reference is used.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
vref: regulator-vref {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vref-ltc2632";
|
||||
regulator-min-microvolt = <1250000>;
|
||||
regulator-max-microvolt = <1250000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
compatible = "lltc,ltc2632";
|
||||
reg = <0>; /* CS0 */
|
||||
spi-max-frequency = <1000000>;
|
||||
vref-supply = <&vref>;
|
||||
};
|
||||
};
|
||||
...
|
@ -1,49 +0,0 @@
|
||||
Linear Technology LTC2632/2634/2636 DAC
|
||||
|
||||
Required properties:
|
||||
- compatible: Has to contain one of the following:
|
||||
lltc,ltc2632-l12
|
||||
lltc,ltc2632-l10
|
||||
lltc,ltc2632-l8
|
||||
lltc,ltc2632-h12
|
||||
lltc,ltc2632-h10
|
||||
lltc,ltc2632-h8
|
||||
lltc,ltc2634-l12
|
||||
lltc,ltc2634-l10
|
||||
lltc,ltc2634-l8
|
||||
lltc,ltc2634-h12
|
||||
lltc,ltc2634-h10
|
||||
lltc,ltc2634-h8
|
||||
lltc,ltc2636-l12
|
||||
lltc,ltc2636-l10
|
||||
lltc,ltc2636-l8
|
||||
lltc,ltc2636-h12
|
||||
lltc,ltc2636-h10
|
||||
lltc,ltc2636-h8
|
||||
|
||||
Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
apply. In particular, "reg" and "spi-max-frequency" properties must be given.
|
||||
|
||||
Optional properties:
|
||||
- vref-supply: Phandle to the external reference voltage supply. This should
|
||||
only be set if there is an external reference voltage connected to the VREF
|
||||
pin. If the property is not set the internal reference is used.
|
||||
|
||||
Example:
|
||||
|
||||
vref: regulator-vref {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vref-ltc2632";
|
||||
regulator-min-microvolt = <1250000>;
|
||||
regulator-max-microvolt = <1250000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
spi_master {
|
||||
dac: ltc2632@0 {
|
||||
compatible = "lltc,ltc2632-l12";
|
||||
reg = <0>; /* CS0 */
|
||||
spi-max-frequency = <1000000>;
|
||||
vref-supply = <&vref>; /* optional */
|
||||
};
|
||||
};
|
@ -0,0 +1,53 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2020 Analog Devices Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/gyroscope/adi,adxrs290.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices ADXRS290 Dual-Axis MEMS Gyroscope
|
||||
|
||||
maintainers:
|
||||
- Nishant Malpani <nish.malpani25@gmail.com>
|
||||
|
||||
description: |
|
||||
Bindings for the Analog Devices ADXRS290 dual-axis MEMS gyroscope device.
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ADXRS290.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: adi,adxrs290
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 5000000
|
||||
|
||||
spi-cpol: true
|
||||
|
||||
spi-cpha: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- spi-max-frequency
|
||||
- spi-cpol
|
||||
- spi-cpha
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
gyro@0 {
|
||||
compatible = "adi,adxrs290";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <5000000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
};
|
||||
};
|
||||
...
|
@ -0,0 +1,45 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/humidity/ti,hdc2010.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: HDC2010/HDC2080 humidity and temperature iio sensors
|
||||
|
||||
maintainers:
|
||||
- Eugene Zaikonnikov <ez@norophonic.com>
|
||||
|
||||
description: |
|
||||
Relative humidity and tempereature sensors on I2C bus
|
||||
|
||||
Datasheets are available at:
|
||||
http://www.ti.com/product/HDC2010/datasheet
|
||||
http://www.ti.com/product/HDC2080/datasheet
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,hdc2010
|
||||
- ti,hdc2080
|
||||
|
||||
vdd-supply:
|
||||
maxItems: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
humidity@40 {
|
||||
compatible = "ti,hdc2010";
|
||||
reg = <0x40>;
|
||||
};
|
||||
};
|
54
Documentation/devicetree/bindings/iio/light/ams,as73211.yaml
Normal file
54
Documentation/devicetree/bindings/iio/light/ams,as73211.yaml
Normal file
@ -0,0 +1,54 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/light/ams,as73211.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: AMS AS73211 JENCOLOR(R) Digital XYZ Sensor
|
||||
|
||||
maintainers:
|
||||
- Christian Eggers <ceggers@arri.de>
|
||||
|
||||
description: |
|
||||
XYZ True Color Sensor with I2C Interface
|
||||
https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf/a65474c0-b302-c2fd-e30a-c98df87616df
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ams,as73211
|
||||
|
||||
reg:
|
||||
description:
|
||||
I2C address of the device (0x74...0x77).
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
Interrupt specifier for the READY interrupt generated by the device.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
as73211@74 {
|
||||
compatible = "ams,as73211";
|
||||
reg = <0x74>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_color_sensor>;
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <19 IRQ_TYPE_EDGE_RISING>; /* READY */
|
||||
};
|
||||
};
|
||||
...
|
@ -0,0 +1,65 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/proximity/semtech,sx9310.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Semtech's SX9310 capacitive proximity sensor
|
||||
|
||||
maintainers:
|
||||
- Daniel Campello <campello@chromium.org>
|
||||
|
||||
description: |
|
||||
Semtech's SX9310/SX9311 capacitive proximity/button solution.
|
||||
|
||||
Specifications about the devices can be found at:
|
||||
https://www.semtech.com/products/smart-sensing/sar-sensors/sx9310
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- semtech,sx9310
|
||||
- semtech,sx9311
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
The sole interrupt generated by the device used to announce the
|
||||
preceding reading request has finished and that data is
|
||||
available or that a close/far proximity event has happened.
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply:
|
||||
description: Main power supply
|
||||
|
||||
svdd-supply:
|
||||
description: Host interface power supply
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#io-channel-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
proximity@28 {
|
||||
compatible = "semtech,sx9310";
|
||||
reg = <0x28>;
|
||||
interrupt-parent = <&pio>;
|
||||
interrupts = <5 IRQ_TYPE_LEVEL_LOW 5>;
|
||||
vdd-supply = <&pp3300_a>;
|
||||
svdd-supply = <&pp1800_prox>;
|
||||
#io-channel-cells = <1>;
|
||||
};
|
||||
};
|
@ -128,6 +128,22 @@ properties:
|
||||
- mcube,mc3230
|
||||
# MEMSIC 2-axis 8-bit digital accelerometer
|
||||
- memsic,mxc6225
|
||||
# Microchip differential I2C ADC, 1 Channel, 18 bit
|
||||
- microchip,mcp3421
|
||||
# Microchip differential I2C ADC, 2 Channel, 18 bit
|
||||
- microchip,mcp3422
|
||||
# Microchip differential I2C ADC, 2 Channel, 18 bit
|
||||
- microchip,mcp3423
|
||||
# Microchip differential I2C ADC, 4 Channel, 18 bit
|
||||
- microchip,mcp3424
|
||||
# Microchip differential I2C ADC, 1 Channel, 16 bit
|
||||
- microchip,mcp3425
|
||||
# Microchip differential I2C ADC, 2 Channel, 16 bit
|
||||
- microchip,mcp3426
|
||||
# Microchip differential I2C ADC, 2 Channel, 16 bit
|
||||
- microchip,mcp3427
|
||||
# Microchip differential I2C ADC, 4 Channel, 16 bit
|
||||
- microchip,mcp3428
|
||||
# Microchip 7-bit Single I2C Digital POT (5k)
|
||||
- microchip,mcp4017-502
|
||||
# Microchip 7-bit Single I2C Digital POT (10k)
|
||||
|
14
MAINTAINERS
14
MAINTAINERS
@ -943,6 +943,13 @@ S: Supported
|
||||
F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
|
||||
F: drivers/net/ethernet/amd/xgbe/
|
||||
|
||||
AMS AS73211 DRIVER
|
||||
M: Christian Eggers <ceggers@arri.de>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/light/ams,as73211.yaml
|
||||
F: drivers/iio/light/as73211.c
|
||||
|
||||
ANALOG DEVICES INC AD5686 DRIVER
|
||||
M: Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
L: linux-pm@vger.kernel.org
|
||||
@ -1108,6 +1115,13 @@ L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/media/i2c/adv7842*
|
||||
|
||||
ANALOG DEVICES INC ADXRS290 DRIVER
|
||||
M: Nishant Malpani <nish.malpani25@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/iio/gyro/adxrs290.c
|
||||
F: Documentation/devicetree/bindings/iio/gyroscope/adi,adxrs290.yaml
|
||||
|
||||
ANALOG DEVICES INC ASOC CODEC DRIVERS
|
||||
M: Lars-Peter Clausen <lars@metafoo.de>
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright 2018 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
@ -113,6 +114,11 @@
|
||||
#define ADXL372_STATUS_1_AWAKE(x) (((x) >> 6) & 0x1)
|
||||
#define ADXL372_STATUS_1_ERR_USR_REGS(x) (((x) >> 7) & 0x1)
|
||||
|
||||
/* ADXL372_STATUS_2 */
|
||||
#define ADXL372_STATUS_2_INACT(x) (((x) >> 4) & 0x1)
|
||||
#define ADXL372_STATUS_2_ACT(x) (((x) >> 5) & 0x1)
|
||||
#define ADXL372_STATUS_2_AC2(x) (((x) >> 6) & 0x1)
|
||||
|
||||
/* ADXL372_INT1_MAP */
|
||||
#define ADXL372_INT1_MAP_DATA_RDY_MSK BIT(0)
|
||||
#define ADXL372_INT1_MAP_DATA_RDY_MODE(x) (((x) & 0x1) << 0)
|
||||
@ -131,8 +137,17 @@
|
||||
#define ADXL372_INT1_MAP_LOW_MSK BIT(7)
|
||||
#define ADXL372_INT1_MAP_LOW_MODE(x) (((x) & 0x1) << 7)
|
||||
|
||||
/* ADX372_THRESH */
|
||||
#define ADXL372_THRESH_VAL_H_MSK GENMASK(10, 3)
|
||||
#define ADXL372_THRESH_VAL_H_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_H_MSK, x)
|
||||
#define ADXL372_THRESH_VAL_L_MSK GENMASK(2, 0)
|
||||
#define ADXL372_THRESH_VAL_L_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_L_MSK, x)
|
||||
|
||||
/* The ADXL372 includes a deep, 512 sample FIFO buffer */
|
||||
#define ADXL372_FIFO_SIZE 512
|
||||
#define ADXL372_X_AXIS_EN(x) ((x) & BIT(0))
|
||||
#define ADXL372_Y_AXIS_EN(x) ((x) & BIT(1))
|
||||
#define ADXL372_Z_AXIS_EN(x) ((x) & BIT(2))
|
||||
|
||||
/*
|
||||
* At +/- 200g with 12-bit resolution, scale is computed as:
|
||||
@ -222,6 +237,20 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = {
|
||||
{ BIT(0) | BIT(1) | BIT(2), ADXL372_XYZ_FIFO },
|
||||
};
|
||||
|
||||
static const struct iio_event_spec adxl372_events[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE),
|
||||
.mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE),
|
||||
.mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
#define ADXL372_ACCEL_CHANNEL(index, reg, axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.address = reg, \
|
||||
@ -239,6 +268,8 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = {
|
||||
.shift = 4, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
.event_spec = adxl372_events, \
|
||||
.num_event_specs = ARRAY_SIZE(adxl372_events) \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec adxl372_channels[] = {
|
||||
@ -252,8 +283,10 @@ struct adxl372_state {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct iio_trigger *dready_trig;
|
||||
struct iio_trigger *peak_datardy_trig;
|
||||
enum adxl372_fifo_mode fifo_mode;
|
||||
enum adxl372_fifo_format fifo_format;
|
||||
unsigned int fifo_axis_mask;
|
||||
enum adxl372_op_mode op_mode;
|
||||
enum adxl372_act_proc_mode act_proc_mode;
|
||||
enum adxl372_odr odr;
|
||||
@ -261,10 +294,12 @@ struct adxl372_state {
|
||||
u32 act_time_ms;
|
||||
u32 inact_time_ms;
|
||||
u8 fifo_set_size;
|
||||
u8 int1_bitmask;
|
||||
u8 int2_bitmask;
|
||||
unsigned long int1_bitmask;
|
||||
unsigned long int2_bitmask;
|
||||
u16 watermark;
|
||||
__be16 fifo_buf[ADXL372_FIFO_SIZE];
|
||||
bool peak_fifo_mode_en;
|
||||
struct mutex threshold_m; /* lock for threshold */
|
||||
};
|
||||
|
||||
static const unsigned long adxl372_channel_masks[] = {
|
||||
@ -276,6 +311,46 @@ static const unsigned long adxl372_channel_masks[] = {
|
||||
0
|
||||
};
|
||||
|
||||
static ssize_t adxl372_read_threshold_value(struct iio_dev *indio_dev, unsigned int addr,
|
||||
u16 *threshold)
|
||||
{
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
__be16 raw_regval;
|
||||
u16 regval;
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(st->regmap, addr, &raw_regval, sizeof(raw_regval));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
regval = be16_to_cpu(raw_regval);
|
||||
regval >>= 5;
|
||||
|
||||
*threshold = regval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t adxl372_write_threshold_value(struct iio_dev *indio_dev, unsigned int addr,
|
||||
u16 threshold)
|
||||
{
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->threshold_m);
|
||||
ret = regmap_write(st->regmap, addr, ADXL372_THRESH_VAL_H_SEL(threshold));
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
ret = regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5),
|
||||
ADXL372_THRESH_VAL_L_SEL(threshold) << 5);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&st->threshold_m);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adxl372_read_axis(struct adxl372_state *st, u8 addr)
|
||||
{
|
||||
__be16 regval;
|
||||
@ -453,8 +528,8 @@ static int adxl372_set_inactivity_time_ms(struct adxl372_state *st,
|
||||
}
|
||||
|
||||
static int adxl372_set_interrupts(struct adxl372_state *st,
|
||||
unsigned char int1_bitmask,
|
||||
unsigned char int2_bitmask)
|
||||
unsigned long int1_bitmask,
|
||||
unsigned long int2_bitmask)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -523,6 +598,39 @@ static int adxl372_get_status(struct adxl372_state *st,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void adxl372_arrange_axis_data(struct adxl372_state *st, __be16 *sample)
|
||||
{
|
||||
__be16 axis_sample[3];
|
||||
int i = 0;
|
||||
|
||||
memset(axis_sample, 0, 3 * sizeof(__be16));
|
||||
if (ADXL372_X_AXIS_EN(st->fifo_axis_mask))
|
||||
axis_sample[i++] = sample[0];
|
||||
if (ADXL372_Y_AXIS_EN(st->fifo_axis_mask))
|
||||
axis_sample[i++] = sample[1];
|
||||
if (ADXL372_Z_AXIS_EN(st->fifo_axis_mask))
|
||||
axis_sample[i++] = sample[2];
|
||||
|
||||
memcpy(sample, axis_sample, 3 * sizeof(__be16));
|
||||
}
|
||||
|
||||
static void adxl372_push_event(struct iio_dev *indio_dev, s64 timestamp, u8 status2)
|
||||
{
|
||||
unsigned int ev_dir = IIO_EV_DIR_NONE;
|
||||
|
||||
if (ADXL372_STATUS_2_ACT(status2))
|
||||
ev_dir = IIO_EV_DIR_RISING;
|
||||
|
||||
if (ADXL372_STATUS_2_INACT(status2))
|
||||
ev_dir = IIO_EV_DIR_FALLING;
|
||||
|
||||
if (ev_dir != IIO_EV_DIR_NONE)
|
||||
iio_push_event(indio_dev,
|
||||
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z,
|
||||
IIO_EV_TYPE_THRESH, ev_dir),
|
||||
timestamp);
|
||||
}
|
||||
|
||||
static irqreturn_t adxl372_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
@ -536,6 +644,8 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p)
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
adxl372_push_event(indio_dev, iio_get_time_ns(indio_dev), status2);
|
||||
|
||||
if (st->fifo_mode != ADXL372_FIFO_BYPASSED &&
|
||||
ADXL372_STATUS_1_FIFO_FULL(status1)) {
|
||||
/*
|
||||
@ -554,8 +664,12 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p)
|
||||
goto err;
|
||||
|
||||
/* Each sample is 2 bytes */
|
||||
for (i = 0; i < fifo_entries; i += st->fifo_set_size)
|
||||
for (i = 0; i < fifo_entries; i += st->fifo_set_size) {
|
||||
/* filter peak detection data */
|
||||
if (st->peak_fifo_mode_en)
|
||||
adxl372_arrange_axis_data(st, &st->fifo_buf[i]);
|
||||
iio_push_to_buffers(indio_dev, &st->fifo_buf[i]);
|
||||
}
|
||||
}
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
@ -723,6 +837,129 @@ static int adxl372_write_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl372_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type, enum iio_event_direction dir,
|
||||
enum iio_event_info info, int *val, int *val2)
|
||||
{
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
unsigned int addr;
|
||||
u16 raw_value;
|
||||
int ret;
|
||||
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index;
|
||||
ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = raw_value * ADXL372_USCALE;
|
||||
*val2 = 1000000;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_EV_DIR_FALLING:
|
||||
addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index;
|
||||
ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = raw_value * ADXL372_USCALE;
|
||||
*val2 = 1000000;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_EV_INFO_PERIOD:
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
*val = st->act_time_ms;
|
||||
*val2 = 1000;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_EV_DIR_FALLING:
|
||||
*val = st->inact_time_ms;
|
||||
*val2 = 1000;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl372_write_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type, enum iio_event_direction dir,
|
||||
enum iio_event_info info, int val, int val2)
|
||||
{
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
unsigned int val_ms;
|
||||
unsigned int addr;
|
||||
u16 raw_val;
|
||||
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
raw_val = DIV_ROUND_UP(val * 1000000, ADXL372_USCALE);
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index;
|
||||
return adxl372_write_threshold_value(indio_dev, addr, raw_val);
|
||||
case IIO_EV_DIR_FALLING:
|
||||
addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index;
|
||||
return adxl372_write_threshold_value(indio_dev, addr, raw_val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_EV_INFO_PERIOD:
|
||||
val_ms = val * 1000 + DIV_ROUND_UP(val2, 1000);
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
return adxl372_set_activity_time_ms(st, val_ms);
|
||||
case IIO_EV_DIR_FALLING:
|
||||
return adxl372_set_inactivity_time_ms(st, val_ms);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl372_read_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type, enum iio_event_direction dir)
|
||||
{
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
return FIELD_GET(ADXL372_INT1_MAP_ACT_MSK, st->int1_bitmask);
|
||||
case IIO_EV_DIR_FALLING:
|
||||
return FIELD_GET(ADXL372_INT1_MAP_INACT_MSK, st->int1_bitmask);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type, enum iio_event_direction dir,
|
||||
int state)
|
||||
{
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_ACT_MSK,
|
||||
ADXL372_INT1_MAP_ACT_MODE(state));
|
||||
break;
|
||||
case IIO_EV_DIR_FALLING:
|
||||
set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_INACT_MSK,
|
||||
ADXL372_INT1_MAP_INACT_MODE(state));
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return adxl372_set_interrupts(st, st->int1_bitmask, 0);
|
||||
}
|
||||
|
||||
static ssize_t adxl372_show_filter_freq_avail(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -795,7 +1032,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
|
||||
unsigned int mask;
|
||||
int i, ret;
|
||||
|
||||
ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0);
|
||||
st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK;
|
||||
ret = adxl372_set_interrupts(st, st->int1_bitmask, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -810,13 +1048,22 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
|
||||
return -EINVAL;
|
||||
|
||||
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);
|
||||
|
||||
/* Configure the FIFO to store sets of impact event peak. */
|
||||
if (st->peak_fifo_mode_en) {
|
||||
st->fifo_set_size = 3;
|
||||
st->fifo_format = ADXL372_XYZ_PEAK_FIFO;
|
||||
}
|
||||
|
||||
/*
|
||||
* The 512 FIFO samples can be allotted in several ways, such as:
|
||||
* 170 sample sets of concurrent 3-axis data
|
||||
* 256 sample sets of concurrent 2-axis data (user selectable)
|
||||
* 512 sample sets of single-axis data
|
||||
* 170 sets of impact event peak (x, y, z)
|
||||
*/
|
||||
if ((st->watermark * st->fifo_set_size) > ADXL372_FIFO_SIZE)
|
||||
st->watermark = (ADXL372_FIFO_SIZE / st->fifo_set_size);
|
||||
@ -826,7 +1073,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
|
||||
ret = adxl372_configure_fifo(st);
|
||||
if (ret < 0) {
|
||||
st->fifo_mode = ADXL372_FIFO_BYPASSED;
|
||||
adxl372_set_interrupts(st, 0, 0);
|
||||
st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK;
|
||||
adxl372_set_interrupts(st, st->int1_bitmask, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -837,7 +1085,8 @@ static int adxl372_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
|
||||
adxl372_set_interrupts(st, 0, 0);
|
||||
st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK;
|
||||
adxl372_set_interrupts(st, st->int1_bitmask, 0);
|
||||
st->fifo_mode = ADXL372_FIFO_BYPASSED;
|
||||
adxl372_configure_fifo(st);
|
||||
|
||||
@ -854,12 +1103,11 @@ static int adxl372_dready_trig_set_state(struct iio_trigger *trig,
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
unsigned long int mask = 0;
|
||||
|
||||
if (state)
|
||||
mask = ADXL372_INT1_MAP_FIFO_FULL_MSK;
|
||||
st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK;
|
||||
|
||||
return adxl372_set_interrupts(st, mask, 0);
|
||||
return adxl372_set_interrupts(st, st->int1_bitmask, 0);
|
||||
}
|
||||
|
||||
static int adxl372_validate_trigger(struct iio_dev *indio_dev,
|
||||
@ -867,7 +1115,7 @@ static int adxl372_validate_trigger(struct iio_dev *indio_dev,
|
||||
{
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (st->dready_trig != trig)
|
||||
if (st->dready_trig != trig && st->peak_datardy_trig != trig)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@ -878,6 +1126,25 @@ static const struct iio_trigger_ops adxl372_trigger_ops = {
|
||||
.set_trigger_state = adxl372_dready_trig_set_state,
|
||||
};
|
||||
|
||||
static int adxl372_peak_dready_trig_set_state(struct iio_trigger *trig,
|
||||
bool state)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (state)
|
||||
st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK;
|
||||
|
||||
st->peak_fifo_mode_en = state;
|
||||
|
||||
return adxl372_set_interrupts(st, st->int1_bitmask, 0);
|
||||
}
|
||||
|
||||
static const struct iio_trigger_ops adxl372_peak_data_trigger_ops = {
|
||||
.validate_device = &iio_trigger_validate_own_device,
|
||||
.set_trigger_state = adxl372_peak_dready_trig_set_state,
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400");
|
||||
static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available,
|
||||
0444, adxl372_show_filter_freq_avail, NULL, 0);
|
||||
@ -897,6 +1164,10 @@ static const struct iio_info adxl372_info = {
|
||||
.attrs = &adxl372_attrs_group,
|
||||
.read_raw = adxl372_read_raw,
|
||||
.write_raw = adxl372_write_raw,
|
||||
.read_event_config = adxl372_read_event_config,
|
||||
.write_event_config = adxl372_write_event_config,
|
||||
.read_event_value = adxl372_read_event_value,
|
||||
.write_event_value = adxl372_write_event_value,
|
||||
.debugfs_reg_access = &adxl372_reg_access,
|
||||
.hwfifo_set_watermark = adxl372_set_watermark,
|
||||
};
|
||||
@ -925,6 +1196,8 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
|
||||
st->regmap = regmap;
|
||||
st->irq = irq;
|
||||
|
||||
mutex_init(&st->threshold_m);
|
||||
|
||||
indio_dev->channels = adxl372_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adxl372_channels);
|
||||
indio_dev->available_scan_masks = adxl372_channel_masks;
|
||||
@ -955,13 +1228,27 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
|
||||
if (st->dready_trig == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
st->peak_datardy_trig = devm_iio_trigger_alloc(dev,
|
||||
"%s-dev%d-peak",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
if (!st->peak_datardy_trig)
|
||||
return -ENOMEM;
|
||||
|
||||
st->dready_trig->ops = &adxl372_trigger_ops;
|
||||
st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops;
|
||||
st->dready_trig->dev.parent = dev;
|
||||
st->peak_datardy_trig->dev.parent = dev;
|
||||
iio_trigger_set_drvdata(st->dready_trig, indio_dev);
|
||||
iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev);
|
||||
ret = devm_iio_trigger_register(dev, st->dready_trig);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_trigger_register(dev, st->peak_datardy_trig);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
indio_dev->trig = iio_trigger_get(st->dready_trig);
|
||||
|
||||
ret = devm_request_threaded_irq(dev, st->irq,
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
@ -46,9 +47,16 @@ static const struct i2c_device_id adxl372_i2c_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
|
||||
|
||||
static const struct of_device_id adxl372_of_match[] = {
|
||||
{ .compatible = "adi,adxl372" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adxl372_of_match);
|
||||
|
||||
static struct i2c_driver adxl372_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "adxl372_i2c",
|
||||
.of_match_table = adxl372_of_match,
|
||||
},
|
||||
.probe = adxl372_i2c_probe,
|
||||
.id_table = adxl372_i2c_id,
|
||||
|
@ -40,8 +40,8 @@ static const struct spi_device_id adxl372_spi_id[] = {
|
||||
MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
|
||||
|
||||
static const struct of_device_id adxl372_of_match[] = {
|
||||
{ .compatible = "adi,adxl372" },
|
||||
{ },
|
||||
{ .compatible = "adi,adxl372" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adxl372_of_match);
|
||||
|
||||
|
@ -1000,19 +1000,15 @@ static int bma180_probe(struct i2c_client *client,
|
||||
return ret;
|
||||
|
||||
data->vdd_supply = devm_regulator_get(dev, "vdd");
|
||||
if (IS_ERR(data->vdd_supply)) {
|
||||
if (PTR_ERR(data->vdd_supply) != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get vdd regulator %d\n",
|
||||
(int)PTR_ERR(data->vdd_supply));
|
||||
return PTR_ERR(data->vdd_supply);
|
||||
}
|
||||
if (IS_ERR(data->vdd_supply))
|
||||
return dev_err_probe(dev, PTR_ERR(data->vdd_supply),
|
||||
"Failed to get vdd regulator\n");
|
||||
|
||||
data->vddio_supply = devm_regulator_get(dev, "vddio");
|
||||
if (IS_ERR(data->vddio_supply)) {
|
||||
if (PTR_ERR(data->vddio_supply) != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get vddio regulator %d\n",
|
||||
(int)PTR_ERR(data->vddio_supply));
|
||||
return PTR_ERR(data->vddio_supply);
|
||||
}
|
||||
if (IS_ERR(data->vddio_supply))
|
||||
return dev_err_probe(dev, PTR_ERR(data->vddio_supply),
|
||||
"Failed to get vddio regulator\n");
|
||||
|
||||
/* Typical voltage 2.4V these are min and max */
|
||||
ret = regulator_set_voltage(data->vdd_supply, 1620000, 3600000);
|
||||
if (ret)
|
||||
|
@ -2,16 +2,18 @@
|
||||
/**
|
||||
* BMA220 Digital triaxial acceleration sensor driver
|
||||
*
|
||||
* Copyright (c) 2016, Intel Corporation.
|
||||
* Copyright (c) 2016,2020 Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
@ -23,14 +25,13 @@
|
||||
#define BMA220_REG_SUSPEND 0x18
|
||||
|
||||
#define BMA220_CHIP_ID 0xDD
|
||||
#define BMA220_READ_MASK 0x80
|
||||
#define BMA220_RANGE_MASK 0x03
|
||||
#define BMA220_READ_MASK BIT(7)
|
||||
#define BMA220_RANGE_MASK GENMASK(1, 0)
|
||||
#define BMA220_DATA_SHIFT 2
|
||||
#define BMA220_SUSPEND_SLEEP 0xFF
|
||||
#define BMA220_SUSPEND_WAKE 0x00
|
||||
|
||||
#define BMA220_DEVICE_NAME "bma220"
|
||||
#define BMA220_SCALE_AVAILABLE "0.623 1.248 2.491 4.983"
|
||||
|
||||
#define BMA220_ACCEL_CHANNEL(index, reg, axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
@ -55,19 +56,8 @@ enum bma220_axis {
|
||||
AXIS_Z,
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR(in_accel_scale_available, BMA220_SCALE_AVAILABLE);
|
||||
|
||||
static struct attribute *bma220_attributes[] = {
|
||||
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group bma220_attribute_group = {
|
||||
.attrs = bma220_attributes,
|
||||
};
|
||||
|
||||
static const int bma220_scale_table[][4] = {
|
||||
{0, 623000}, {1, 248000}, {2, 491000}, {4, 983000}
|
||||
static const int bma220_scale_table[][2] = {
|
||||
{0, 623000}, {1, 248000}, {2, 491000}, {4, 983000},
|
||||
};
|
||||
|
||||
struct bma220_data {
|
||||
@ -182,10 +172,26 @@ static int bma220_write_raw(struct iio_dev *indio_dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int bma220_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length,
|
||||
long mask)
|
||||
{
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*vals = (int *)bma220_scale_table;
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
*length = ARRAY_SIZE(bma220_scale_table) * 2;
|
||||
return IIO_AVAIL_LIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info bma220_info = {
|
||||
.read_raw = bma220_read_raw,
|
||||
.write_raw = bma220_write_raw,
|
||||
.attrs = &bma220_attribute_group,
|
||||
.read_avail = bma220_read_avail,
|
||||
};
|
||||
|
||||
static int bma220_init(struct spi_device *spi)
|
||||
@ -198,10 +204,12 @@ static int bma220_init(struct spi_device *spi)
|
||||
|
||||
/* Make sure the chip is powered on */
|
||||
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
|
||||
if (ret == BMA220_SUSPEND_WAKE)
|
||||
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret == BMA220_SUSPEND_WAKE)
|
||||
return bma220_read_reg(spi, BMA220_REG_SUSPEND);
|
||||
if (ret == BMA220_SUSPEND_WAKE)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -212,10 +220,12 @@ static int bma220_deinit(struct spi_device *spi)
|
||||
|
||||
/* Make sure the chip is powered off */
|
||||
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
|
||||
if (ret == BMA220_SUSPEND_SLEEP)
|
||||
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret == BMA220_SUSPEND_SLEEP)
|
||||
return bma220_read_reg(spi, BMA220_REG_SUSPEND);
|
||||
if (ret == BMA220_SUSPEND_SLEEP)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -245,7 +255,7 @@ static int bma220_probe(struct spi_device *spi)
|
||||
indio_dev->available_scan_masks = bma220_accel_scan_masks;
|
||||
|
||||
ret = bma220_init(data->spi_device);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
|
||||
@ -278,56 +288,43 @@ static int bma220_remove(struct spi_device *spi)
|
||||
return bma220_deinit(spi);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int bma220_suspend(struct device *dev)
|
||||
static __maybe_unused int bma220_suspend(struct device *dev)
|
||||
{
|
||||
struct bma220_data *data =
|
||||
iio_priv(spi_get_drvdata(to_spi_device(dev)));
|
||||
struct bma220_data *data = iio_priv(dev_get_drvdata(dev));
|
||||
|
||||
/* The chip can be suspended/woken up by a simple register read. */
|
||||
return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
|
||||
}
|
||||
|
||||
static int bma220_resume(struct device *dev)
|
||||
static __maybe_unused int bma220_resume(struct device *dev)
|
||||
{
|
||||
struct bma220_data *data =
|
||||
iio_priv(spi_get_drvdata(to_spi_device(dev)));
|
||||
struct bma220_data *data = iio_priv(dev_get_drvdata(dev));
|
||||
|
||||
return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume);
|
||||
|
||||
#define BMA220_PM_OPS (&bma220_pm_ops)
|
||||
#else
|
||||
#define BMA220_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static const struct spi_device_id bma220_spi_id[] = {
|
||||
{"bma220", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id bma220_acpi_id[] = {
|
||||
{"BMA0220", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(spi, bma220_spi_id);
|
||||
#endif
|
||||
|
||||
static struct spi_driver bma220_driver = {
|
||||
.driver = {
|
||||
.name = "bma220_spi",
|
||||
.pm = BMA220_PM_OPS,
|
||||
.acpi_match_table = ACPI_PTR(bma220_acpi_id),
|
||||
.pm = &bma220_pm_ops,
|
||||
.acpi_match_table = bma220_acpi_id,
|
||||
},
|
||||
.probe = bma220_probe,
|
||||
.remove = bma220_remove,
|
||||
.id_table = bma220_spi_id,
|
||||
};
|
||||
|
||||
module_spi_driver(bma220_driver);
|
||||
|
||||
MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
|
||||
|
@ -1538,22 +1538,14 @@ static int mma8452_probe(struct i2c_client *client,
|
||||
data->chip_info = match->data;
|
||||
|
||||
data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
|
||||
if (IS_ERR(data->vdd_reg)) {
|
||||
if (PTR_ERR(data->vdd_reg) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_err(&client->dev, "failed to get VDD regulator!\n");
|
||||
return PTR_ERR(data->vdd_reg);
|
||||
}
|
||||
if (IS_ERR(data->vdd_reg))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(data->vdd_reg),
|
||||
"failed to get VDD regulator!\n");
|
||||
|
||||
data->vddio_reg = devm_regulator_get(&client->dev, "vddio");
|
||||
if (IS_ERR(data->vddio_reg)) {
|
||||
if (PTR_ERR(data->vddio_reg) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_err(&client->dev, "failed to get VDDIO regulator!\n");
|
||||
return PTR_ERR(data->vddio_reg);
|
||||
}
|
||||
if (IS_ERR(data->vddio_reg))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(data->vddio_reg),
|
||||
"failed to get VDDIO regulator!\n");
|
||||
|
||||
ret = regulator_enable(data->vdd_reg);
|
||||
if (ret) {
|
||||
|
@ -340,7 +340,7 @@ config AXP288_ADC
|
||||
|
||||
config BCM_IPROC_ADC
|
||||
tristate "Broadcom IPROC ADC driver"
|
||||
depends on ARCH_BCM_IPROC || COMPILE_TEST
|
||||
depends on (ARCH_BCM_IPROC && OF) || COMPILE_TEST
|
||||
depends on MFD_SYSCON
|
||||
default ARCH_BCM_CYGNUS
|
||||
help
|
||||
|
@ -276,7 +276,7 @@ static struct attribute *adi_axi_adc_attributes[] = {
|
||||
static umode_t axi_adc_attr_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct adi_axi_adc_state *st = iio_priv(indio_dev);
|
||||
struct adi_axi_adc_conv *conv = &st->client->conv;
|
||||
|
@ -9,10 +9,10 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
@ -67,7 +67,7 @@ struct axp_data;
|
||||
|
||||
struct axp20x_adc_iio {
|
||||
struct regmap *regmap;
|
||||
struct axp_data *data;
|
||||
const struct axp_data *data;
|
||||
};
|
||||
|
||||
enum axp20x_adc_channel_v {
|
||||
@ -670,15 +670,15 @@ static int axp20x_probe(struct platform_device *pdev)
|
||||
info->regmap = axp20x_dev->regmap;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
if (!dev_fwnode(&pdev->dev)) {
|
||||
const struct platform_device_id *id;
|
||||
|
||||
id = platform_get_device_id(pdev);
|
||||
info->data = (struct axp_data *)id->driver_data;
|
||||
info->data = (const struct axp_data *)id->driver_data;
|
||||
} else {
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
info->data = (struct axp_data *)of_device_get_match_data(dev);
|
||||
info->data = device_get_match_data(dev);
|
||||
}
|
||||
|
||||
indio_dev->name = platform_get_device_id(pdev)->name;
|
||||
@ -742,7 +742,7 @@ static int axp20x_remove(struct platform_device *pdev)
|
||||
static struct platform_driver axp20x_adc_driver = {
|
||||
.driver = {
|
||||
.name = "axp20x-adc",
|
||||
.of_match_table = of_match_ptr(axp20x_adc_of_match),
|
||||
.of_match_table = axp20x_adc_of_match,
|
||||
},
|
||||
.id_table = axp20x_adc_id_match,
|
||||
.probe = axp20x_probe,
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
@ -617,7 +617,7 @@ static struct platform_driver iproc_adc_driver = {
|
||||
.remove = iproc_adc_remove,
|
||||
.driver = {
|
||||
.name = "iproc-static-adc",
|
||||
.of_match_table = of_match_ptr(iproc_adc_of_match),
|
||||
.of_match_table = iproc_adc_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(iproc_adc_driver);
|
||||
|
@ -348,11 +348,9 @@ static int envelope_detector_probe(struct platform_device *pdev)
|
||||
indio_dev->num_channels = 1;
|
||||
|
||||
env->dac = devm_iio_channel_get(dev, "dac");
|
||||
if (IS_ERR(env->dac)) {
|
||||
if (PTR_ERR(env->dac) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get dac input channel\n");
|
||||
return PTR_ERR(env->dac);
|
||||
}
|
||||
if (IS_ERR(env->dac))
|
||||
return dev_err_probe(dev, PTR_ERR(env->dac),
|
||||
"failed to get dac input channel\n");
|
||||
|
||||
env->comp_irq = platform_get_irq_byname(pdev, "comp");
|
||||
if (env->comp_irq < 0)
|
||||
@ -360,11 +358,9 @@ static int envelope_detector_probe(struct platform_device *pdev)
|
||||
|
||||
ret = devm_request_irq(dev, env->comp_irq, envelope_detector_comp_isr,
|
||||
0, "envelope-detector", env);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to request interrupt\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to request interrupt\n");
|
||||
|
||||
env->comp_irq_trigger = irq_get_trigger_type(env->comp_irq);
|
||||
if (env->comp_irq_trigger & IRQF_TRIGGER_RISING)
|
||||
env->comp_irq_trigger_inv |= IRQF_TRIGGER_FALLING;
|
||||
|
@ -844,13 +844,9 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
info->vdd = devm_regulator_get(&pdev->dev, "vdd");
|
||||
if (IS_ERR(info->vdd)) {
|
||||
if (PTR_ERR(info->vdd) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
"failed getting regulator, err = %ld\n",
|
||||
PTR_ERR(info->vdd));
|
||||
return PTR_ERR(info->vdd);
|
||||
}
|
||||
if (IS_ERR(info->vdd))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(info->vdd),
|
||||
"failed getting regulator");
|
||||
|
||||
ret = regulator_enable(info->vdd);
|
||||
if (ret)
|
||||
|
@ -180,13 +180,9 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
|
||||
return ret;
|
||||
|
||||
ddata->ref = devm_regulator_get(dev, "vref");
|
||||
if (IS_ERR(ddata->ref)) {
|
||||
if (PTR_ERR(ddata->ref) != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get vref regulator: %pe\n",
|
||||
ddata->ref);
|
||||
|
||||
return PTR_ERR(ddata->ref);
|
||||
}
|
||||
if (IS_ERR(ddata->ref))
|
||||
return dev_err_probe(dev, PTR_ERR(ddata->ref),
|
||||
"Failed to get vref regulator\n");
|
||||
|
||||
ret = regulator_enable(ddata->ref);
|
||||
if (ret < 0) {
|
||||
|
@ -719,11 +719,8 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
|
||||
if (ret == -ENODEV)
|
||||
return 0;
|
||||
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(indio_dev->dev.parent,
|
||||
"failed to get temperature_calib cell\n");
|
||||
|
||||
return ret;
|
||||
return dev_err_probe(indio_dev->dev.parent, ret,
|
||||
"failed to get temperature_calib cell\n");
|
||||
}
|
||||
|
||||
priv->tsc_regmap =
|
||||
|
@ -495,12 +495,9 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(priv->regs);
|
||||
|
||||
priv->clk = devm_clk_get(dev, "fck");
|
||||
if (IS_ERR(priv->clk)) {
|
||||
ret = PTR_ERR(priv->clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get IF clock (ret=%i)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(priv->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->clk),
|
||||
"Failed to get IF clock\n");
|
||||
|
||||
ret = rcar_gyroadc_parse_subdevs(indio_dev);
|
||||
if (ret)
|
||||
|
@ -582,11 +582,9 @@ static int stm32_adc_core_switches_probe(struct device *dev,
|
||||
priv->syscfg = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
|
||||
if (IS_ERR(priv->syscfg)) {
|
||||
ret = PTR_ERR(priv->syscfg);
|
||||
if (ret != -ENODEV) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Can't probe syscfg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret, "Can't probe syscfg\n");
|
||||
|
||||
priv->syscfg = NULL;
|
||||
}
|
||||
|
||||
@ -596,12 +594,9 @@ static int stm32_adc_core_switches_probe(struct device *dev,
|
||||
priv->booster = devm_regulator_get_optional(dev, "booster");
|
||||
if (IS_ERR(priv->booster)) {
|
||||
ret = PTR_ERR(priv->booster);
|
||||
if (ret != -ENODEV) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "can't get booster %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret != -ENODEV)
|
||||
dev_err_probe(dev, ret, "can't get booster\n");
|
||||
|
||||
priv->booster = NULL;
|
||||
}
|
||||
}
|
||||
@ -612,11 +607,9 @@ static int stm32_adc_core_switches_probe(struct device *dev,
|
||||
priv->vdd = devm_regulator_get_optional(dev, "vdd");
|
||||
if (IS_ERR(priv->vdd)) {
|
||||
ret = PTR_ERR(priv->vdd);
|
||||
if (ret != -ENODEV) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "can't get vdd %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret, "can't get vdd\n");
|
||||
|
||||
priv->vdd = NULL;
|
||||
}
|
||||
}
|
||||
@ -669,42 +662,24 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
||||
priv->common.phys_base = res->start;
|
||||
|
||||
priv->vdda = devm_regulator_get(&pdev->dev, "vdda");
|
||||
if (IS_ERR(priv->vdda)) {
|
||||
ret = PTR_ERR(priv->vdda);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "vdda get failed, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(priv->vdda))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->vdda),
|
||||
"vdda get failed\n");
|
||||
|
||||
priv->vref = devm_regulator_get(&pdev->dev, "vref");
|
||||
if (IS_ERR(priv->vref)) {
|
||||
ret = PTR_ERR(priv->vref);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "vref get failed, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(priv->vref))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->vref),
|
||||
"vref get failed\n");
|
||||
|
||||
priv->aclk = devm_clk_get(&pdev->dev, "adc");
|
||||
if (IS_ERR(priv->aclk)) {
|
||||
ret = PTR_ERR(priv->aclk);
|
||||
if (ret != -ENOENT) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Can't get 'adc' clock\n");
|
||||
return ret;
|
||||
}
|
||||
priv->aclk = NULL;
|
||||
}
|
||||
priv->aclk = devm_clk_get_optional(&pdev->dev, "adc");
|
||||
if (IS_ERR(priv->aclk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->aclk),
|
||||
"Can't get 'adc' clock\n");
|
||||
|
||||
priv->bclk = devm_clk_get(&pdev->dev, "bus");
|
||||
if (IS_ERR(priv->bclk)) {
|
||||
ret = PTR_ERR(priv->bclk);
|
||||
if (ret != -ENOENT) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Can't get 'bus' clock\n");
|
||||
return ret;
|
||||
}
|
||||
priv->bclk = NULL;
|
||||
}
|
||||
priv->bclk = devm_clk_get_optional(&pdev->dev, "bus");
|
||||
if (IS_ERR(priv->bclk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->bclk),
|
||||
"Can't get 'bus' clock\n");
|
||||
|
||||
ret = stm32_adc_core_switches_probe(dev, priv);
|
||||
if (ret)
|
||||
|
@ -1805,13 +1805,9 @@ static int stm32_adc_dma_request(struct device *dev, struct iio_dev *indio_dev)
|
||||
adc->dma_chan = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(adc->dma_chan)) {
|
||||
ret = PTR_ERR(adc->dma_chan);
|
||||
if (ret != -ENODEV) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev,
|
||||
"DMA channel request failed with %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret,
|
||||
"DMA channel request failed with\n");
|
||||
|
||||
/* DMA is optional: fall back to IRQ mode */
|
||||
adc->dma_chan = NULL;
|
||||
|
@ -1473,13 +1473,9 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev)
|
||||
/* Optionally request DMA */
|
||||
ret = stm32_dfsdm_dma_request(dev, indio_dev);
|
||||
if (ret) {
|
||||
if (ret != -ENODEV) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev,
|
||||
"DMA channel request failed with %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret,
|
||||
"DMA channel request failed with\n");
|
||||
|
||||
dev_dbg(dev, "No DMA support\n");
|
||||
return 0;
|
||||
|
@ -243,12 +243,9 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
|
||||
* on use case.
|
||||
*/
|
||||
priv->clk = devm_clk_get(&pdev->dev, "dfsdm");
|
||||
if (IS_ERR(priv->clk)) {
|
||||
ret = PTR_ERR(priv->clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Failed to get clock (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(priv->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk),
|
||||
"Failed to get clock\n");
|
||||
|
||||
priv->aclk = devm_clk_get(&pdev->dev, "audio");
|
||||
if (IS_ERR(priv->aclk))
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
@ -153,17 +152,7 @@ static int adc081c_probe(struct i2c_client *client,
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (ACPI_COMPANION(&client->dev)) {
|
||||
const struct acpi_device_id *ad_id;
|
||||
|
||||
ad_id = acpi_match_device(client->dev.driver->acpi_match_table,
|
||||
&client->dev);
|
||||
if (!ad_id)
|
||||
return -ENODEV;
|
||||
model = &adcxx1c_models[ad_id->driver_data];
|
||||
} else {
|
||||
model = &adcxx1c_models[id->driver_data];
|
||||
}
|
||||
model = &adcxx1c_models[id->driver_data];
|
||||
|
||||
iio = devm_iio_device_alloc(&client->dev, sizeof(*adc));
|
||||
if (!iio)
|
||||
@ -238,21 +227,10 @@ static const struct of_device_id adc081c_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adc081c_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id adc081c_acpi_match[] = {
|
||||
{ "ADC081C", ADC081C },
|
||||
{ "ADC101C", ADC101C },
|
||||
{ "ADC121C", ADC121C },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, adc081c_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver adc081c_driver = {
|
||||
.driver = {
|
||||
.name = "adc081c",
|
||||
.of_match_table = adc081c_of_match,
|
||||
.acpi_match_table = ACPI_PTR(adc081c_acpi_match),
|
||||
},
|
||||
.probe = adc081c_probe,
|
||||
.remove = adc081c_remove,
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
@ -299,13 +300,11 @@ static int adc108s102_remove(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id adc108s102_of_match[] = {
|
||||
{ .compatible = "ti,adc108s102" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adc108s102_of_match);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id adc108s102_acpi_ids[] = {
|
||||
@ -324,7 +323,7 @@ MODULE_DEVICE_TABLE(spi, adc108s102_id);
|
||||
static struct spi_driver adc108s102_driver = {
|
||||
.driver = {
|
||||
.name = "adc108s102",
|
||||
.of_match_table = of_match_ptr(adc108s102_of_match),
|
||||
.of_match_table = adc108s102_of_match,
|
||||
.acpi_match_table = ACPI_PTR(adc108s102_acpi_ids),
|
||||
},
|
||||
.probe = adc108s102_probe,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
@ -220,7 +221,7 @@ MODULE_DEVICE_TABLE(acpi, adc128_acpi_match);
|
||||
static struct spi_driver adc128_driver = {
|
||||
.driver = {
|
||||
.name = "adc128s052",
|
||||
.of_match_table = of_match_ptr(adc128_of_match),
|
||||
.of_match_table = adc128_of_match,
|
||||
.acpi_match_table = ACPI_PTR(adc128_acpi_match),
|
||||
},
|
||||
.probe = adc128_probe,
|
||||
|
@ -276,11 +276,9 @@ static int rescale_probe(struct platform_device *pdev)
|
||||
int ret;
|
||||
|
||||
source = devm_iio_channel_get(dev, NULL);
|
||||
if (IS_ERR(source)) {
|
||||
if (PTR_ERR(source) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get source channel\n");
|
||||
return PTR_ERR(source);
|
||||
}
|
||||
if (IS_ERR(source))
|
||||
return dev_err_probe(dev, PTR_ERR(source),
|
||||
"failed to get source channel\n");
|
||||
|
||||
sizeof_ext_info = iio_get_channel_ext_info_count(source);
|
||||
if (sizeof_ext_info) {
|
||||
|
@ -18,6 +18,7 @@ config AD8366
|
||||
AD8366 Dual-Digital Variable Gain Amplifier (VGA)
|
||||
ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
|
||||
ADL5240 Digitally controlled variable gain amplifier (VGA)
|
||||
HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad8366.
|
||||
|
@ -201,12 +201,9 @@ static int hmc425a_probe(struct platform_device *pdev)
|
||||
st->gain = st->chip_info->default_gain;
|
||||
|
||||
st->gpios = devm_gpiod_get_array(&pdev->dev, "ctrl", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->gpios)) {
|
||||
ret = PTR_ERR(st->gpios);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "failed to get gpios\n");
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(st->gpios))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(st->gpios),
|
||||
"failed to get gpios\n");
|
||||
|
||||
if (st->gpios->ndescs != st->chip_info->num_gpios) {
|
||||
dev_err(&pdev->dev, "%d GPIOs needed to operate\n",
|
||||
|
@ -45,7 +45,8 @@ static struct dmaengine_buffer *iio_buffer_to_dmaengine_buffer(
|
||||
return container_of(buffer, struct dmaengine_buffer, queue.buffer);
|
||||
}
|
||||
|
||||
static void iio_dmaengine_buffer_block_done(void *data)
|
||||
static void iio_dmaengine_buffer_block_done(void *data,
|
||||
const struct dmaengine_result *result)
|
||||
{
|
||||
struct iio_dma_buffer_block *block = data;
|
||||
unsigned long flags;
|
||||
@ -53,6 +54,7 @@ static void iio_dmaengine_buffer_block_done(void *data)
|
||||
spin_lock_irqsave(&block->queue->list_lock, flags);
|
||||
list_del(&block->head);
|
||||
spin_unlock_irqrestore(&block->queue->list_lock, flags);
|
||||
block->bytes_used -= result->residue;
|
||||
iio_dma_buffer_block_done(block);
|
||||
}
|
||||
|
||||
@ -74,7 +76,7 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue,
|
||||
if (!desc)
|
||||
return -ENOMEM;
|
||||
|
||||
desc->callback = iio_dmaengine_buffer_block_done;
|
||||
desc->callback_result = iio_dmaengine_buffer_block_done;
|
||||
desc->callback_param = block;
|
||||
|
||||
cookie = dmaengine_submit(desc);
|
||||
|
@ -16,10 +16,13 @@
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
#define ATLAS_EZO_DRV_NAME "atlas-ezo-sensor"
|
||||
#define ATLAS_CO2_INT_TIME_IN_MS 950
|
||||
#define ATLAS_INT_TIME_IN_MS 950
|
||||
#define ATLAS_INT_HUM_TIME_IN_MS 350
|
||||
|
||||
enum {
|
||||
ATLAS_CO2_EZO,
|
||||
ATLAS_O2_EZO,
|
||||
ATLAS_HUM_EZO,
|
||||
};
|
||||
|
||||
struct atlas_ezo_device {
|
||||
@ -38,15 +41,37 @@ struct atlas_ezo_data {
|
||||
u8 buffer[8];
|
||||
};
|
||||
|
||||
#define ATLAS_CONCENTRATION_CHANNEL(_modifier) \
|
||||
{ \
|
||||
.type = IIO_CONCENTRATION, \
|
||||
.modified = 1,\
|
||||
.channel2 = _modifier, \
|
||||
.info_mask_separate = \
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.scan_index = 0, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 32, \
|
||||
.storagebits = 32, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec atlas_co2_ezo_channels[] = {
|
||||
ATLAS_CONCENTRATION_CHANNEL(IIO_MOD_CO2),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec atlas_o2_ezo_channels[] = {
|
||||
ATLAS_CONCENTRATION_CHANNEL(IIO_MOD_O2),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec atlas_hum_ezo_channels[] = {
|
||||
{
|
||||
.type = IIO_CONCENTRATION,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_CO2,
|
||||
.type = IIO_HUMIDITYRELATIVE,
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 32,
|
||||
.storagebits = 32,
|
||||
@ -59,10 +84,30 @@ static struct atlas_ezo_device atlas_ezo_devices[] = {
|
||||
[ATLAS_CO2_EZO] = {
|
||||
.channels = atlas_co2_ezo_channels,
|
||||
.num_channels = 1,
|
||||
.delay = ATLAS_CO2_INT_TIME_IN_MS,
|
||||
.delay = ATLAS_INT_TIME_IN_MS,
|
||||
},
|
||||
[ATLAS_O2_EZO] = {
|
||||
.channels = atlas_o2_ezo_channels,
|
||||
.num_channels = 1,
|
||||
.delay = ATLAS_INT_TIME_IN_MS,
|
||||
},
|
||||
[ATLAS_HUM_EZO] = {
|
||||
.channels = atlas_hum_ezo_channels,
|
||||
.num_channels = 1,
|
||||
.delay = ATLAS_INT_HUM_TIME_IN_MS,
|
||||
},
|
||||
};
|
||||
|
||||
static void atlas_ezo_sanitize(char *buf)
|
||||
{
|
||||
char *ptr = strchr(buf, '.');
|
||||
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
memmove(ptr, ptr + 1, strlen(ptr));
|
||||
}
|
||||
|
||||
static int atlas_ezo_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
@ -96,6 +141,9 @@ static int atlas_ezo_read_raw(struct iio_dev *indio_dev,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* removing floating point for fixed number representation */
|
||||
atlas_ezo_sanitize(data->buffer + 2);
|
||||
|
||||
ret = kstrtol(data->buffer + 1, 10, &tmp);
|
||||
|
||||
*val = tmp;
|
||||
@ -105,9 +153,27 @@ static int atlas_ezo_read_raw(struct iio_dev *indio_dev,
|
||||
return ret ? ret : IIO_VAL_INT;
|
||||
}
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
*val2 = 100; /* 0.0001 */
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
switch (chan->type) {
|
||||
case IIO_HUMIDITYRELATIVE:
|
||||
*val = 10;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CONCENTRATION:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* IIO_CONCENTRATION modifiers */
|
||||
switch (chan->channel2) {
|
||||
case IIO_MOD_CO2:
|
||||
*val = 0;
|
||||
*val2 = 100; /* 0.0001 */
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_MOD_O2:
|
||||
*val = 100;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -119,12 +185,16 @@ static const struct iio_info atlas_info = {
|
||||
|
||||
static const struct i2c_device_id atlas_ezo_id[] = {
|
||||
{ "atlas-co2-ezo", ATLAS_CO2_EZO },
|
||||
{ "atlas-o2-ezo", ATLAS_O2_EZO },
|
||||
{ "atlas-hum-ezo", ATLAS_HUM_EZO },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, atlas_ezo_id);
|
||||
|
||||
static const struct of_device_id atlas_ezo_dt_ids[] = {
|
||||
{ .compatible = "atlas,co2-ezo", .data = (void *)ATLAS_CO2_EZO, },
|
||||
{ .compatible = "atlas,o2-ezo", .data = (void *)ATLAS_O2_EZO, },
|
||||
{ .compatible = "atlas,hum-ezo", .data = (void *)ATLAS_HUM_EZO, },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids);
|
||||
|
@ -705,13 +705,8 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
|
||||
indio_dev->available_scan_masks = scd30_scan_masks;
|
||||
|
||||
state->vdd = devm_regulator_get(dev, "vdd");
|
||||
if (IS_ERR(state->vdd)) {
|
||||
if (PTR_ERR(state->vdd) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_err(dev, "failed to get regulator\n");
|
||||
return PTR_ERR(state->vdd);
|
||||
}
|
||||
if (IS_ERR(state->vdd))
|
||||
return dev_err_probe(dev, PTR_ERR(state->vdd), "failed to get regulator\n");
|
||||
|
||||
ret = regulator_enable(state->vdd);
|
||||
if (ret)
|
||||
|
@ -206,12 +206,12 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
|
||||
}
|
||||
|
||||
#define DECLARE_AD5693_CHANNELS(name, bits, _shift) \
|
||||
static struct iio_chan_spec name[] = { \
|
||||
static const struct iio_chan_spec name[] = { \
|
||||
AD5868_CHANNEL(0, 0, bits, _shift), \
|
||||
}
|
||||
|
||||
#define DECLARE_AD5686_CHANNELS(name, bits, _shift) \
|
||||
static struct iio_chan_spec name[] = { \
|
||||
static const struct iio_chan_spec name[] = { \
|
||||
AD5868_CHANNEL(0, 1, bits, _shift), \
|
||||
AD5868_CHANNEL(1, 2, bits, _shift), \
|
||||
AD5868_CHANNEL(2, 4, bits, _shift), \
|
||||
@ -219,7 +219,7 @@ static struct iio_chan_spec name[] = { \
|
||||
}
|
||||
|
||||
#define DECLARE_AD5676_CHANNELS(name, bits, _shift) \
|
||||
static struct iio_chan_spec name[] = { \
|
||||
static const struct iio_chan_spec name[] = { \
|
||||
AD5868_CHANNEL(0, 0, bits, _shift), \
|
||||
AD5868_CHANNEL(1, 1, bits, _shift), \
|
||||
AD5868_CHANNEL(2, 2, bits, _shift), \
|
||||
@ -231,7 +231,7 @@ static struct iio_chan_spec name[] = { \
|
||||
}
|
||||
|
||||
#define DECLARE_AD5679_CHANNELS(name, bits, _shift) \
|
||||
static struct iio_chan_spec name[] = { \
|
||||
static const struct iio_chan_spec name[] = { \
|
||||
AD5868_CHANNEL(0, 0, bits, _shift), \
|
||||
AD5868_CHANNEL(1, 1, bits, _shift), \
|
||||
AD5868_CHANNEL(2, 2, bits, _shift), \
|
||||
|
@ -104,7 +104,7 @@ typedef int (*ad5686_read_func)(struct ad5686_state *st, u8 addr);
|
||||
struct ad5686_chip_info {
|
||||
u16 int_vref_mv;
|
||||
unsigned int num_channels;
|
||||
struct iio_chan_spec *channels;
|
||||
const struct iio_chan_spec *channels;
|
||||
enum ad5686_regmap_type regmap_type;
|
||||
};
|
||||
|
||||
|
@ -183,18 +183,14 @@ static int dpot_dac_probe(struct platform_device *pdev)
|
||||
indio_dev->num_channels = 1;
|
||||
|
||||
dac->vref = devm_regulator_get(dev, "vref");
|
||||
if (IS_ERR(dac->vref)) {
|
||||
if (PTR_ERR(dac->vref) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "failed to get vref regulator\n");
|
||||
return PTR_ERR(dac->vref);
|
||||
}
|
||||
if (IS_ERR(dac->vref))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(dac->vref),
|
||||
"failed to get vref regulator\n");
|
||||
|
||||
dac->dpot = devm_iio_channel_get(dev, "dpot");
|
||||
if (IS_ERR(dac->dpot)) {
|
||||
if (PTR_ERR(dac->dpot) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get dpot input channel\n");
|
||||
return PTR_ERR(dac->dpot);
|
||||
}
|
||||
if (IS_ERR(dac->dpot))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(dac->dpot),
|
||||
"failed to get dpot input channel\n");
|
||||
|
||||
ret = iio_get_channel_type(dac->dpot, &type);
|
||||
if (ret < 0)
|
||||
|
@ -150,10 +150,7 @@ static int stm32_dac_probe(struct platform_device *pdev)
|
||||
rst = devm_reset_control_get_optional_exclusive(dev, NULL);
|
||||
if (rst) {
|
||||
if (IS_ERR(rst)) {
|
||||
ret = PTR_ERR(rst);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "reset get failed, %d\n", ret);
|
||||
|
||||
ret = dev_err_probe(dev, PTR_ERR(rst), "reset get failed\n");
|
||||
goto err_hw_stop;
|
||||
}
|
||||
|
||||
|
@ -47,8 +47,8 @@ struct dac5571_data {
|
||||
struct mutex lock;
|
||||
struct regulator *vref;
|
||||
u16 val[4];
|
||||
bool powerdown;
|
||||
u8 powerdown_mode;
|
||||
bool powerdown[4];
|
||||
u8 powerdown_mode[4];
|
||||
struct dac5571_spec const *spec;
|
||||
int (*dac5571_cmd)(struct dac5571_data *data, int channel, u16 val);
|
||||
int (*dac5571_pwrdwn)(struct dac5571_data *data, int channel, u8 pwrdwn);
|
||||
@ -125,7 +125,7 @@ static int dac5571_get_powerdown_mode(struct iio_dev *indio_dev,
|
||||
{
|
||||
struct dac5571_data *data = iio_priv(indio_dev);
|
||||
|
||||
return data->powerdown_mode;
|
||||
return data->powerdown_mode[chan->channel];
|
||||
}
|
||||
|
||||
static int dac5571_set_powerdown_mode(struct iio_dev *indio_dev,
|
||||
@ -135,17 +135,17 @@ static int dac5571_set_powerdown_mode(struct iio_dev *indio_dev,
|
||||
struct dac5571_data *data = iio_priv(indio_dev);
|
||||
int ret = 0;
|
||||
|
||||
if (data->powerdown_mode == mode)
|
||||
if (data->powerdown_mode[chan->channel] == mode)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
if (data->powerdown) {
|
||||
if (data->powerdown[chan->channel]) {
|
||||
ret = data->dac5571_pwrdwn(data, chan->channel,
|
||||
DAC5571_POWERDOWN(mode));
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
data->powerdown_mode = mode;
|
||||
data->powerdown_mode[chan->channel] = mode;
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->lock);
|
||||
@ -167,7 +167,7 @@ static ssize_t dac5571_read_powerdown(struct iio_dev *indio_dev,
|
||||
{
|
||||
struct dac5571_data *data = iio_priv(indio_dev);
|
||||
|
||||
return sprintf(buf, "%d\n", data->powerdown);
|
||||
return sprintf(buf, "%d\n", data->powerdown[chan->channel]);
|
||||
}
|
||||
|
||||
static ssize_t dac5571_write_powerdown(struct iio_dev *indio_dev,
|
||||
@ -183,19 +183,20 @@ static ssize_t dac5571_write_powerdown(struct iio_dev *indio_dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (data->powerdown == powerdown)
|
||||
if (data->powerdown[chan->channel] == powerdown)
|
||||
return len;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
if (powerdown)
|
||||
ret = data->dac5571_pwrdwn(data, chan->channel,
|
||||
DAC5571_POWERDOWN(data->powerdown_mode));
|
||||
DAC5571_POWERDOWN(data->powerdown_mode[chan->channel]));
|
||||
else
|
||||
ret = data->dac5571_cmd(data, chan->channel, data->val[0]);
|
||||
ret = data->dac5571_cmd(data, chan->channel,
|
||||
data->val[chan->channel]);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
data->powerdown = powerdown;
|
||||
data->powerdown[chan->channel] = powerdown;
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->lock);
|
||||
@ -209,9 +210,9 @@ static const struct iio_chan_spec_ext_info dac5571_ext_info[] = {
|
||||
.name = "powerdown",
|
||||
.read = dac5571_read_powerdown,
|
||||
.write = dac5571_write_powerdown,
|
||||
.shared = IIO_SHARED_BY_TYPE,
|
||||
.shared = IIO_SEPARATE,
|
||||
},
|
||||
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &dac5571_powerdown_mode),
|
||||
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &dac5571_powerdown_mode),
|
||||
IIO_ENUM_AVAILABLE("powerdown_mode", &dac5571_powerdown_mode),
|
||||
{},
|
||||
};
|
||||
@ -276,7 +277,7 @@ static int dac5571_write_raw(struct iio_dev *indio_dev,
|
||||
if (val >= (1 << data->spec->resolution) || val < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (data->powerdown)
|
||||
if (data->powerdown[chan->channel])
|
||||
return -EBUSY;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
@ -969,6 +969,13 @@ static int ad9523_setup(struct iio_dev *indio_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ad9523_reg_disable(void *data)
|
||||
{
|
||||
struct regulator *reg = data;
|
||||
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static int ad9523_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad9523_platform_data *pdata = spi->dev.platform_data;
|
||||
@ -994,21 +1001,22 @@ static int ad9523_probe(struct spi_device *spi)
|
||||
ret = regulator_enable(st->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad9523_reg_disable,
|
||||
st->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(st->pwrdown_gpio)) {
|
||||
ret = PTR_ERR(st->pwrdown_gpio);
|
||||
goto error_disable_reg;
|
||||
}
|
||||
if (IS_ERR(st->pwrdown_gpio))
|
||||
return PTR_ERR(st->pwrdown_gpio);
|
||||
|
||||
st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->reset_gpio)) {
|
||||
ret = PTR_ERR(st->reset_gpio);
|
||||
goto error_disable_reg;
|
||||
}
|
||||
if (IS_ERR(st->reset_gpio))
|
||||
return PTR_ERR(st->reset_gpio);
|
||||
|
||||
if (st->reset_gpio) {
|
||||
udelay(1);
|
||||
@ -1017,10 +1025,8 @@ static int ad9523_probe(struct spi_device *spi)
|
||||
|
||||
st->sync_gpio = devm_gpiod_get_optional(&spi->dev, "sync",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(st->sync_gpio)) {
|
||||
ret = PTR_ERR(st->sync_gpio);
|
||||
goto error_disable_reg;
|
||||
}
|
||||
if (IS_ERR(st->sync_gpio))
|
||||
return PTR_ERR(st->sync_gpio);
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
st->spi = spi;
|
||||
@ -1035,34 +1041,9 @@ static int ad9523_probe(struct spi_device *spi)
|
||||
|
||||
ret = ad9523_setup(indio_dev);
|
||||
if (ret < 0)
|
||||
goto error_disable_reg;
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto error_disable_reg;
|
||||
|
||||
dev_info(&spi->dev, "probed %s\n", indio_dev->name);
|
||||
|
||||
return 0;
|
||||
|
||||
error_disable_reg:
|
||||
if (!IS_ERR(st->reg))
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad9523_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ad9523_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
if (!IS_ERR(st->reg))
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return 0;
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad9523_id[] = {
|
||||
@ -1076,7 +1057,6 @@ static struct spi_driver ad9523_driver = {
|
||||
.name = "ad9523",
|
||||
},
|
||||
.probe = ad9523_probe,
|
||||
.remove = ad9523_remove,
|
||||
.id_table = ad9523_id,
|
||||
};
|
||||
module_spi_driver(ad9523_driver);
|
||||
|
@ -41,6 +41,16 @@ config ADIS16260
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adis16260.
|
||||
|
||||
config ADXRS290
|
||||
tristate "Analog Devices ADXRS290 Dual-Axis MEMS Gyroscope SPI driver"
|
||||
depends on SPI
|
||||
help
|
||||
Say yes here to build support for Analog Devices ADXRS290 programmable
|
||||
digital output gyroscope.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called adxrs290.
|
||||
|
||||
config ADXRS450
|
||||
tristate "Analog Devices ADXRS450/3 Digital Output Gyroscope SPI driver"
|
||||
depends on SPI
|
||||
|
@ -8,6 +8,7 @@ obj-$(CONFIG_ADIS16080) += adis16080.o
|
||||
obj-$(CONFIG_ADIS16130) += adis16130.o
|
||||
obj-$(CONFIG_ADIS16136) += adis16136.o
|
||||
obj-$(CONFIG_ADIS16260) += adis16260.o
|
||||
obj-$(CONFIG_ADXRS290) += adxrs290.o
|
||||
obj-$(CONFIG_ADXRS450) += adxrs450.o
|
||||
obj-$(CONFIG_BMG160) += bmg160_core.o
|
||||
obj-$(CONFIG_BMG160_I2C) += bmg160_i2c.o
|
||||
|
446
drivers/iio/gyro/adxrs290.c
Normal file
446
drivers/iio/gyro/adxrs290.c
Normal file
@ -0,0 +1,446 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* ADXRS290 SPI Gyroscope Driver
|
||||
*
|
||||
* Copyright (C) 2020 Nishant Malpani <nish.malpani25@gmail.com>
|
||||
* Copyright (C) 2020 Analog Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#define ADXRS290_ADI_ID 0xAD
|
||||
#define ADXRS290_MEMS_ID 0x1D
|
||||
#define ADXRS290_DEV_ID 0x92
|
||||
|
||||
#define ADXRS290_REG_ADI_ID 0x00
|
||||
#define ADXRS290_REG_MEMS_ID 0x01
|
||||
#define ADXRS290_REG_DEV_ID 0x02
|
||||
#define ADXRS290_REG_REV_ID 0x03
|
||||
#define ADXRS290_REG_SN0 0x04 /* Serial Number Registers, 4 bytes */
|
||||
#define ADXRS290_REG_DATAX0 0x08 /* Roll Rate o/p Data Regs, 2 bytes */
|
||||
#define ADXRS290_REG_DATAY0 0x0A /* Pitch Rate o/p Data Regs, 2 bytes */
|
||||
#define ADXRS290_REG_TEMP0 0x0C
|
||||
#define ADXRS290_REG_POWER_CTL 0x10
|
||||
#define ADXRS290_REG_FILTER 0x11
|
||||
#define ADXRS290_REG_DATA_RDY 0x12
|
||||
|
||||
#define ADXRS290_READ BIT(7)
|
||||
#define ADXRS290_TSM BIT(0)
|
||||
#define ADXRS290_MEASUREMENT BIT(1)
|
||||
#define ADXRS290_SYNC GENMASK(1, 0)
|
||||
#define ADXRS290_LPF_MASK GENMASK(2, 0)
|
||||
#define ADXRS290_LPF(x) FIELD_PREP(ADXRS290_LPF_MASK, x)
|
||||
#define ADXRS290_HPF_MASK GENMASK(7, 4)
|
||||
#define ADXRS290_HPF(x) FIELD_PREP(ADXRS290_HPF_MASK, x)
|
||||
|
||||
#define ADXRS290_READ_REG(reg) (ADXRS290_READ | (reg))
|
||||
|
||||
#define ADXRS290_MAX_TRANSITION_TIME_MS 100
|
||||
|
||||
enum adxrs290_mode {
|
||||
ADXRS290_MODE_STANDBY,
|
||||
ADXRS290_MODE_MEASUREMENT,
|
||||
};
|
||||
|
||||
struct adxrs290_state {
|
||||
struct spi_device *spi;
|
||||
/* Serialize reads and their subsequent processing */
|
||||
struct mutex lock;
|
||||
enum adxrs290_mode mode;
|
||||
unsigned int lpf_3db_freq_idx;
|
||||
unsigned int hpf_3db_freq_idx;
|
||||
};
|
||||
|
||||
/*
|
||||
* Available cut-off frequencies of the low pass filter in Hz.
|
||||
* The integer part and fractional part are represented separately.
|
||||
*/
|
||||
static const int adxrs290_lpf_3db_freq_hz_table[][2] = {
|
||||
[0] = {480, 0},
|
||||
[1] = {320, 0},
|
||||
[2] = {160, 0},
|
||||
[3] = {80, 0},
|
||||
[4] = {56, 600000},
|
||||
[5] = {40, 0},
|
||||
[6] = {28, 300000},
|
||||
[7] = {20, 0},
|
||||
};
|
||||
|
||||
/*
|
||||
* Available cut-off frequencies of the high pass filter in Hz.
|
||||
* The integer part and fractional part are represented separately.
|
||||
*/
|
||||
static const int adxrs290_hpf_3db_freq_hz_table[][2] = {
|
||||
[0] = {0, 0},
|
||||
[1] = {0, 11000},
|
||||
[2] = {0, 22000},
|
||||
[3] = {0, 44000},
|
||||
[4] = {0, 87000},
|
||||
[5] = {0, 175000},
|
||||
[6] = {0, 350000},
|
||||
[7] = {0, 700000},
|
||||
[8] = {1, 400000},
|
||||
[9] = {2, 800000},
|
||||
[10] = {11, 300000},
|
||||
};
|
||||
|
||||
static int adxrs290_get_rate_data(struct iio_dev *indio_dev, const u8 cmd, int *val)
|
||||
{
|
||||
struct adxrs290_state *st = iio_priv(indio_dev);
|
||||
int ret = 0;
|
||||
int temp;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
temp = spi_w8r16(st->spi, cmd);
|
||||
if (temp < 0) {
|
||||
ret = temp;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
*val = temp;
|
||||
|
||||
err_unlock:
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adxrs290_get_temp_data(struct iio_dev *indio_dev, int *val)
|
||||
{
|
||||
const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_TEMP0);
|
||||
struct adxrs290_state *st = iio_priv(indio_dev);
|
||||
int ret = 0;
|
||||
int temp;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
temp = spi_w8r16(st->spi, cmd);
|
||||
if (temp < 0) {
|
||||
ret = temp;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
/* extract lower 12 bits temperature reading */
|
||||
*val = temp & 0x0FFF;
|
||||
|
||||
err_unlock:
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adxrs290_get_3db_freq(struct iio_dev *indio_dev, u8 *val, u8 *val2)
|
||||
{
|
||||
const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_FILTER);
|
||||
struct adxrs290_state *st = iio_priv(indio_dev);
|
||||
int ret = 0;
|
||||
short temp;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
temp = spi_w8r8(st->spi, cmd);
|
||||
if (temp < 0) {
|
||||
ret = temp;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
*val = FIELD_GET(ADXRS290_LPF_MASK, temp);
|
||||
*val2 = FIELD_GET(ADXRS290_HPF_MASK, temp);
|
||||
|
||||
err_unlock:
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adxrs290_spi_write_reg(struct spi_device *spi, const u8 reg,
|
||||
const u8 val)
|
||||
{
|
||||
u8 buf[2];
|
||||
|
||||
buf[0] = reg;
|
||||
buf[1] = val;
|
||||
|
||||
return spi_write_then_read(spi, buf, ARRAY_SIZE(buf), NULL, 0);
|
||||
}
|
||||
|
||||
static int adxrs290_find_match(const int (*freq_tbl)[2], const int n,
|
||||
const int val, const int val2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (freq_tbl[i][0] == val && freq_tbl[i][1] == val2)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adxrs290_set_filter_freq(struct iio_dev *indio_dev,
|
||||
const unsigned int lpf_idx,
|
||||
const unsigned int hpf_idx)
|
||||
{
|
||||
struct adxrs290_state *st = iio_priv(indio_dev);
|
||||
u8 val;
|
||||
|
||||
val = ADXRS290_HPF(hpf_idx) | ADXRS290_LPF(lpf_idx);
|
||||
|
||||
return adxrs290_spi_write_reg(st->spi, ADXRS290_REG_FILTER, val);
|
||||
}
|
||||
|
||||
static int adxrs290_initial_setup(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct adxrs290_state *st = iio_priv(indio_dev);
|
||||
|
||||
st->mode = ADXRS290_MODE_MEASUREMENT;
|
||||
|
||||
return adxrs290_spi_write_reg(st->spi,
|
||||
ADXRS290_REG_POWER_CTL,
|
||||
ADXRS290_MEASUREMENT | ADXRS290_TSM);
|
||||
}
|
||||
|
||||
static int adxrs290_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
int *val2,
|
||||
long mask)
|
||||
{
|
||||
struct adxrs290_state *st = iio_priv(indio_dev);
|
||||
unsigned int t;
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
switch (chan->type) {
|
||||
case IIO_ANGL_VEL:
|
||||
ret = adxrs290_get_rate_data(indio_dev,
|
||||
ADXRS290_READ_REG(chan->address),
|
||||
val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_TEMP:
|
||||
ret = adxrs290_get_temp_data(indio_dev, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_ANGL_VEL:
|
||||
/* 1 LSB = 0.005 degrees/sec */
|
||||
*val = 0;
|
||||
*val2 = 87266;
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
case IIO_TEMP:
|
||||
/* 1 LSB = 0.1 degrees Celsius */
|
||||
*val = 100;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
switch (chan->type) {
|
||||
case IIO_ANGL_VEL:
|
||||
t = st->lpf_3db_freq_idx;
|
||||
*val = adxrs290_lpf_3db_freq_hz_table[t][0];
|
||||
*val2 = adxrs290_lpf_3db_freq_hz_table[t][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
|
||||
switch (chan->type) {
|
||||
case IIO_ANGL_VEL:
|
||||
t = st->hpf_3db_freq_idx;
|
||||
*val = adxrs290_hpf_3db_freq_hz_table[t][0];
|
||||
*val2 = adxrs290_hpf_3db_freq_hz_table[t][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adxrs290_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val,
|
||||
int val2,
|
||||
long mask)
|
||||
{
|
||||
struct adxrs290_state *st = iio_priv(indio_dev);
|
||||
int lpf_idx, hpf_idx;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
lpf_idx = adxrs290_find_match(adxrs290_lpf_3db_freq_hz_table,
|
||||
ARRAY_SIZE(adxrs290_lpf_3db_freq_hz_table),
|
||||
val, val2);
|
||||
if (lpf_idx < 0)
|
||||
return -EINVAL;
|
||||
/* caching the updated state of the low-pass filter */
|
||||
st->lpf_3db_freq_idx = lpf_idx;
|
||||
/* retrieving the current state of the high-pass filter */
|
||||
hpf_idx = st->hpf_3db_freq_idx;
|
||||
return adxrs290_set_filter_freq(indio_dev, lpf_idx, hpf_idx);
|
||||
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
|
||||
hpf_idx = adxrs290_find_match(adxrs290_hpf_3db_freq_hz_table,
|
||||
ARRAY_SIZE(adxrs290_hpf_3db_freq_hz_table),
|
||||
val, val2);
|
||||
if (hpf_idx < 0)
|
||||
return -EINVAL;
|
||||
/* caching the updated state of the high-pass filter */
|
||||
st->hpf_3db_freq_idx = hpf_idx;
|
||||
/* retrieving the current state of the low-pass filter */
|
||||
lpf_idx = st->lpf_3db_freq_idx;
|
||||
return adxrs290_set_filter_freq(indio_dev, lpf_idx, hpf_idx);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adxrs290_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length,
|
||||
long mask)
|
||||
{
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
*vals = (const int *)adxrs290_lpf_3db_freq_hz_table;
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
/* Values are stored in a 2D matrix */
|
||||
*length = ARRAY_SIZE(adxrs290_lpf_3db_freq_hz_table) * 2;
|
||||
|
||||
return IIO_AVAIL_LIST;
|
||||
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
|
||||
*vals = (const int *)adxrs290_hpf_3db_freq_hz_table;
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
/* Values are stored in a 2D matrix */
|
||||
*length = ARRAY_SIZE(adxrs290_hpf_3db_freq_hz_table) * 2;
|
||||
|
||||
return IIO_AVAIL_LIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
#define ADXRS290_ANGL_VEL_CHANNEL(reg, axis) { \
|
||||
.type = IIO_ANGL_VEL, \
|
||||
.address = reg, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
|
||||
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
|
||||
.info_mask_shared_by_type_available = \
|
||||
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
|
||||
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec adxrs290_channels[] = {
|
||||
ADXRS290_ANGL_VEL_CHANNEL(ADXRS290_REG_DATAX0, X),
|
||||
ADXRS290_ANGL_VEL_CHANNEL(ADXRS290_REG_DATAY0, Y),
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.address = ADXRS290_REG_TEMP0,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_info adxrs290_info = {
|
||||
.read_raw = &adxrs290_read_raw,
|
||||
.write_raw = &adxrs290_write_raw,
|
||||
.read_avail = &adxrs290_read_avail,
|
||||
};
|
||||
|
||||
static int adxrs290_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct adxrs290_state *st;
|
||||
u8 val, val2;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
st->spi = spi;
|
||||
|
||||
indio_dev->name = "adxrs290";
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = adxrs290_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adxrs290_channels);
|
||||
indio_dev->info = &adxrs290_info;
|
||||
|
||||
mutex_init(&st->lock);
|
||||
|
||||
val = spi_w8r8(spi, ADXRS290_READ_REG(ADXRS290_REG_ADI_ID));
|
||||
if (val != ADXRS290_ADI_ID) {
|
||||
dev_err(&spi->dev, "Wrong ADI ID 0x%02x\n", val);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
val = spi_w8r8(spi, ADXRS290_READ_REG(ADXRS290_REG_MEMS_ID));
|
||||
if (val != ADXRS290_MEMS_ID) {
|
||||
dev_err(&spi->dev, "Wrong MEMS ID 0x%02x\n", val);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
val = spi_w8r8(spi, ADXRS290_READ_REG(ADXRS290_REG_DEV_ID));
|
||||
if (val != ADXRS290_DEV_ID) {
|
||||
dev_err(&spi->dev, "Wrong DEV ID 0x%02x\n", val);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* default mode the gyroscope starts in */
|
||||
st->mode = ADXRS290_MODE_STANDBY;
|
||||
|
||||
/* switch to measurement mode and switch on the temperature sensor */
|
||||
ret = adxrs290_initial_setup(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* max transition time to measurement mode */
|
||||
msleep(ADXRS290_MAX_TRANSITION_TIME_MS);
|
||||
|
||||
ret = adxrs290_get_3db_freq(indio_dev, &val, &val2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st->lpf_3db_freq_idx = val;
|
||||
st->hpf_3db_freq_idx = val2;
|
||||
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id adxrs290_of_match[] = {
|
||||
{ .compatible = "adi,adxrs290" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adxrs290_of_match);
|
||||
|
||||
static struct spi_driver adxrs290_driver = {
|
||||
.driver = {
|
||||
.name = "adxrs290",
|
||||
.of_match_table = adxrs290_of_match,
|
||||
},
|
||||
.probe = adxrs290_probe,
|
||||
};
|
||||
module_spi_driver(adxrs290_driver);
|
||||
|
||||
MODULE_AUTHOR("Nishant Malpani <nish.malpani25@gmail.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices ADXRS290 Gyroscope SPI driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -2,7 +2,7 @@
|
||||
/*
|
||||
* max30102.c - Support for MAX30102 heart rate and pulse oximeter sensor
|
||||
*
|
||||
* Copyright (C) 2017 Matt Ranostay <matt@ranostay.consulting>
|
||||
* Copyright (C) 2017 Matt Ranostay <matt.ranostay@konsulko.com>
|
||||
*
|
||||
* Support for MAX30105 optical particle sensor
|
||||
* Copyright (C) 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
|
||||
@ -632,6 +632,6 @@ static struct i2c_driver max30102_driver = {
|
||||
};
|
||||
module_i2c_driver(max30102_driver);
|
||||
|
||||
MODULE_AUTHOR("Matt Ranostay <matt@ranostay.consulting>");
|
||||
MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
|
||||
MODULE_DESCRIPTION("MAX30102 heart rate/pulse oximeter and MAX30105 particle sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -38,6 +38,16 @@ config HDC100X
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called hdc100x.
|
||||
|
||||
config HDC2010
|
||||
tristate "TI HDC2010 relative humidity and temperature sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for the Texas Instruments
|
||||
HDC2010 and HDC2080 relative humidity and temperature sensors.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called hdc2010.
|
||||
|
||||
config HID_SENSOR_HUMIDITY
|
||||
tristate "HID Environmental humidity sensor"
|
||||
depends on HID_SENSOR_HUB
|
||||
|
@ -6,6 +6,7 @@
|
||||
obj-$(CONFIG_AM2315) += am2315.o
|
||||
obj-$(CONFIG_DHT11) += dht11.o
|
||||
obj-$(CONFIG_HDC100X) += hdc100x.o
|
||||
obj-$(CONFIG_HDC2010) += hdc2010.o
|
||||
obj-$(CONFIG_HID_SENSOR_HUMIDITY) += hid-sensor-humidity.o
|
||||
|
||||
hts221-y := hts221_core.o \
|
||||
|
353
drivers/iio/humidity/hdc2010.c
Normal file
353
drivers/iio/humidity/hdc2010.c
Normal file
@ -0,0 +1,353 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* hdc2010.c - Support for the TI HDC2010 and HDC2080
|
||||
* temperature + relative humidity sensors
|
||||
*
|
||||
* Copyright (C) 2020 Norphonic AS
|
||||
* Author: Eugene Zaikonnikov <ez@norphonic.com>
|
||||
*
|
||||
* Datasheet: https://www.ti.com/product/HDC2010/datasheet
|
||||
* Datasheet: https://www.ti.com/product/HDC2080/datasheet
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#define HDC2010_REG_TEMP_LOW 0x00
|
||||
#define HDC2010_REG_TEMP_HIGH 0x01
|
||||
#define HDC2010_REG_HUMIDITY_LOW 0x02
|
||||
#define HDC2010_REG_HUMIDITY_HIGH 0x03
|
||||
#define HDC2010_REG_INTERRUPT_DRDY 0x04
|
||||
#define HDC2010_REG_TEMP_MAX 0x05
|
||||
#define HDC2010_REG_HUMIDITY_MAX 0x06
|
||||
#define HDC2010_REG_INTERRUPT_EN 0x07
|
||||
#define HDC2010_REG_TEMP_OFFSET_ADJ 0x08
|
||||
#define HDC2010_REG_HUMIDITY_OFFSET_ADJ 0x09
|
||||
#define HDC2010_REG_TEMP_THR_L 0x0a
|
||||
#define HDC2010_REG_TEMP_THR_H 0x0b
|
||||
#define HDC2010_REG_RH_THR_L 0x0c
|
||||
#define HDC2010_REG_RH_THR_H 0x0d
|
||||
#define HDC2010_REG_RESET_DRDY_INT_CONF 0x0e
|
||||
#define HDC2010_REG_MEASUREMENT_CONF 0x0f
|
||||
|
||||
#define HDC2010_MEAS_CONF GENMASK(2, 1)
|
||||
#define HDC2010_MEAS_TRIG BIT(0)
|
||||
#define HDC2010_HEATER_EN BIT(3)
|
||||
#define HDC2010_AMM GENMASK(6, 4)
|
||||
|
||||
struct hdc2010_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
u8 measurement_config;
|
||||
u8 interrupt_config;
|
||||
u8 drdy_config;
|
||||
};
|
||||
|
||||
enum hdc2010_addr_groups {
|
||||
HDC2010_GROUP_TEMP = 0,
|
||||
HDC2010_GROUP_HUMIDITY,
|
||||
};
|
||||
|
||||
struct hdc2010_reg_record {
|
||||
unsigned long primary;
|
||||
unsigned long peak;
|
||||
};
|
||||
|
||||
static const struct hdc2010_reg_record hdc2010_reg_translation[] = {
|
||||
[HDC2010_GROUP_TEMP] = {
|
||||
.primary = HDC2010_REG_TEMP_LOW,
|
||||
.peak = HDC2010_REG_TEMP_MAX,
|
||||
},
|
||||
[HDC2010_GROUP_HUMIDITY] = {
|
||||
.primary = HDC2010_REG_HUMIDITY_LOW,
|
||||
.peak = HDC2010_REG_HUMIDITY_MAX,
|
||||
},
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR(out_current_heater_raw_available, "0 1");
|
||||
|
||||
static struct attribute *hdc2010_attributes[] = {
|
||||
&iio_const_attr_out_current_heater_raw_available.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hdc2010_attribute_group = {
|
||||
.attrs = hdc2010_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec hdc2010_channels[] = {
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.address = HDC2010_GROUP_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_PEAK) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
{
|
||||
.type = IIO_HUMIDITYRELATIVE,
|
||||
.address = HDC2010_GROUP_HUMIDITY,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_PEAK) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
{
|
||||
.type = IIO_CURRENT,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.extend_name = "heater",
|
||||
.output = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static int hdc2010_update_drdy_config(struct hdc2010_data *data,
|
||||
char mask, char val)
|
||||
{
|
||||
u8 tmp = (~mask & data->drdy_config) | val;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
HDC2010_REG_RESET_DRDY_INT_CONF, tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->drdy_config = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdc2010_get_prim_measurement_word(struct hdc2010_data *data,
|
||||
struct iio_chan_spec const *chan)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
s32 ret;
|
||||
|
||||
ret = i2c_smbus_read_word_data(client,
|
||||
hdc2010_reg_translation[chan->address].primary);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Could not read sensor measurement word\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hdc2010_get_peak_measurement_byte(struct hdc2010_data *data,
|
||||
struct iio_chan_spec const *chan)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
s32 ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client,
|
||||
hdc2010_reg_translation[chan->address].peak);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Could not read sensor measurement byte\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hdc2010_get_heater_status(struct hdc2010_data *data)
|
||||
{
|
||||
return !!(data->drdy_config & HDC2010_HEATER_EN);
|
||||
}
|
||||
|
||||
static int hdc2010_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct hdc2010_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW: {
|
||||
int ret;
|
||||
|
||||
if (chan->type == IIO_CURRENT) {
|
||||
*val = hdc2010_get_heater_status(data);
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
mutex_lock(&data->lock);
|
||||
ret = hdc2010_get_prim_measurement_word(data, chan);
|
||||
mutex_unlock(&data->lock);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
case IIO_CHAN_INFO_PEAK: {
|
||||
int ret;
|
||||
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
mutex_lock(&data->lock);
|
||||
ret = hdc2010_get_peak_measurement_byte(data, chan);
|
||||
mutex_unlock(&data->lock);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Scaling up the value so we can use same offset as RAW */
|
||||
*val = ret * 256;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val2 = 65536;
|
||||
if (chan->type == IIO_TEMP)
|
||||
*val = 165000;
|
||||
else
|
||||
*val = 100000;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = -15887;
|
||||
*val2 = 515151;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int hdc2010_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct hdc2010_data *data = iio_priv(indio_dev);
|
||||
int new, ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (chan->type != IIO_CURRENT || val2 != 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (val) {
|
||||
case 1:
|
||||
new = HDC2010_HEATER_EN;
|
||||
break;
|
||||
case 0:
|
||||
new = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = hdc2010_update_drdy_config(data, HDC2010_HEATER_EN, new);
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info hdc2010_info = {
|
||||
.read_raw = hdc2010_read_raw,
|
||||
.write_raw = hdc2010_write_raw,
|
||||
.attrs = &hdc2010_attribute_group,
|
||||
};
|
||||
|
||||
static int hdc2010_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct hdc2010_data *data;
|
||||
u8 tmp;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
/*
|
||||
* As DEVICE ID register does not differentiate between
|
||||
* HDC2010 and HDC2080, we have the name hardcoded
|
||||
*/
|
||||
indio_dev->name = "hdc2010";
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &hdc2010_info;
|
||||
|
||||
indio_dev->channels = hdc2010_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(hdc2010_channels);
|
||||
|
||||
/* Enable Automatic Measurement Mode at 5Hz */
|
||||
ret = hdc2010_update_drdy_config(data, HDC2010_AMM, HDC2010_AMM);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We enable both temp and humidity measurement.
|
||||
* However the measurement won't start even in AMM until triggered.
|
||||
*/
|
||||
tmp = (data->measurement_config & ~HDC2010_MEAS_CONF) |
|
||||
HDC2010_MEAS_TRIG;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, HDC2010_REG_MEASUREMENT_CONF, tmp);
|
||||
if (ret) {
|
||||
dev_warn(&client->dev, "Unable to set up measurement\n");
|
||||
if (hdc2010_update_drdy_config(data, HDC2010_AMM, 0))
|
||||
dev_warn(&client->dev, "Unable to restore default AMM\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->measurement_config = tmp;
|
||||
|
||||
return iio_device_register(indio_dev);
|
||||
}
|
||||
|
||||
static int hdc2010_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct hdc2010_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
/* Disable Automatic Measurement Mode */
|
||||
if (hdc2010_update_drdy_config(data, HDC2010_AMM, 0))
|
||||
dev_warn(&client->dev, "Unable to restore default AMM\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id hdc2010_id[] = {
|
||||
{ "hdc2010" },
|
||||
{ "hdc2080" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, hdc2010_id);
|
||||
|
||||
static const struct of_device_id hdc2010_dt_ids[] = {
|
||||
{ .compatible = "ti,hdc2010" },
|
||||
{ .compatible = "ti,hdc2080" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hdc2010_dt_ids);
|
||||
|
||||
static struct i2c_driver hdc2010_driver = {
|
||||
.driver = {
|
||||
.name = "hdc2010",
|
||||
.of_match_table = hdc2010_dt_ids,
|
||||
},
|
||||
.probe = hdc2010_probe,
|
||||
.remove = hdc2010_remove,
|
||||
.id_table = hdc2010_id,
|
||||
};
|
||||
module_i2c_driver(hdc2010_driver);
|
||||
|
||||
MODULE_AUTHOR("Eugene Zaikonnikov <ez@norphonic.com>");
|
||||
MODULE_DESCRIPTION("TI HDC2010 humidity and temperature sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -30,7 +30,7 @@ int iio_trigger_detach_poll_func(struct iio_trigger *trig,
|
||||
* iio_device_register_trigger_consumer() - set up an iio_dev to use triggers
|
||||
* @indio_dev: iio_dev associated with the device that will consume the trigger
|
||||
**/
|
||||
static int iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
|
||||
static inline int iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -39,7 +39,7 @@ static int iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
|
||||
* iio_device_unregister_trigger_consumer() - reverse the registration process
|
||||
* @indio_dev: iio_dev associated with the device that consumed the trigger
|
||||
**/
|
||||
static void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
|
||||
static inline void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1475,22 +1475,14 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
||||
}
|
||||
|
||||
st->vdd_supply = devm_regulator_get(dev, "vdd");
|
||||
if (IS_ERR(st->vdd_supply)) {
|
||||
if (PTR_ERR(st->vdd_supply) != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get vdd regulator %d\n",
|
||||
(int)PTR_ERR(st->vdd_supply));
|
||||
|
||||
return PTR_ERR(st->vdd_supply);
|
||||
}
|
||||
if (IS_ERR(st->vdd_supply))
|
||||
return dev_err_probe(dev, PTR_ERR(st->vdd_supply),
|
||||
"Failed to get vdd regulator\n");
|
||||
|
||||
st->vddio_supply = devm_regulator_get(dev, "vddio");
|
||||
if (IS_ERR(st->vddio_supply)) {
|
||||
if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get vddio regulator %d\n",
|
||||
(int)PTR_ERR(st->vddio_supply));
|
||||
|
||||
return PTR_ERR(st->vddio_supply);
|
||||
}
|
||||
if (IS_ERR(st->vddio_supply))
|
||||
return dev_err_probe(dev, PTR_ERR(st->vddio_supply),
|
||||
"Failed to get vddio regulator\n");
|
||||
|
||||
result = regulator_enable(st->vdd_supply);
|
||||
if (result) {
|
||||
|
@ -133,6 +133,7 @@ static const char * const iio_modifier_names[] = {
|
||||
[IIO_MOD_PM10] = "pm10",
|
||||
[IIO_MOD_ETHANOL] = "ethanol",
|
||||
[IIO_MOD_H2] = "h2",
|
||||
[IIO_MOD_O2] = "o2",
|
||||
};
|
||||
|
||||
/* relies on pairs of these shared then separate */
|
||||
|
@ -86,6 +86,21 @@ config APDS9960
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called apds9960
|
||||
|
||||
config AS73211
|
||||
tristate "AMS AS73211 XYZ color sensor"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
If you say yes here you get support for the AMS AS73211
|
||||
JENCOLOR(R) Digital XYZ Sensor.
|
||||
|
||||
For triggered measurements, you will need an additional trigger driver
|
||||
like IIO_HRTIMER_TRIGGER or IIO_SYSFS_TRIGGER.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called as73211.
|
||||
|
||||
config BH1750
|
||||
tristate "ROHM BH1750 ambient light sensor"
|
||||
depends on I2C
|
||||
|
@ -11,6 +11,7 @@ obj-$(CONFIG_AL3010) += al3010.o
|
||||
obj-$(CONFIG_AL3320A) += al3320a.o
|
||||
obj-$(CONFIG_APDS9300) += apds9300.o
|
||||
obj-$(CONFIG_APDS9960) += apds9960.o
|
||||
obj-$(CONFIG_AS73211) += as73211.o
|
||||
obj-$(CONFIG_BH1750) += bh1750.o
|
||||
obj-$(CONFIG_BH1780) += bh1780.o
|
||||
obj-$(CONFIG_CM32181) += cm32181.o
|
||||
|
801
drivers/iio/light/as73211.c
Normal file
801
drivers/iio/light/as73211.c
Normal file
@ -0,0 +1,801 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor
|
||||
*
|
||||
* Author: Christian Eggers <ceggers@arri.de>
|
||||
*
|
||||
* Copyright (c) 2020 ARRI Lighting
|
||||
*
|
||||
* Color light sensor with 16-bit channels for x, y, z and temperature);
|
||||
* 7-bit I2C slave address 0x74 .. 0x77.
|
||||
*
|
||||
* Datasheet: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#define HZ_PER_KHZ 1000
|
||||
|
||||
#define AS73211_DRV_NAME "as73211"
|
||||
|
||||
/* AS73211 configuration registers */
|
||||
#define AS73211_REG_OSR 0x0
|
||||
#define AS73211_REG_AGEN 0x2
|
||||
#define AS73211_REG_CREG1 0x6
|
||||
#define AS73211_REG_CREG2 0x7
|
||||
#define AS73211_REG_CREG3 0x8
|
||||
|
||||
/* AS73211 output register bank */
|
||||
#define AS73211_OUT_OSR_STATUS 0
|
||||
#define AS73211_OUT_TEMP 1
|
||||
#define AS73211_OUT_MRES1 2
|
||||
#define AS73211_OUT_MRES2 3
|
||||
#define AS73211_OUT_MRES3 4
|
||||
|
||||
#define AS73211_OSR_SS BIT(7)
|
||||
#define AS73211_OSR_PD BIT(6)
|
||||
#define AS73211_OSR_SW_RES BIT(3)
|
||||
#define AS73211_OSR_DOS_MASK GENMASK(2, 0)
|
||||
#define AS73211_OSR_DOS_CONFIG FIELD_PREP(AS73211_OSR_DOS_MASK, 0x2)
|
||||
#define AS73211_OSR_DOS_MEASURE FIELD_PREP(AS73211_OSR_DOS_MASK, 0x3)
|
||||
|
||||
#define AS73211_AGEN_DEVID_MASK GENMASK(7, 4)
|
||||
#define AS73211_AGEN_DEVID(x) FIELD_PREP(AS73211_AGEN_DEVID_MASK, (x))
|
||||
#define AS73211_AGEN_MUT_MASK GENMASK(3, 0)
|
||||
#define AS73211_AGEN_MUT(x) FIELD_PREP(AS73211_AGEN_MUT_MASK, (x))
|
||||
|
||||
#define AS73211_CREG1_GAIN_MASK GENMASK(7, 4)
|
||||
#define AS73211_CREG1_GAIN_1 11
|
||||
#define AS73211_CREG1_TIME_MASK GENMASK(3, 0)
|
||||
|
||||
#define AS73211_CREG3_CCLK_MASK GENMASK(1, 0)
|
||||
|
||||
#define AS73211_OSR_STATUS_OUTCONVOF BIT(15)
|
||||
#define AS73211_OSR_STATUS_MRESOF BIT(14)
|
||||
#define AS73211_OSR_STATUS_ADCOF BIT(13)
|
||||
#define AS73211_OSR_STATUS_LDATA BIT(12)
|
||||
#define AS73211_OSR_STATUS_NDATA BIT(11)
|
||||
#define AS73211_OSR_STATUS_NOTREADY BIT(10)
|
||||
|
||||
#define AS73211_SAMPLE_FREQ_BASE 1024000
|
||||
|
||||
#define AS73211_SAMPLE_TIME_NUM 15
|
||||
#define AS73211_SAMPLE_TIME_MAX_MS BIT(AS73211_SAMPLE_TIME_NUM - 1)
|
||||
|
||||
/* Available sample frequencies are 1.024MHz multiplied by powers of two. */
|
||||
static const int as73211_samp_freq_avail[] = {
|
||||
AS73211_SAMPLE_FREQ_BASE * 1,
|
||||
AS73211_SAMPLE_FREQ_BASE * 2,
|
||||
AS73211_SAMPLE_FREQ_BASE * 4,
|
||||
AS73211_SAMPLE_FREQ_BASE * 8,
|
||||
};
|
||||
|
||||
static const int as73211_hardwaregain_avail[] = {
|
||||
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct as73211_data - Instance data for one AS73211
|
||||
* @client: I2C client.
|
||||
* @osr: Cached Operational State Register.
|
||||
* @creg1: Cached Configuration Register 1.
|
||||
* @creg2: Cached Configuration Register 2.
|
||||
* @creg3: Cached Configuration Register 3.
|
||||
* @mutex: Keeps cached registers in sync with the device.
|
||||
* @completion: Completion to wait for interrupt.
|
||||
* @int_time_avail: Available integration times (depend on sampling frequency).
|
||||
*/
|
||||
struct as73211_data {
|
||||
struct i2c_client *client;
|
||||
u8 osr;
|
||||
u8 creg1;
|
||||
u8 creg2;
|
||||
u8 creg3;
|
||||
struct mutex mutex;
|
||||
struct completion completion;
|
||||
int int_time_avail[AS73211_SAMPLE_TIME_NUM * 2];
|
||||
};
|
||||
|
||||
#define AS73211_COLOR_CHANNEL(_color, _si, _addr) { \
|
||||
.type = IIO_INTENSITY, \
|
||||
.modified = 1, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_type = \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
|
||||
BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
|
||||
BIT(IIO_CHAN_INFO_INT_TIME), \
|
||||
.info_mask_shared_by_type_available = \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
|
||||
BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
|
||||
BIT(IIO_CHAN_INFO_INT_TIME), \
|
||||
.channel2 = IIO_MOD_##_color, \
|
||||
.address = _addr, \
|
||||
.scan_index = _si, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 16, \
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_LE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define AS73211_OFFSET_TEMP_INT (-66)
|
||||
#define AS73211_OFFSET_TEMP_MICRO 900000
|
||||
#define AS73211_SCALE_TEMP_INT 0
|
||||
#define AS73211_SCALE_TEMP_MICRO 50000
|
||||
|
||||
#define AS73211_SCALE_X 277071108 /* nW/m^2 */
|
||||
#define AS73211_SCALE_Y 298384270 /* nW/m^2 */
|
||||
#define AS73211_SCALE_Z 160241927 /* nW/m^2 */
|
||||
|
||||
/* Channel order MUST match devices result register order */
|
||||
#define AS73211_SCAN_INDEX_TEMP 0
|
||||
#define AS73211_SCAN_INDEX_X 1
|
||||
#define AS73211_SCAN_INDEX_Y 2
|
||||
#define AS73211_SCAN_INDEX_Z 3
|
||||
#define AS73211_SCAN_INDEX_TS 4
|
||||
|
||||
#define AS73211_SCAN_MASK_COLOR ( \
|
||||
BIT(AS73211_SCAN_INDEX_X) | \
|
||||
BIT(AS73211_SCAN_INDEX_Y) | \
|
||||
BIT(AS73211_SCAN_INDEX_Z))
|
||||
|
||||
#define AS73211_SCAN_MASK_ALL ( \
|
||||
BIT(AS73211_SCAN_INDEX_TEMP) | \
|
||||
AS73211_SCAN_MASK_COLOR)
|
||||
|
||||
static const struct iio_chan_spec as73211_channels[] = {
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.address = AS73211_OUT_TEMP,
|
||||
.scan_index = AS73211_SCAN_INDEX_TEMP,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_LE,
|
||||
}
|
||||
},
|
||||
AS73211_COLOR_CHANNEL(X, AS73211_SCAN_INDEX_X, AS73211_OUT_MRES1),
|
||||
AS73211_COLOR_CHANNEL(Y, AS73211_SCAN_INDEX_Y, AS73211_OUT_MRES2),
|
||||
AS73211_COLOR_CHANNEL(Z, AS73211_SCAN_INDEX_Z, AS73211_OUT_MRES3),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS),
|
||||
};
|
||||
|
||||
static unsigned int as73211_integration_time_1024cyc(struct as73211_data *data)
|
||||
{
|
||||
/*
|
||||
* Return integration time in units of 1024 clock cycles. Integration time
|
||||
* in CREG1 is in powers of 2 (x 1024 cycles).
|
||||
*/
|
||||
return BIT(FIELD_GET(AS73211_CREG1_TIME_MASK, data->creg1));
|
||||
}
|
||||
|
||||
static unsigned int as73211_integration_time_us(struct as73211_data *data,
|
||||
unsigned int integration_time_1024cyc)
|
||||
{
|
||||
/*
|
||||
* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz)
|
||||
* t_cycl is configured in CREG1 in powers of 2 (x 1024 cycles)
|
||||
* t_int_us = 1 / (f_samp) * t_cycl * US_PER_SEC
|
||||
* = 1 / (2^CREG3_CCLK * 1,024,000) * 2^CREG1_CYCLES * 1,024 * US_PER_SEC
|
||||
* = 2^(-CREG3_CCLK) * 2^CREG1_CYCLES * 1,000
|
||||
* In order to get rid of negative exponents, we extend the "fraction"
|
||||
* by 2^3 (CREG3_CCLK,max = 3)
|
||||
* t_int_us = 2^(3-CREG3_CCLK) * 2^CREG1_CYCLES * 125
|
||||
*/
|
||||
return BIT(3 - FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3)) *
|
||||
integration_time_1024cyc * 125;
|
||||
}
|
||||
|
||||
static void as73211_integration_time_calc_avail(struct as73211_data *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data->int_time_avail) / 2; i++) {
|
||||
unsigned int time_us = as73211_integration_time_us(data, BIT(i));
|
||||
|
||||
data->int_time_avail[i * 2 + 0] = time_us / USEC_PER_SEC;
|
||||
data->int_time_avail[i * 2 + 1] = time_us % USEC_PER_SEC;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int as73211_gain(struct as73211_data *data)
|
||||
{
|
||||
/* gain can be calculated from CREG1 as 2^(11 - CREG1_GAIN) */
|
||||
return BIT(AS73211_CREG1_GAIN_1 - FIELD_GET(AS73211_CREG1_GAIN_MASK, data->creg1));
|
||||
}
|
||||
|
||||
/* must be called with as73211_data::mutex held. */
|
||||
static int as73211_req_data(struct as73211_data *data)
|
||||
{
|
||||
unsigned int time_us = as73211_integration_time_us(data,
|
||||
as73211_integration_time_1024cyc(data));
|
||||
struct device *dev = &data->client->dev;
|
||||
union i2c_smbus_data smbus_data;
|
||||
u16 osr_status;
|
||||
int ret;
|
||||
|
||||
if (data->client->irq)
|
||||
reinit_completion(&data->completion);
|
||||
|
||||
/*
|
||||
* During measurement, there should be no traffic on the i2c bus as the
|
||||
* electrical noise would disturb the measurement process.
|
||||
*/
|
||||
i2c_lock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
|
||||
|
||||
data->osr &= ~AS73211_OSR_DOS_MASK;
|
||||
data->osr |= AS73211_OSR_DOS_MEASURE | AS73211_OSR_SS;
|
||||
|
||||
smbus_data.byte = data->osr;
|
||||
ret = __i2c_smbus_xfer(data->client->adapter, data->client->addr,
|
||||
data->client->flags, I2C_SMBUS_WRITE,
|
||||
AS73211_REG_OSR, I2C_SMBUS_BYTE_DATA, &smbus_data);
|
||||
if (ret < 0) {
|
||||
i2c_unlock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset AS73211_OSR_SS (is self clearing) in order to avoid unintentional
|
||||
* triggering of further measurements later.
|
||||
*/
|
||||
data->osr &= ~AS73211_OSR_SS;
|
||||
|
||||
/*
|
||||
* Add some extra margin for the timeout. sensor timing is not as precise
|
||||
* as our one ...
|
||||
*/
|
||||
time_us += time_us / 8;
|
||||
if (data->client->irq) {
|
||||
ret = wait_for_completion_timeout(&data->completion, usecs_to_jiffies(time_us));
|
||||
if (!ret) {
|
||||
dev_err(dev, "timeout waiting for READY IRQ\n");
|
||||
i2c_unlock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
/* Wait integration time */
|
||||
usleep_range(time_us, 2 * time_us);
|
||||
}
|
||||
|
||||
i2c_unlock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
|
||||
|
||||
ret = i2c_smbus_read_word_data(data->client, AS73211_OUT_OSR_STATUS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
osr_status = ret;
|
||||
if (osr_status != (AS73211_OSR_DOS_MEASURE | AS73211_OSR_STATUS_NDATA)) {
|
||||
if (osr_status & AS73211_OSR_SS) {
|
||||
dev_err(dev, "%s() Measurement has not stopped\n", __func__);
|
||||
return -ETIME;
|
||||
}
|
||||
if (osr_status & AS73211_OSR_STATUS_NOTREADY) {
|
||||
dev_err(dev, "%s() Data is not ready\n", __func__);
|
||||
return -ENODATA;
|
||||
}
|
||||
if (!(osr_status & AS73211_OSR_STATUS_NDATA)) {
|
||||
dev_err(dev, "%s() No new data available\n", __func__);
|
||||
return -ENODATA;
|
||||
}
|
||||
if (osr_status & AS73211_OSR_STATUS_LDATA) {
|
||||
dev_err(dev, "%s() Result buffer overrun\n", __func__);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
if (osr_status & AS73211_OSR_STATUS_ADCOF) {
|
||||
dev_err(dev, "%s() ADC overflow\n", __func__);
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
if (osr_status & AS73211_OSR_STATUS_MRESOF) {
|
||||
dev_err(dev, "%s() Measurement result overflow\n", __func__);
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
if (osr_status & AS73211_OSR_STATUS_OUTCONVOF) {
|
||||
dev_err(dev, "%s() Timer overflow\n", __func__);
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
dev_err(dev, "%s() Unexpected status value\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct as73211_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW: {
|
||||
int ret;
|
||||
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = as73211_req_data(data);
|
||||
if (ret < 0) {
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_word_data(data->client, chan->address);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = ret;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = AS73211_OFFSET_TEMP_INT;
|
||||
*val2 = AS73211_OFFSET_TEMP_MICRO;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
*val = AS73211_SCALE_TEMP_INT;
|
||||
*val2 = AS73211_SCALE_TEMP_MICRO;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
|
||||
case IIO_INTENSITY: {
|
||||
unsigned int scale;
|
||||
|
||||
switch (chan->channel2) {
|
||||
case IIO_MOD_X:
|
||||
scale = AS73211_SCALE_X;
|
||||
break;
|
||||
case IIO_MOD_Y:
|
||||
scale = AS73211_SCALE_Y;
|
||||
break;
|
||||
case IIO_MOD_Z:
|
||||
scale = AS73211_SCALE_Z;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
scale /= as73211_gain(data);
|
||||
scale /= as73211_integration_time_1024cyc(data);
|
||||
*val = scale;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}}
|
||||
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
/* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */
|
||||
*val = BIT(FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3)) *
|
||||
AS73211_SAMPLE_FREQ_BASE;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
*val = as73211_gain(data);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_INT_TIME: {
|
||||
unsigned int time_us;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
time_us = as73211_integration_time_us(data, as73211_integration_time_1024cyc(data));
|
||||
mutex_unlock(&data->mutex);
|
||||
*val = time_us / USEC_PER_SEC;
|
||||
*val2 = time_us % USEC_PER_SEC;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}}
|
||||
}
|
||||
|
||||
static int as73211_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length, long mask)
|
||||
{
|
||||
struct as73211_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*length = ARRAY_SIZE(as73211_samp_freq_avail);
|
||||
*vals = as73211_samp_freq_avail;
|
||||
*type = IIO_VAL_INT;
|
||||
return IIO_AVAIL_LIST;
|
||||
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
*length = ARRAY_SIZE(as73211_hardwaregain_avail);
|
||||
*vals = as73211_hardwaregain_avail;
|
||||
*type = IIO_VAL_INT;
|
||||
return IIO_AVAIL_LIST;
|
||||
|
||||
case IIO_CHAN_INFO_INT_TIME:
|
||||
*length = ARRAY_SIZE(data->int_time_avail);
|
||||
*vals = data->int_time_avail;
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
return IIO_AVAIL_LIST;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int _as73211_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan __always_unused,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct as73211_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ: {
|
||||
int reg_bits, freq_kHz = val / HZ_PER_KHZ; /* 1024, 2048, ... */
|
||||
|
||||
/* val must be 1024 * 2^x */
|
||||
if (val < 0 || (freq_kHz * HZ_PER_KHZ) != val ||
|
||||
!is_power_of_2(freq_kHz) || val2)
|
||||
return -EINVAL;
|
||||
|
||||
/* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz (=2^10)) */
|
||||
reg_bits = ilog2(freq_kHz) - 10;
|
||||
if (!FIELD_FIT(AS73211_CREG3_CCLK_MASK, reg_bits))
|
||||
return -EINVAL;
|
||||
|
||||
data->creg3 &= ~AS73211_CREG3_CCLK_MASK;
|
||||
data->creg3 |= FIELD_PREP(AS73211_CREG3_CCLK_MASK, reg_bits);
|
||||
as73211_integration_time_calc_avail(data);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_CREG3, data->creg3);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN: {
|
||||
unsigned int reg_bits;
|
||||
|
||||
if (val < 0 || !is_power_of_2(val) || val2)
|
||||
return -EINVAL;
|
||||
|
||||
/* gain can be calculated from CREG1 as 2^(11 - CREG1_GAIN) */
|
||||
reg_bits = AS73211_CREG1_GAIN_1 - ilog2(val);
|
||||
if (!FIELD_FIT(AS73211_CREG1_GAIN_MASK, reg_bits))
|
||||
return -EINVAL;
|
||||
|
||||
data->creg1 &= ~AS73211_CREG1_GAIN_MASK;
|
||||
data->creg1 |= FIELD_PREP(AS73211_CREG1_GAIN_MASK, reg_bits);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_CREG1, data->creg1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case IIO_CHAN_INFO_INT_TIME: {
|
||||
int val_us = val * USEC_PER_SEC + val2;
|
||||
int time_ms;
|
||||
int reg_bits;
|
||||
|
||||
/* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */
|
||||
int f_samp_1_024mhz = BIT(FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3));
|
||||
|
||||
/*
|
||||
* time_ms = time_us * US_PER_MS * f_samp_1_024mhz / MHZ_PER_HZ
|
||||
* = time_us * f_samp_1_024mhz / 1000
|
||||
*/
|
||||
time_ms = (val_us * f_samp_1_024mhz) / 1000; /* 1 ms, 2 ms, ... (power of two) */
|
||||
if (time_ms < 0 || !is_power_of_2(time_ms) || time_ms > AS73211_SAMPLE_TIME_MAX_MS)
|
||||
return -EINVAL;
|
||||
|
||||
reg_bits = ilog2(time_ms);
|
||||
if (!FIELD_FIT(AS73211_CREG1_TIME_MASK, reg_bits))
|
||||
return -EINVAL; /* not possible due to previous tests */
|
||||
|
||||
data->creg1 &= ~AS73211_CREG1_TIME_MASK;
|
||||
data->creg1 |= FIELD_PREP(AS73211_CREG1_TIME_MASK, reg_bits);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_CREG1, data->creg1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}}
|
||||
}
|
||||
|
||||
static int as73211_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct as73211_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret < 0)
|
||||
goto error_unlock;
|
||||
|
||||
/* Need to switch to config mode ... */
|
||||
if ((data->osr & AS73211_OSR_DOS_MASK) != AS73211_OSR_DOS_CONFIG) {
|
||||
data->osr &= ~AS73211_OSR_DOS_MASK;
|
||||
data->osr |= AS73211_OSR_DOS_CONFIG;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr);
|
||||
if (ret < 0)
|
||||
goto error_release;
|
||||
}
|
||||
|
||||
ret = _as73211_write_raw(indio_dev, chan, val, val2, mask);
|
||||
|
||||
error_release:
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
error_unlock:
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t as73211_ready_handler(int irq __always_unused, void *priv)
|
||||
{
|
||||
struct as73211_data *data = iio_priv(priv);
|
||||
|
||||
complete(&data->completion);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct as73211_data *data = iio_priv(indio_dev);
|
||||
struct {
|
||||
__le16 chan[4];
|
||||
s64 ts __aligned(8);
|
||||
} scan;
|
||||
int data_result, ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
data_result = as73211_req_data(data);
|
||||
if (data_result < 0 && data_result != -EOVERFLOW)
|
||||
goto done; /* don't push any data for errors other than EOVERFLOW */
|
||||
|
||||
if (*indio_dev->active_scan_mask == AS73211_SCAN_MASK_ALL) {
|
||||
/* Optimization for reading all (color + temperature) channels */
|
||||
u8 addr = as73211_channels[0].address;
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = data->client->addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = &addr,
|
||||
},
|
||||
{
|
||||
.addr = data->client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = sizeof(scan.chan),
|
||||
.buf = (u8 *)&scan.chan,
|
||||
},
|
||||
};
|
||||
|
||||
ret = i2c_transfer(data->client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
} else {
|
||||
/* Optimization for reading only color channels */
|
||||
|
||||
/* AS73211 starts reading at address 2 */
|
||||
ret = i2c_master_recv(data->client,
|
||||
(char *)&scan.chan[1], 3 * sizeof(scan.chan[1]));
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (data_result) {
|
||||
/*
|
||||
* Saturate all channels (in case of overflows). Temperature channel
|
||||
* is not affected by overflows.
|
||||
*/
|
||||
scan.chan[1] = cpu_to_le16(U16_MAX);
|
||||
scan.chan[2] = cpu_to_le16(U16_MAX);
|
||||
scan.chan[3] = cpu_to_le16(U16_MAX);
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
mutex_unlock(&data->mutex);
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct iio_info as73211_info = {
|
||||
.read_raw = as73211_read_raw,
|
||||
.read_avail = as73211_read_avail,
|
||||
.write_raw = as73211_write_raw,
|
||||
};
|
||||
|
||||
static int as73211_power(struct iio_dev *indio_dev, bool state)
|
||||
{
|
||||
struct as73211_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (state)
|
||||
data->osr &= ~AS73211_OSR_PD;
|
||||
else
|
||||
data->osr |= AS73211_OSR_PD;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr);
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void as73211_power_disable(void *data)
|
||||
{
|
||||
struct iio_dev *indio_dev = data;
|
||||
|
||||
as73211_power(indio_dev, false);
|
||||
}
|
||||
|
||||
static int as73211_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct as73211_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
|
||||
mutex_init(&data->mutex);
|
||||
init_completion(&data->completion);
|
||||
|
||||
indio_dev->info = &as73211_info;
|
||||
indio_dev->name = AS73211_DRV_NAME;
|
||||
indio_dev->channels = as73211_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(as73211_channels);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->osr = ret;
|
||||
|
||||
/* reset device */
|
||||
data->osr |= AS73211_OSR_SW_RES;
|
||||
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->osr = ret;
|
||||
|
||||
/*
|
||||
* Reading AGEN is only possible after reset (AGEN is not available if
|
||||
* device is in measurement mode).
|
||||
*/
|
||||
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_AGEN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* At the time of writing this driver, only DEVID 2 and MUT 1 are known. */
|
||||
if ((ret & AS73211_AGEN_DEVID_MASK) != AS73211_AGEN_DEVID(2) ||
|
||||
(ret & AS73211_AGEN_MUT_MASK) != AS73211_AGEN_MUT(1))
|
||||
return -ENODEV;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_CREG1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->creg1 = ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_CREG2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->creg2 = ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_CREG3);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->creg3 = ret;
|
||||
as73211_integration_time_calc_avail(data);
|
||||
|
||||
ret = as73211_power(indio_dev, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, as73211_power_disable, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, as73211_trigger_handler, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (client->irq) {
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL,
|
||||
as73211_ready_handler,
|
||||
IRQF_ONESHOT,
|
||||
client->name, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused as73211_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
|
||||
return as73211_power(indio_dev, false);
|
||||
}
|
||||
|
||||
static int __maybe_unused as73211_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
|
||||
return as73211_power(indio_dev, true);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(as73211_pm_ops, as73211_suspend, as73211_resume);
|
||||
|
||||
static const struct of_device_id as73211_of_match[] = {
|
||||
{ .compatible = "ams,as73211" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, as73211_of_match);
|
||||
|
||||
static const struct i2c_device_id as73211_id[] = {
|
||||
{ "as73211", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, as73211_id);
|
||||
|
||||
static struct i2c_driver as73211_driver = {
|
||||
.driver = {
|
||||
.name = AS73211_DRV_NAME,
|
||||
.of_match_table = as73211_of_match,
|
||||
.pm = &as73211_pm_ops,
|
||||
},
|
||||
.probe_new = as73211_probe,
|
||||
.id_table = as73211_id,
|
||||
};
|
||||
module_i2c_driver(as73211_driver);
|
||||
|
||||
MODULE_AUTHOR("Christian Eggers <ceggers@arri.de>");
|
||||
MODULE_DESCRIPTION("AS73211 XYZ True Color Sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -746,12 +746,9 @@ static int isl29018_probe(struct i2c_client *client,
|
||||
chip->suspended = false;
|
||||
|
||||
chip->vcc_reg = devm_regulator_get(&client->dev, "vcc");
|
||||
if (IS_ERR(chip->vcc_reg)) {
|
||||
err = PTR_ERR(chip->vcc_reg);
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(&client->dev, "failed to get VCC regulator!\n");
|
||||
return err;
|
||||
}
|
||||
if (IS_ERR(chip->vcc_reg))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(chip->vcc_reg),
|
||||
"failed to get VCC regulator!\n");
|
||||
|
||||
err = regulator_enable(chip->vcc_reg);
|
||||
if (err) {
|
||||
|
@ -1776,14 +1776,8 @@ static int tsl2772_probe(struct i2c_client *clientp,
|
||||
ret = devm_regulator_bulk_get(&clientp->dev,
|
||||
ARRAY_SIZE(chip->supplies),
|
||||
chip->supplies);
|
||||
if (ret < 0) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&clientp->dev,
|
||||
"Failed to get regulators: %d\n",
|
||||
ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&clientp->dev, ret, "Failed to get regulators\n");
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(chip->supplies), chip->supplies);
|
||||
if (ret < 0) {
|
||||
|
@ -843,15 +843,8 @@ static int ak8974_probe(struct i2c_client *i2c,
|
||||
ret = devm_regulator_bulk_get(&i2c->dev,
|
||||
ARRAY_SIZE(ak8974->regs),
|
||||
ak8974->regs);
|
||||
if (ret < 0) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&i2c->dev, "cannot get regulators: %d\n", ret);
|
||||
else
|
||||
dev_dbg(&i2c->dev,
|
||||
"regulators unavailable, deferring probe\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&i2c->dev, ret, "cannot get regulators\n");
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(ak8974->regs), ak8974->regs);
|
||||
if (ret < 0) {
|
||||
|
@ -476,22 +476,14 @@ static int mag3110_probe(struct i2c_client *client,
|
||||
data = iio_priv(indio_dev);
|
||||
|
||||
data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
|
||||
if (IS_ERR(data->vdd_reg)) {
|
||||
if (PTR_ERR(data->vdd_reg) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_err(&client->dev, "failed to get VDD regulator!\n");
|
||||
return PTR_ERR(data->vdd_reg);
|
||||
}
|
||||
if (IS_ERR(data->vdd_reg))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(data->vdd_reg),
|
||||
"failed to get VDD regulator!\n");
|
||||
|
||||
data->vddio_reg = devm_regulator_get(&client->dev, "vddio");
|
||||
if (IS_ERR(data->vddio_reg)) {
|
||||
if (PTR_ERR(data->vddio_reg) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_err(&client->dev, "failed to get VDDIO regulator!\n");
|
||||
return PTR_ERR(data->vddio_reg);
|
||||
}
|
||||
if (IS_ERR(data->vddio_reg))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(data->vddio_reg),
|
||||
"failed to get VDDIO regulator!\n");
|
||||
|
||||
ret = regulator_enable(data->vdd_reg);
|
||||
if (ret) {
|
||||
|
@ -354,11 +354,9 @@ static int mux_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
|
||||
parent = devm_iio_channel_get(dev, "parent");
|
||||
if (IS_ERR(parent)) {
|
||||
if (PTR_ERR(parent) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get parent channel\n");
|
||||
return PTR_ERR(parent);
|
||||
}
|
||||
if (IS_ERR(parent))
|
||||
return dev_err_probe(dev, PTR_ERR(parent),
|
||||
"failed to get parent channel\n");
|
||||
|
||||
sizeof_ext_info = iio_get_channel_ext_info_count(parent);
|
||||
if (sizeof_ext_info) {
|
||||
|
@ -6,19 +6,21 @@
|
||||
* Based on SX9500 driver and Semtech driver using the input framework
|
||||
* <https://my.syncplicity.com/share/teouwsim8niiaud/
|
||||
* linux-driver-SX9310_NoSmartHSensing>.
|
||||
* Reworked April 2019 by Evan Green <evgreen@chromium.org>
|
||||
* and January 2020 by Daniel Campello <campello@chromium.org>
|
||||
* Reworked in April 2019 by Evan Green <evgreen@chromium.org>
|
||||
* and in January 2020 by Daniel Campello <campello@chromium.org>.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/iio/buffer.h>
|
||||
@ -33,45 +35,44 @@
|
||||
#define SX9310_REG_IRQ_SRC 0x00
|
||||
#define SX9310_REG_STAT0 0x01
|
||||
#define SX9310_REG_STAT1 0x02
|
||||
#define SX9310_REG_STAT1_COMPSTAT_MASK GENMASK(3, 0)
|
||||
#define SX9310_REG_IRQ_MSK 0x03
|
||||
#define SX9310_CONVDONE_IRQ BIT(3)
|
||||
#define SX9310_FAR_IRQ BIT(5)
|
||||
#define SX9310_CLOSE_IRQ BIT(6)
|
||||
#define SX9310_EVENT_IRQ (SX9310_FAR_IRQ | \
|
||||
SX9310_CLOSE_IRQ)
|
||||
#define SX9310_REG_IRQ_FUNC 0x04
|
||||
|
||||
#define SX9310_REG_PROX_CTRL0 0x10
|
||||
#define SX9310_REG_PROX_CTRL0_PROXSTAT2 0x10
|
||||
#define SX9310_REG_PROX_CTRL0_EN_MASK 0x0F
|
||||
#define SX9310_REG_PROX_CTRL0_SENSOREN_MASK GENMASK(3, 0)
|
||||
#define SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK GENMASK(7, 4)
|
||||
#define SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS 0x01
|
||||
#define SX9310_REG_PROX_CTRL1 0x11
|
||||
#define SX9310_REG_PROX_CTRL2 0x12
|
||||
#define SX9310_REG_PROX_CTRL2_COMBMODE_ALL 0x80
|
||||
#define SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC 0x04
|
||||
#define SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2 (0x02 << 6)
|
||||
#define SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC (0x01 << 2)
|
||||
#define SX9310_REG_PROX_CTRL3 0x13
|
||||
#define SX9310_REG_PROX_CTRL3_GAIN0_X8 0x0c
|
||||
#define SX9310_REG_PROX_CTRL3_GAIN0_X8 (0x03 << 2)
|
||||
#define SX9310_REG_PROX_CTRL3_GAIN12_X4 0x02
|
||||
#define SX9310_REG_PROX_CTRL4 0x14
|
||||
#define SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST 0x07
|
||||
#define SX9310_REG_PROX_CTRL5 0x15
|
||||
#define SX9310_REG_PROX_CTRL5_RANGE_SMALL 0xc0
|
||||
#define SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 0x04
|
||||
#define SX9310_REG_PROX_CTRL5_RANGE_SMALL (0x03 << 6)
|
||||
#define SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 (0x01 << 2)
|
||||
#define SX9310_REG_PROX_CTRL5_RAWFILT_1P25 0x02
|
||||
#define SX9310_REG_PROX_CTRL6 0x16
|
||||
#define SX9310_REG_PROX_CTRL6_COMP_COMMON 0x20
|
||||
#define SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT 0x20
|
||||
#define SX9310_REG_PROX_CTRL7 0x17
|
||||
#define SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 0x08
|
||||
#define SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 (0x01 << 3)
|
||||
#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 0x05
|
||||
#define SX9310_REG_PROX_CTRL8 0x18
|
||||
#define SX9310_REG_PROX_CTRL9 0x19
|
||||
#define SX9310_REG_PROX_CTRL8_9_PTHRESH12_28 0x40
|
||||
#define SX9310_REG_PROX_CTRL8_9_PTHRESH_96 0x88
|
||||
#define SX9310_REG_PROX_CTRL8_9_PTHRESH_28 (0x08 << 3)
|
||||
#define SX9310_REG_PROX_CTRL8_9_PTHRESH_96 (0x11 << 3)
|
||||
#define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900 0x03
|
||||
#define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500 0x05
|
||||
#define SX9310_REG_PROX_CTRL10 0x1a
|
||||
#define SX9310_REG_PROX_CTRL10_HYST_6PCT 0x10
|
||||
#define SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_8 0x12
|
||||
#define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_8 0x03
|
||||
#define SX9310_REG_PROX_CTRL10_HYST_6PCT (0x01 << 4)
|
||||
#define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2 0x01
|
||||
#define SX9310_REG_PROX_CTRL11 0x1b
|
||||
#define SX9310_REG_PROX_CTRL12 0x1c
|
||||
#define SX9310_REG_PROX_CTRL13 0x1d
|
||||
@ -82,8 +83,8 @@
|
||||
#define SX9310_REG_PROX_CTRL18 0x22
|
||||
#define SX9310_REG_PROX_CTRL19 0x23
|
||||
#define SX9310_REG_SAR_CTRL0 0x2a
|
||||
#define SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES 0x40
|
||||
#define SX9310_REG_SAR_CTRL0_SARHYST_8 0x10
|
||||
#define SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES (0x02 << 5)
|
||||
#define SX9310_REG_SAR_CTRL0_SARHYST_8 (0x02 << 3)
|
||||
#define SX9310_REG_SAR_CTRL1 0x2b
|
||||
/* Each increment of the slope register is 0.0078125. */
|
||||
#define SX9310_REG_SAR_CTRL1_SLOPE(_hnslope) (_hnslope / 78125)
|
||||
@ -91,39 +92,28 @@
|
||||
#define SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT 0x3c
|
||||
|
||||
#define SX9310_REG_SENSOR_SEL 0x30
|
||||
|
||||
#define SX9310_REG_USE_MSB 0x31
|
||||
#define SX9310_REG_USE_LSB 0x32
|
||||
|
||||
#define SX9310_REG_AVG_MSB 0x33
|
||||
#define SX9310_REG_AVG_LSB 0x34
|
||||
|
||||
#define SX9310_REG_DIFF_MSB 0x35
|
||||
#define SX9310_REG_DIFF_LSB 0x36
|
||||
|
||||
#define SX9310_REG_OFFSET_MSB 0x37
|
||||
#define SX9310_REG_OFFSET_LSB 0x38
|
||||
|
||||
#define SX9310_REG_SAR_MSB 0x39
|
||||
#define SX9310_REG_SAR_LSB 0x3a
|
||||
|
||||
#define SX9310_REG_I2CADDR 0x40
|
||||
#define SX9310_REG_I2C_ADDR 0x40
|
||||
#define SX9310_REG_PAUSE 0x41
|
||||
#define SX9310_REG_WHOAMI 0x42
|
||||
#define SX9310_WHOAMI_VALUE 0x01
|
||||
#define SX9311_WHOAMI_VALUE 0x02
|
||||
|
||||
#define SX9310_REG_RESET 0x7f
|
||||
#define SX9310_SOFT_RESET 0xde
|
||||
|
||||
#define SX9310_SCAN_PERIOD_MASK GENMASK(7, 4)
|
||||
#define SX9310_SCAN_PERIOD_SHIFT 4
|
||||
|
||||
#define SX9310_COMPSTAT_MASK GENMASK(3, 0)
|
||||
|
||||
/* 4 hardware channels, as defined in STAT0: COMB, CS2, CS1 and CS0. */
|
||||
#define SX9310_NUM_CHANNELS 4
|
||||
#define SX9310_CHAN_ENABLED_MASK GENMASK(3, 0)
|
||||
static_assert(SX9310_NUM_CHANNELS < BITS_PER_LONG);
|
||||
|
||||
struct sx9310_data {
|
||||
/* Serialize access to registers and channel configuration */
|
||||
@ -131,20 +121,24 @@ struct sx9310_data {
|
||||
struct i2c_client *client;
|
||||
struct iio_trigger *trig;
|
||||
struct regmap *regmap;
|
||||
struct regulator_bulk_data supplies[2];
|
||||
/*
|
||||
* Last reading of the proximity status for each channel.
|
||||
* We only send an event to user space when this changes.
|
||||
*/
|
||||
bool prox_stat[SX9310_NUM_CHANNELS];
|
||||
unsigned long chan_prox_stat;
|
||||
bool trigger_enabled;
|
||||
__be16 buffer[SX9310_NUM_CHANNELS +
|
||||
4]; /* 64-bit data + 64-bit timestamp */
|
||||
/* Ensure correct alignment of timestamp when present. */
|
||||
struct {
|
||||
__be16 channels[SX9310_NUM_CHANNELS];
|
||||
s64 ts __aligned(8);
|
||||
} buffer;
|
||||
/* Remember enabled channels and sample rate during suspend. */
|
||||
unsigned int suspend_ctrl0;
|
||||
struct completion completion;
|
||||
unsigned int chan_read, chan_event;
|
||||
int channel_users[SX9310_NUM_CHANNELS];
|
||||
int whoami;
|
||||
unsigned long chan_read;
|
||||
unsigned long chan_event;
|
||||
unsigned int whoami;
|
||||
};
|
||||
|
||||
static const struct iio_event_spec sx9310_events[] = {
|
||||
@ -251,7 +245,7 @@ static const struct regmap_range sx9310_readable_reg_ranges[] = {
|
||||
regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19),
|
||||
regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2),
|
||||
regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SAR_LSB),
|
||||
regmap_reg_range(SX9310_REG_I2CADDR, SX9310_REG_WHOAMI),
|
||||
regmap_reg_range(SX9310_REG_I2C_ADDR, SX9310_REG_WHOAMI),
|
||||
regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET),
|
||||
};
|
||||
|
||||
@ -285,15 +279,16 @@ static const struct regmap_config sx9310_regmap_config = {
|
||||
};
|
||||
|
||||
static int sx9310_update_chan_en(struct sx9310_data *data,
|
||||
unsigned int chan_read,
|
||||
unsigned int chan_event)
|
||||
unsigned long chan_read,
|
||||
unsigned long chan_event)
|
||||
{
|
||||
int ret;
|
||||
unsigned long channels = chan_read | chan_event;
|
||||
|
||||
if ((data->chan_read | data->chan_event) != (chan_read | chan_event)) {
|
||||
if ((data->chan_read | data->chan_event) != channels) {
|
||||
ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL0,
|
||||
SX9310_CHAN_ENABLED_MASK,
|
||||
chan_read | chan_event);
|
||||
SX9310_REG_PROX_CTRL0_SENSOREN_MASK,
|
||||
channels);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -328,11 +323,15 @@ static int sx9310_put_event_channel(struct sx9310_data *data, int channel)
|
||||
|
||||
static int sx9310_enable_irq(struct sx9310_data *data, unsigned int irq)
|
||||
{
|
||||
if (!data->client->irq)
|
||||
return 0;
|
||||
return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, irq);
|
||||
}
|
||||
|
||||
static int sx9310_disable_irq(struct sx9310_data *data, unsigned int irq)
|
||||
{
|
||||
if (!data->client->irq)
|
||||
return 0;
|
||||
return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, 0);
|
||||
}
|
||||
|
||||
@ -342,10 +341,10 @@ static int sx9310_read_prox_data(struct sx9310_data *data,
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(data->regmap, SX9310_REG_SENSOR_SEL, chan->channel);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_bulk_read(data->regmap, chan->address, val, 2);
|
||||
return regmap_bulk_read(data->regmap, chan->address, val, sizeof(*val));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -358,10 +357,10 @@ static int sx9310_wait_for_sample(struct sx9310_data *data)
|
||||
unsigned int val;
|
||||
|
||||
ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &val);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = (val & SX9310_SCAN_PERIOD_MASK) >> SX9310_SCAN_PERIOD_SHIFT;
|
||||
val = FIELD_GET(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, val);
|
||||
|
||||
msleep(sx9310_scan_period_table[val]);
|
||||
|
||||
@ -371,22 +370,22 @@ static int sx9310_wait_for_sample(struct sx9310_data *data)
|
||||
static int sx9310_read_proximity(struct sx9310_data *data,
|
||||
const struct iio_chan_spec *chan, int *val)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
__be16 rawval;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
ret = sx9310_get_read_channel(data, chan->channel);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
goto out_put_channel;
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
if (data->client->irq > 0) {
|
||||
if (data->client->irq) {
|
||||
ret = wait_for_completion_interruptible(&data->completion);
|
||||
reinit_completion(&data->completion);
|
||||
} else {
|
||||
@ -395,22 +394,22 @@ static int sx9310_read_proximity(struct sx9310_data *data,
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
goto out_disable_irq;
|
||||
|
||||
ret = sx9310_read_prox_data(data, chan, &rawval);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
goto out_disable_irq;
|
||||
|
||||
*val = sign_extend32(be16_to_cpu(rawval),
|
||||
(chan->address == SX9310_REG_DIFF_MSB ? 11 : 15));
|
||||
chan->address == SX9310_REG_DIFF_MSB ? 11 : 15);
|
||||
|
||||
ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
goto out_put_channel;
|
||||
|
||||
ret = sx9310_put_read_channel(data, chan->channel);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
@ -430,12 +429,13 @@ out:
|
||||
static int sx9310_read_samp_freq(struct sx9310_data *data, int *val, int *val2)
|
||||
{
|
||||
unsigned int regval;
|
||||
int ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, ®val);
|
||||
int ret;
|
||||
|
||||
if (ret < 0)
|
||||
ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regval = (regval & SX9310_SCAN_PERIOD_MASK) >> SX9310_SCAN_PERIOD_SHIFT;
|
||||
regval = FIELD_GET(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, regval);
|
||||
*val = sx9310_samp_freq_table[regval].val;
|
||||
*val2 = sx9310_samp_freq_table[regval].val2;
|
||||
|
||||
@ -482,9 +482,10 @@ static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2)
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL0,
|
||||
SX9310_SCAN_PERIOD_MASK,
|
||||
i << SX9310_SCAN_PERIOD_SHIFT);
|
||||
ret = regmap_update_bits(
|
||||
data->regmap, SX9310_REG_PROX_CTRL0,
|
||||
SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK,
|
||||
FIELD_PREP(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, i));
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
@ -515,10 +516,9 @@ static irqreturn_t sx9310_irq_handler(int irq, void *private)
|
||||
iio_trigger_poll(data->trig);
|
||||
|
||||
/*
|
||||
* Even if no event is enabled, we need to wake the thread to
|
||||
* clear the interrupt state by reading SX9310_REG_IRQ_SRC. It
|
||||
* is not possible to do that here because regmap_read takes a
|
||||
* mutex.
|
||||
* Even if no event is enabled, we need to wake the thread to clear the
|
||||
* interrupt state by reading SX9310_REG_IRQ_SRC.
|
||||
* It is not possible to do that here because regmap_read takes a mutex.
|
||||
*/
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
@ -529,32 +529,32 @@ static void sx9310_push_events(struct iio_dev *indio_dev)
|
||||
unsigned int val, chan;
|
||||
struct sx9310_data *data = iio_priv(indio_dev);
|
||||
s64 timestamp = iio_get_time_ns(indio_dev);
|
||||
unsigned long prox_changed;
|
||||
|
||||
/* Read proximity state on all channels */
|
||||
ret = regmap_read(data->regmap, SX9310_REG_STAT0, &val);
|
||||
if (ret < 0) {
|
||||
if (ret) {
|
||||
dev_err(&data->client->dev, "i2c transfer error in irq\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (chan = 0; chan < SX9310_NUM_CHANNELS; chan++) {
|
||||
/*
|
||||
* Only iterate over channels with changes on proximity status that have
|
||||
* events enabled.
|
||||
*/
|
||||
prox_changed = (data->chan_prox_stat ^ val) & data->chan_event;
|
||||
|
||||
for_each_set_bit(chan, &prox_changed, SX9310_NUM_CHANNELS) {
|
||||
int dir;
|
||||
u64 ev;
|
||||
bool new_prox = val & BIT(chan);
|
||||
|
||||
if (!(data->chan_event & BIT(chan)))
|
||||
continue;
|
||||
if (new_prox == data->prox_stat[chan])
|
||||
/* No change on this channel. */
|
||||
continue;
|
||||
|
||||
dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
|
||||
dir = (val & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
|
||||
ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan,
|
||||
IIO_EV_TYPE_THRESH, dir);
|
||||
|
||||
iio_push_event(indio_dev, ev, timestamp);
|
||||
data->prox_stat[chan] = new_prox;
|
||||
}
|
||||
data->chan_prox_stat = val;
|
||||
}
|
||||
|
||||
static irqreturn_t sx9310_irq_thread_handler(int irq, void *private)
|
||||
@ -567,12 +567,12 @@ static irqreturn_t sx9310_irq_thread_handler(int irq, void *private)
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val);
|
||||
if (ret < 0) {
|
||||
if (ret) {
|
||||
dev_err(&data->client->dev, "i2c transfer error in irq\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (val & SX9310_EVENT_IRQ)
|
||||
if (val & (SX9310_FAR_IRQ | SX9310_CLOSE_IRQ))
|
||||
sx9310_push_events(indio_dev);
|
||||
|
||||
if (val & SX9310_CONVDONE_IRQ)
|
||||
@ -600,6 +600,7 @@ static int sx9310_write_event_config(struct iio_dev *indio_dev,
|
||||
enum iio_event_direction dir, int state)
|
||||
{
|
||||
struct sx9310_data *data = iio_priv(indio_dev);
|
||||
unsigned int eventirq = SX9310_FAR_IRQ | SX9310_CLOSE_IRQ;
|
||||
int ret;
|
||||
|
||||
/* If the state hasn't changed, there's nothing to do. */
|
||||
@ -609,20 +610,20 @@ static int sx9310_write_event_config(struct iio_dev *indio_dev,
|
||||
mutex_lock(&data->mutex);
|
||||
if (state) {
|
||||
ret = sx9310_get_event_channel(data, chan->channel);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
if (!(data->chan_event & ~BIT(chan->channel))) {
|
||||
ret = sx9310_enable_irq(data, SX9310_EVENT_IRQ);
|
||||
if (ret < 0)
|
||||
ret = sx9310_enable_irq(data, eventirq);
|
||||
if (ret)
|
||||
sx9310_put_event_channel(data, chan->channel);
|
||||
}
|
||||
} else {
|
||||
ret = sx9310_put_event_channel(data, chan->channel);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
if (!data->chan_event) {
|
||||
ret = sx9310_disable_irq(data, SX9310_EVENT_IRQ);
|
||||
if (ret < 0)
|
||||
ret = sx9310_disable_irq(data, eventirq);
|
||||
if (ret)
|
||||
sx9310_get_event_channel(data, chan->channel);
|
||||
}
|
||||
}
|
||||
@ -634,7 +635,7 @@ out_unlock:
|
||||
|
||||
static struct attribute *sx9310_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group sx9310_attribute_group = {
|
||||
@ -661,7 +662,7 @@ static int sx9310_set_trigger_state(struct iio_trigger *trig, bool state)
|
||||
ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ);
|
||||
else if (!data->chan_read)
|
||||
ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
data->trigger_enabled = state;
|
||||
@ -690,13 +691,13 @@ static irqreturn_t sx9310_trigger_handler(int irq, void *private)
|
||||
indio_dev->masklength) {
|
||||
ret = sx9310_read_prox_data(data, &indio_dev->channels[bit],
|
||||
&val);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
data->buffer[i++] = val;
|
||||
data->buffer.channels[i++] = val;
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
|
||||
pf->timestamp);
|
||||
|
||||
out:
|
||||
@ -710,13 +711,13 @@ out:
|
||||
static int sx9310_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct sx9310_data *data = iio_priv(indio_dev);
|
||||
unsigned int channels = 0;
|
||||
unsigned long channels = 0;
|
||||
int bit, ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength)
|
||||
channels |= BIT(indio_dev->channels[bit].channel);
|
||||
__set_bit(indio_dev->channels[bit].channel, &channels);
|
||||
|
||||
ret = sx9310_update_chan_en(data, channels, data->chan_event);
|
||||
mutex_unlock(&data->mutex);
|
||||
@ -744,89 +745,77 @@ struct sx9310_reg_default {
|
||||
u8 def;
|
||||
};
|
||||
|
||||
#define SX_INIT(_reg, _def) \
|
||||
{ \
|
||||
.reg = SX9310_REG_##_reg, \
|
||||
.def = _def, \
|
||||
}
|
||||
|
||||
static const struct sx9310_reg_default sx9310_default_regs[] = {
|
||||
SX_INIT(IRQ_MSK, 0x00),
|
||||
SX_INIT(IRQ_FUNC, 0x00),
|
||||
{ SX9310_REG_IRQ_MSK, 0x00 },
|
||||
{ SX9310_REG_IRQ_FUNC, 0x00 },
|
||||
/*
|
||||
* The lower 4 bits should not be set as it enable sensors measurements.
|
||||
* Turning the detection on before the configuration values are set to
|
||||
* good values can cause the device to return erroneous readings.
|
||||
*/
|
||||
SX_INIT(PROX_CTRL0, SX9310_REG_PROX_CTRL0_PROXSTAT2),
|
||||
SX_INIT(PROX_CTRL1, 0x00),
|
||||
SX_INIT(PROX_CTRL2, SX9310_REG_PROX_CTRL2_COMBMODE_ALL |
|
||||
SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC),
|
||||
SX_INIT(PROX_CTRL3, SX9310_REG_PROX_CTRL3_GAIN0_X8 |
|
||||
SX9310_REG_PROX_CTRL3_GAIN12_X4),
|
||||
SX_INIT(PROX_CTRL4, SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST),
|
||||
SX_INIT(PROX_CTRL5, SX9310_REG_PROX_CTRL5_RANGE_SMALL |
|
||||
SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 |
|
||||
SX9310_REG_PROX_CTRL5_RAWFILT_1P25),
|
||||
SX_INIT(PROX_CTRL6, SX9310_REG_PROX_CTRL6_COMP_COMMON),
|
||||
SX_INIT(PROX_CTRL7, SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 |
|
||||
SX9310_REG_PROX_CTRL7_AVGPOSFILT_512),
|
||||
SX_INIT(PROX_CTRL8, SX9310_REG_PROX_CTRL8_9_PTHRESH_96 |
|
||||
SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500),
|
||||
SX_INIT(PROX_CTRL9, SX9310_REG_PROX_CTRL8_9_PTHRESH12_28 |
|
||||
SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900),
|
||||
SX_INIT(PROX_CTRL10, SX9310_REG_PROX_CTRL10_HYST_6PCT |
|
||||
SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_8 |
|
||||
SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_8),
|
||||
SX_INIT(PROX_CTRL11, 0x00),
|
||||
SX_INIT(PROX_CTRL12, 0x00),
|
||||
SX_INIT(PROX_CTRL13, 0x00),
|
||||
SX_INIT(PROX_CTRL14, 0x00),
|
||||
SX_INIT(PROX_CTRL15, 0x00),
|
||||
SX_INIT(PROX_CTRL16, 0x00),
|
||||
SX_INIT(PROX_CTRL17, 0x00),
|
||||
SX_INIT(PROX_CTRL18, 0x00),
|
||||
SX_INIT(PROX_CTRL19, 0x00),
|
||||
SX_INIT(SAR_CTRL0, SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES |
|
||||
SX9310_REG_SAR_CTRL0_SARHYST_8),
|
||||
SX_INIT(SAR_CTRL1, SX9310_REG_SAR_CTRL1_SLOPE(10781250)),
|
||||
SX_INIT(SAR_CTRL2, SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT),
|
||||
{ SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS },
|
||||
{ SX9310_REG_PROX_CTRL1, 0x00 },
|
||||
{ SX9310_REG_PROX_CTRL2, SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2 |
|
||||
SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC },
|
||||
{ SX9310_REG_PROX_CTRL3, SX9310_REG_PROX_CTRL3_GAIN0_X8 |
|
||||
SX9310_REG_PROX_CTRL3_GAIN12_X4 },
|
||||
{ SX9310_REG_PROX_CTRL4, SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST },
|
||||
{ SX9310_REG_PROX_CTRL5, SX9310_REG_PROX_CTRL5_RANGE_SMALL |
|
||||
SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 |
|
||||
SX9310_REG_PROX_CTRL5_RAWFILT_1P25 },
|
||||
{ SX9310_REG_PROX_CTRL6, SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT },
|
||||
{ SX9310_REG_PROX_CTRL7, SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 |
|
||||
SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 },
|
||||
{ SX9310_REG_PROX_CTRL8, SX9310_REG_PROX_CTRL8_9_PTHRESH_96 |
|
||||
SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500 },
|
||||
{ SX9310_REG_PROX_CTRL9, SX9310_REG_PROX_CTRL8_9_PTHRESH_28 |
|
||||
SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900 },
|
||||
{ SX9310_REG_PROX_CTRL10, SX9310_REG_PROX_CTRL10_HYST_6PCT |
|
||||
SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2 },
|
||||
{ SX9310_REG_PROX_CTRL11, 0x00 },
|
||||
{ SX9310_REG_PROX_CTRL12, 0x00 },
|
||||
{ SX9310_REG_PROX_CTRL13, 0x00 },
|
||||
{ SX9310_REG_PROX_CTRL14, 0x00 },
|
||||
{ SX9310_REG_PROX_CTRL15, 0x00 },
|
||||
{ SX9310_REG_PROX_CTRL16, 0x00 },
|
||||
{ SX9310_REG_PROX_CTRL17, 0x00 },
|
||||
{ SX9310_REG_PROX_CTRL18, 0x00 },
|
||||
{ SX9310_REG_PROX_CTRL19, 0x00 },
|
||||
{ SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES |
|
||||
SX9310_REG_SAR_CTRL0_SARHYST_8 },
|
||||
{ SX9310_REG_SAR_CTRL1, SX9310_REG_SAR_CTRL1_SLOPE(10781250) },
|
||||
{ SX9310_REG_SAR_CTRL2, SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT },
|
||||
};
|
||||
|
||||
/* Activate all channels and perform an initial compensation. */
|
||||
static int sx9310_init_compensation(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct sx9310_data *data = iio_priv(indio_dev);
|
||||
int i, ret;
|
||||
int ret;
|
||||
unsigned int val;
|
||||
unsigned int ctrl0;
|
||||
|
||||
ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &ctrl0);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* run the compensation phase on all channels */
|
||||
ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0,
|
||||
ctrl0 | SX9310_REG_PROX_CTRL0_EN_MASK);
|
||||
if (ret < 0)
|
||||
ctrl0 | SX9310_REG_PROX_CTRL0_SENSOREN_MASK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 100; i >= 0; i--) {
|
||||
msleep(20);
|
||||
ret = regmap_read(data->regmap, SX9310_REG_STAT1, &val);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (!(val & SX9310_COMPSTAT_MASK))
|
||||
break;
|
||||
ret = regmap_read_poll_timeout(data->regmap, SX9310_REG_STAT1, val,
|
||||
!(val & SX9310_REG_STAT1_COMPSTAT_MASK),
|
||||
20000, 2000000);
|
||||
if (ret) {
|
||||
if (ret == -ETIMEDOUT)
|
||||
dev_err(&data->client->dev,
|
||||
"initial compensation timed out: 0x%02x\n",
|
||||
val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"initial compensation timed out: 0x%02x", val);
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
out:
|
||||
regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);
|
||||
return ret;
|
||||
}
|
||||
@ -839,21 +828,21 @@ static int sx9310_init_device(struct iio_dev *indio_dev)
|
||||
unsigned int i, val;
|
||||
|
||||
ret = regmap_write(data->regmap, SX9310_REG_RESET, SX9310_SOFT_RESET);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
usleep_range(1000, 2000); /* power-up time is ~1ms. */
|
||||
|
||||
/* Clear reset interrupt state by reading SX9310_REG_IRQ_SRC. */
|
||||
ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Program some sane defaults. */
|
||||
for (i = 0; i < ARRAY_SIZE(sx9310_default_regs); i++) {
|
||||
initval = &sx9310_default_regs[i];
|
||||
ret = regmap_write(data->regmap, initval->reg, initval->def);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -862,24 +851,15 @@ static int sx9310_init_device(struct iio_dev *indio_dev)
|
||||
|
||||
static int sx9310_set_indio_dev_name(struct device *dev,
|
||||
struct iio_dev *indio_dev,
|
||||
const struct i2c_device_id *id, int whoami)
|
||||
unsigned int whoami)
|
||||
{
|
||||
const struct acpi_device_id *acpi_id;
|
||||
unsigned int long ddata;
|
||||
|
||||
/* id will be NULL when enumerated via ACPI */
|
||||
if (id) {
|
||||
if (id->driver_data != whoami)
|
||||
dev_err(dev, "WHOAMI does not match i2c_device_id: %s",
|
||||
id->name);
|
||||
} else if (ACPI_HANDLE(dev)) {
|
||||
acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
if (!acpi_id)
|
||||
return -ENODEV;
|
||||
if (acpi_id->driver_data != whoami)
|
||||
dev_err(dev, "WHOAMI does not match acpi_device_id: %s",
|
||||
acpi_id->id);
|
||||
} else
|
||||
ddata = (uintptr_t)device_get_match_data(dev);
|
||||
if (ddata != whoami) {
|
||||
dev_err(dev, "WHOAMI does not match device data: %u\n", whoami);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
switch (whoami) {
|
||||
case SX9310_WHOAMI_VALUE:
|
||||
@ -889,26 +869,35 @@ static int sx9310_set_indio_dev_name(struct device *dev,
|
||||
indio_dev->name = "sx9311";
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unexpected WHOAMI response: %u", whoami);
|
||||
dev_err(dev, "unexpected WHOAMI response: %u\n", whoami);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sx9310_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static void sx9310_regulator_disable(void *_data)
|
||||
{
|
||||
struct sx9310_data *data = _data;
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
|
||||
}
|
||||
|
||||
static int sx9310_probe(struct i2c_client *client)
|
||||
{
|
||||
int ret;
|
||||
struct device *dev = &client->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct sx9310_data *data;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (indio_dev == NULL)
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
data->client = client;
|
||||
data->supplies[0].supply = "vdd";
|
||||
data->supplies[1].supply = "svdd";
|
||||
mutex_init(&data->mutex);
|
||||
init_completion(&data->completion);
|
||||
|
||||
@ -916,19 +905,32 @@ static int sx9310_probe(struct i2c_client *client,
|
||||
if (IS_ERR(data->regmap))
|
||||
return PTR_ERR(data->regmap);
|
||||
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
|
||||
data->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Must wait for Tpor time after initial power up */
|
||||
usleep_range(1000, 1100);
|
||||
|
||||
ret = devm_add_action_or_reset(dev, sx9310_regulator_disable, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read(data->regmap, SX9310_REG_WHOAMI, &data->whoami);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "error in reading WHOAMI register: %d",
|
||||
ret);
|
||||
if (ret) {
|
||||
dev_err(dev, "error in reading WHOAMI register: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sx9310_set_indio_dev_name(&client->dev, indio_dev, id,
|
||||
data->whoami);
|
||||
if (ret < 0)
|
||||
ret = sx9310_set_indio_dev_name(dev, indio_dev, data->whoami);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ACPI_COMPANION_SET(&indio_dev->dev, ACPI_COMPANION(&client->dev));
|
||||
ACPI_COMPANION_SET(&indio_dev->dev, ACPI_COMPANION(dev));
|
||||
indio_dev->channels = sx9310_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(sx9310_channels);
|
||||
indio_dev->info = &sx9310_info;
|
||||
@ -936,41 +938,41 @@ static int sx9310_probe(struct i2c_client *client,
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
ret = sx9310_init_device(indio_dev);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (client->irq) {
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
ret = devm_request_threaded_irq(dev, client->irq,
|
||||
sx9310_irq_handler,
|
||||
sx9310_irq_thread_handler,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
IRQF_ONESHOT,
|
||||
"sx9310_event", indio_dev);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->trig =
|
||||
devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
|
||||
indio_dev->name, indio_dev->id);
|
||||
data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
if (!data->trig)
|
||||
return -ENOMEM;
|
||||
|
||||
data->trig->dev.parent = &client->dev;
|
||||
data->trig->dev.parent = dev;
|
||||
data->trig->ops = &sx9310_trigger_ops;
|
||||
iio_trigger_set_drvdata(data->trig, indio_dev);
|
||||
|
||||
ret = devm_iio_trigger_register(&client->dev, data->trig);
|
||||
ret = devm_iio_trigger_register(dev, data->trig);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
sx9310_trigger_handler,
|
||||
&sx9310_buffer_setup_ops);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused sx9310_suspend(struct device *dev)
|
||||
@ -985,11 +987,10 @@ static int __maybe_unused sx9310_suspend(struct device *dev)
|
||||
mutex_lock(&data->mutex);
|
||||
ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0,
|
||||
&data->suspend_ctrl0);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ctrl0 = data->suspend_ctrl0 & ~SX9310_REG_PROX_CTRL0_EN_MASK;
|
||||
ctrl0 = data->suspend_ctrl0 & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK;
|
||||
ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);
|
||||
if (ret)
|
||||
goto out;
|
||||
@ -1017,10 +1018,11 @@ static int __maybe_unused sx9310_resume(struct device *dev)
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
enable_irq(data->client->irq);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops sx9310_pm_ops = {
|
||||
@ -1030,32 +1032,32 @@ static const struct dev_pm_ops sx9310_pm_ops = {
|
||||
static const struct acpi_device_id sx9310_acpi_match[] = {
|
||||
{ "STH9310", SX9310_WHOAMI_VALUE },
|
||||
{ "STH9311", SX9311_WHOAMI_VALUE },
|
||||
{},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match);
|
||||
|
||||
static const struct of_device_id sx9310_of_match[] = {
|
||||
{ .compatible = "semtech,sx9310" },
|
||||
{ .compatible = "semtech,sx9311" },
|
||||
{},
|
||||
{ .compatible = "semtech,sx9310", (void *)SX9310_WHOAMI_VALUE },
|
||||
{ .compatible = "semtech,sx9311", (void *)SX9311_WHOAMI_VALUE },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sx9310_of_match);
|
||||
|
||||
static const struct i2c_device_id sx9310_id[] = {
|
||||
{ "sx9310", SX9310_WHOAMI_VALUE },
|
||||
{ "sx9311", SX9311_WHOAMI_VALUE },
|
||||
{},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sx9310_id);
|
||||
|
||||
static struct i2c_driver sx9310_driver = {
|
||||
.driver = {
|
||||
.name = "sx9310",
|
||||
.acpi_match_table = ACPI_PTR(sx9310_acpi_match),
|
||||
.of_match_table = of_match_ptr(sx9310_of_match),
|
||||
.acpi_match_table = sx9310_acpi_match,
|
||||
.of_match_table = sx9310_of_match,
|
||||
.pm = &sx9310_pm_ops,
|
||||
},
|
||||
.probe = sx9310_probe,
|
||||
.probe_new = sx9310_probe,
|
||||
.id_table = sx9310_id,
|
||||
};
|
||||
module_i2c_driver(sx9310_driver);
|
||||
|
@ -10,7 +10,9 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/of.h>
|
||||
@ -58,6 +60,8 @@
|
||||
/* Control register address - volatile */
|
||||
#define MLX90632_REG_CONTROL 0x3001 /* Control Register address */
|
||||
#define MLX90632_CFG_PWR_MASK GENMASK(2, 1) /* PowerMode Mask */
|
||||
#define MLX90632_CFG_MTYP_MASK GENMASK(8, 4) /* Meas select Mask */
|
||||
|
||||
/* PowerModes statuses */
|
||||
#define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1)
|
||||
#define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /* hold */
|
||||
@ -65,6 +69,18 @@
|
||||
#define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /* step */
|
||||
#define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous*/
|
||||
|
||||
/* Measurement types */
|
||||
#define MLX90632_MTYP_MEDICAL 0
|
||||
#define MLX90632_MTYP_EXTENDED 17
|
||||
|
||||
/* Measurement type select*/
|
||||
#define MLX90632_MTYP_STATUS(ctrl_val) (ctrl_val << 4)
|
||||
#define MLX90632_MTYP_STATUS_MEDICAL MLX90632_MTYP_STATUS(MLX90632_MTYP_MEDICAL)
|
||||
#define MLX90632_MTYP_STATUS_EXTENDED MLX90632_MTYP_STATUS(MLX90632_MTYP_EXTENDED)
|
||||
|
||||
/* I2C command register - volatile */
|
||||
#define MLX90632_REG_I2C_CMD 0x3005 /* I2C command Register address */
|
||||
|
||||
/* Device status register - volatile */
|
||||
#define MLX90632_REG_STATUS 0x3fff /* Device status register */
|
||||
#define MLX90632_STAT_BUSY BIT(10) /* Device busy indicator */
|
||||
@ -78,26 +94,53 @@
|
||||
#define MLX90632_RAM_2(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 1)
|
||||
#define MLX90632_RAM_3(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 2)
|
||||
|
||||
/* Name important RAM_MEAS channels */
|
||||
#define MLX90632_RAM_DSP5_EXTENDED_AMBIENT_1 MLX90632_RAM_3(17)
|
||||
#define MLX90632_RAM_DSP5_EXTENDED_AMBIENT_2 MLX90632_RAM_3(18)
|
||||
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_1 MLX90632_RAM_1(17)
|
||||
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_2 MLX90632_RAM_2(17)
|
||||
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_3 MLX90632_RAM_1(18)
|
||||
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_4 MLX90632_RAM_2(18)
|
||||
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_5 MLX90632_RAM_1(19)
|
||||
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_6 MLX90632_RAM_2(19)
|
||||
|
||||
/* Magic constants */
|
||||
#define MLX90632_ID_MEDICAL 0x0105 /* EEPROM DSPv5 Medical device id */
|
||||
#define MLX90632_ID_CONSUMER 0x0205 /* EEPROM DSPv5 Consumer device id */
|
||||
#define MLX90632_ID_EXTENDED 0x0505 /* EEPROM DSPv5 Extended range device id */
|
||||
#define MLX90632_ID_MASK GENMASK(14, 0) /* DSP version and device ID in EE_VERSION */
|
||||
#define MLX90632_DSP_VERSION 5 /* DSP version */
|
||||
#define MLX90632_DSP_MASK GENMASK(7, 0) /* DSP version in EE_VERSION */
|
||||
#define MLX90632_RESET_CMD 0x0006 /* Reset sensor (address or global) */
|
||||
#define MLX90632_REF_12 12LL /**< ResCtrlRef value of Ch 1 or Ch 2 */
|
||||
#define MLX90632_REF_3 12LL /**< ResCtrlRef value of Channel 3 */
|
||||
#define MLX90632_MAX_MEAS_NUM 31 /**< Maximum measurements in list */
|
||||
#define MLX90632_SLEEP_DELAY_MS 3000 /**< Autosleep delay */
|
||||
#define MLX90632_REF_12 12LL /* ResCtrlRef value of Ch 1 or Ch 2 */
|
||||
#define MLX90632_REF_3 12LL /* ResCtrlRef value of Channel 3 */
|
||||
#define MLX90632_MAX_MEAS_NUM 31 /* Maximum measurements in list */
|
||||
#define MLX90632_SLEEP_DELAY_MS 3000 /* Autosleep delay */
|
||||
#define MLX90632_EXTENDED_LIMIT 27000 /* Extended mode raw value limit */
|
||||
|
||||
/**
|
||||
* struct mlx90632_data - private data for the MLX90632 device
|
||||
* @client: I2C client of the device
|
||||
* @lock: Internal mutex for multiple reads for single measurement
|
||||
* @regmap: Regmap of the device
|
||||
* @emissivity: Object emissivity from 0 to 1000 where 1000 = 1.
|
||||
* @mtyp: Measurement type physical sensor configuration for extended range
|
||||
* calculations
|
||||
* @object_ambient_temperature: Ambient temperature at object (might differ of
|
||||
* the ambient temperature of sensor.
|
||||
*/
|
||||
struct mlx90632_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock; /* Multiple reads for single measurement */
|
||||
struct mutex lock;
|
||||
struct regmap *regmap;
|
||||
u16 emissivity;
|
||||
u8 mtyp;
|
||||
u32 object_ambient_temperature;
|
||||
};
|
||||
|
||||
static const struct regmap_range mlx90632_volatile_reg_range[] = {
|
||||
regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
|
||||
regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD),
|
||||
regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
|
||||
regmap_reg_range(MLX90632_RAM_1(0),
|
||||
MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
|
||||
@ -113,6 +156,7 @@ static const struct regmap_range mlx90632_read_reg_range[] = {
|
||||
regmap_reg_range(MLX90632_EE_CTRL, MLX90632_EE_I2C_ADDR),
|
||||
regmap_reg_range(MLX90632_EE_Ha, MLX90632_EE_Hb),
|
||||
regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
|
||||
regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD),
|
||||
regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
|
||||
regmap_reg_range(MLX90632_RAM_1(0),
|
||||
MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
|
||||
@ -173,25 +217,19 @@ static s32 mlx90632_pwr_continuous(struct regmap *regmap)
|
||||
*/
|
||||
static int mlx90632_perform_measurement(struct mlx90632_data *data)
|
||||
{
|
||||
int ret, tries = 100;
|
||||
unsigned int reg_status;
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, MLX90632_REG_STATUS,
|
||||
MLX90632_STAT_DATA_RDY, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
while (tries-- > 0) {
|
||||
ret = regmap_read(data->regmap, MLX90632_REG_STATUS,
|
||||
®_status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (reg_status & MLX90632_STAT_DATA_RDY)
|
||||
break;
|
||||
usleep_range(10000, 11000);
|
||||
}
|
||||
ret = regmap_read_poll_timeout(data->regmap, MLX90632_REG_STATUS, reg_status,
|
||||
!(reg_status & MLX90632_STAT_DATA_RDY), 10000,
|
||||
100 * 10000);
|
||||
|
||||
if (tries < 0) {
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "data not ready");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
@ -199,6 +237,26 @@ static int mlx90632_perform_measurement(struct mlx90632_data *data)
|
||||
return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2;
|
||||
}
|
||||
|
||||
static int mlx90632_set_meas_type(struct regmap *regmap, u8 type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((type != MLX90632_MTYP_MEDICAL) && (type != MLX90632_MTYP_EXTENDED))
|
||||
return -EINVAL;
|
||||
|
||||
ret = regmap_write(regmap, MLX90632_REG_I2C_CMD, MLX90632_RESET_CMD);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL,
|
||||
(MLX90632_CFG_MTYP_MASK | MLX90632_CFG_PWR_MASK),
|
||||
(MLX90632_MTYP_STATUS(type) | MLX90632_PWR_STATUS_HALT));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return mlx90632_pwr_continuous(regmap);
|
||||
}
|
||||
|
||||
static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
|
||||
uint8_t *channel_old)
|
||||
{
|
||||
@ -300,6 +358,97 @@ read_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mlx90632_read_ambient_raw_extended(struct regmap *regmap,
|
||||
s16 *ambient_new_raw, s16 *ambient_old_raw)
|
||||
{
|
||||
unsigned int read_tmp;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_AMBIENT_1, &read_tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*ambient_new_raw = (s16)read_tmp;
|
||||
|
||||
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_AMBIENT_2, &read_tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*ambient_old_raw = (s16)read_tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx90632_read_object_raw_extended(struct regmap *regmap, s16 *object_new_raw)
|
||||
{
|
||||
unsigned int read_tmp;
|
||||
s32 read;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_1, &read_tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
read = (s16)read_tmp;
|
||||
|
||||
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_2, &read_tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
read = read - (s16)read_tmp;
|
||||
|
||||
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_3, &read_tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
read = read - (s16)read_tmp;
|
||||
|
||||
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_4, &read_tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
read = (read + (s16)read_tmp) / 2;
|
||||
|
||||
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_5, &read_tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
read = read + (s16)read_tmp;
|
||||
|
||||
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_6, &read_tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
read = read + (s16)read_tmp;
|
||||
|
||||
if (read > S16_MAX || read < S16_MIN)
|
||||
return -ERANGE;
|
||||
|
||||
*object_new_raw = read;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx90632_read_all_channel_extended(struct mlx90632_data *data, s16 *object_new_raw,
|
||||
s16 *ambient_new_raw, s16 *ambient_old_raw)
|
||||
{
|
||||
s32 ret, meas;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_EXTENDED);
|
||||
if (ret < 0)
|
||||
goto read_unlock;
|
||||
|
||||
ret = read_poll_timeout(mlx90632_perform_measurement, meas, meas == 19,
|
||||
50000, 800000, false, data);
|
||||
if (ret != 0)
|
||||
goto read_unlock;
|
||||
|
||||
ret = mlx90632_read_object_raw_extended(data->regmap, object_new_raw);
|
||||
if (ret < 0)
|
||||
goto read_unlock;
|
||||
|
||||
ret = mlx90632_read_ambient_raw_extended(data->regmap, ambient_new_raw, ambient_old_raw);
|
||||
|
||||
read_unlock:
|
||||
(void) mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_MEDICAL);
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mlx90632_read_ee_register(struct regmap *regmap, u16 reg_lsb,
|
||||
s32 *reg_value)
|
||||
{
|
||||
@ -354,9 +503,23 @@ static s64 mlx90632_preprocess_temp_obj(s16 object_new_raw, s16 object_old_raw,
|
||||
return div64_s64((tmp << 19ULL), 1000LL);
|
||||
}
|
||||
|
||||
static s64 mlx90632_preprocess_temp_obj_extended(s16 object_new_raw, s16 ambient_new_raw,
|
||||
s16 ambient_old_raw, s16 Ka)
|
||||
{
|
||||
s64 VR_IR, kKa, tmp;
|
||||
|
||||
kKa = ((s64)Ka * 1000LL) >> 10ULL;
|
||||
VR_IR = (s64)ambient_old_raw * 1000000LL +
|
||||
kKa * div64_s64((s64)ambient_new_raw * 1000LL,
|
||||
MLX90632_REF_3);
|
||||
tmp = div64_s64(
|
||||
div64_s64((s64) object_new_raw * 1000000000000LL, MLX90632_REF_12),
|
||||
VR_IR);
|
||||
return div64_s64(tmp << 19ULL, 1000LL);
|
||||
}
|
||||
|
||||
static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw,
|
||||
s32 P_T, s32 P_R, s32 P_G, s32 P_O,
|
||||
s16 Gb)
|
||||
s32 P_T, s32 P_R, s32 P_G, s32 P_O, s16 Gb)
|
||||
{
|
||||
s64 Asub, Bsub, Ablock, Bblock, Cblock, AMB, sum;
|
||||
|
||||
@ -374,11 +537,11 @@ static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw,
|
||||
}
|
||||
|
||||
static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object,
|
||||
s64 TAdut, s32 Fa, s32 Fb,
|
||||
s64 TAdut, s64 TAdut4, s32 Fa, s32 Fb,
|
||||
s32 Ga, s16 Ha, s16 Hb,
|
||||
u16 emissivity)
|
||||
{
|
||||
s64 calcedKsTO, calcedKsTA, ir_Alpha, TAdut4, Alpha_corr;
|
||||
s64 calcedKsTO, calcedKsTA, ir_Alpha, Alpha_corr;
|
||||
s64 Ha_customer, Hb_customer;
|
||||
|
||||
Ha_customer = ((s64)Ha * 1000000LL) >> 14ULL;
|
||||
@ -393,36 +556,66 @@ static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object,
|
||||
Alpha_corr = emissivity * div64_s64(Alpha_corr, 100000LL);
|
||||
Alpha_corr = div64_s64(Alpha_corr, 1000LL);
|
||||
ir_Alpha = div64_s64((s64)object * 10000000LL, Alpha_corr);
|
||||
TAdut4 = (div64_s64(TAdut, 10000LL) + 27315) *
|
||||
(div64_s64(TAdut, 10000LL) + 27315) *
|
||||
(div64_s64(TAdut, 10000LL) + 27315) *
|
||||
(div64_s64(TAdut, 10000LL) + 27315);
|
||||
|
||||
return (int_sqrt64(int_sqrt64(ir_Alpha * 1000000000000LL + TAdut4))
|
||||
- 27315 - Hb_customer) * 10;
|
||||
}
|
||||
|
||||
static s64 mlx90632_calc_ta4(s64 TAdut, s64 scale)
|
||||
{
|
||||
return (div64_s64(TAdut, scale) + 27315) *
|
||||
(div64_s64(TAdut, scale) + 27315) *
|
||||
(div64_s64(TAdut, scale) + 27315) *
|
||||
(div64_s64(TAdut, scale) + 27315);
|
||||
}
|
||||
|
||||
static s32 mlx90632_calc_temp_object(s64 object, s64 ambient, s32 Ea, s32 Eb,
|
||||
s32 Fa, s32 Fb, s32 Ga, s16 Ha, s16 Hb,
|
||||
u16 tmp_emi)
|
||||
{
|
||||
s64 kTA, kTA0, TAdut;
|
||||
s64 kTA, kTA0, TAdut, TAdut4;
|
||||
s64 temp = 25000;
|
||||
s8 i;
|
||||
|
||||
kTA = (Ea * 1000LL) >> 16LL;
|
||||
kTA0 = (Eb * 1000LL) >> 8LL;
|
||||
TAdut = div64_s64(((ambient - kTA0) * 1000000LL), kTA) + 25 * 1000000LL;
|
||||
TAdut4 = mlx90632_calc_ta4(TAdut, 10000LL);
|
||||
|
||||
/* Iterations of calculation as described in datasheet */
|
||||
for (i = 0; i < 5; ++i) {
|
||||
temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut,
|
||||
temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut, TAdut4,
|
||||
Fa, Fb, Ga, Ha, Hb,
|
||||
tmp_emi);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
static s32 mlx90632_calc_temp_object_extended(s64 object, s64 ambient, s64 reflected,
|
||||
s32 Ea, s32 Eb, s32 Fa, s32 Fb, s32 Ga,
|
||||
s16 Ha, s16 Hb, u16 tmp_emi)
|
||||
{
|
||||
s64 kTA, kTA0, TAdut, TAdut4, Tr4, TaTr4;
|
||||
s64 temp = 25000;
|
||||
s8 i;
|
||||
|
||||
kTA = (Ea * 1000LL) >> 16LL;
|
||||
kTA0 = (Eb * 1000LL) >> 8LL;
|
||||
TAdut = div64_s64((ambient - kTA0) * 1000000LL, kTA) + 25 * 1000000LL;
|
||||
Tr4 = mlx90632_calc_ta4(reflected, 10);
|
||||
TAdut4 = mlx90632_calc_ta4(TAdut, 10000LL);
|
||||
TaTr4 = Tr4 - div64_s64(Tr4 - TAdut4, tmp_emi) * 1000;
|
||||
|
||||
/* Iterations of calculation as described in datasheet */
|
||||
for (i = 0; i < 5; ++i) {
|
||||
temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut, TaTr4,
|
||||
Fa / 2, Fb, Ga, Ha, Hb,
|
||||
tmp_emi);
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
|
||||
{
|
||||
s32 ret;
|
||||
@ -470,6 +663,26 @@ static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (object_new_raw > MLX90632_EXTENDED_LIMIT &&
|
||||
data->mtyp == MLX90632_MTYP_EXTENDED) {
|
||||
ret = mlx90632_read_all_channel_extended(data, &object_new_raw,
|
||||
&ambient_new_raw, &ambient_old_raw);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Use extended mode calculations */
|
||||
ambient = mlx90632_preprocess_temp_amb(ambient_new_raw,
|
||||
ambient_old_raw, Gb);
|
||||
object = mlx90632_preprocess_temp_obj_extended(object_new_raw,
|
||||
ambient_new_raw,
|
||||
ambient_old_raw, Ka);
|
||||
*val = mlx90632_calc_temp_object_extended(object, ambient,
|
||||
data->object_ambient_temperature,
|
||||
Ea, Eb, Fa, Fb, Ga,
|
||||
Ha, Hb, data->emissivity);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ambient = mlx90632_preprocess_temp_amb(ambient_new_raw,
|
||||
ambient_old_raw, Gb);
|
||||
object = mlx90632_preprocess_temp_obj(object_new_raw,
|
||||
@ -643,6 +856,7 @@ static int mlx90632_probe(struct i2c_client *client,
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
mlx90632->client = client;
|
||||
mlx90632->regmap = regmap;
|
||||
mlx90632->mtyp = MLX90632_MTYP_MEDICAL;
|
||||
|
||||
mutex_init(&mlx90632->lock);
|
||||
indio_dev->name = id->name;
|
||||
@ -662,15 +876,20 @@ static int mlx90632_probe(struct i2c_client *client,
|
||||
dev_err(&client->dev, "read of version failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
read = read & MLX90632_ID_MASK;
|
||||
if (read == MLX90632_ID_MEDICAL) {
|
||||
dev_dbg(&client->dev,
|
||||
"Detected Medical EEPROM calibration %x\n", read);
|
||||
} else if (read == MLX90632_ID_CONSUMER) {
|
||||
dev_dbg(&client->dev,
|
||||
"Detected Consumer EEPROM calibration %x\n", read);
|
||||
} else if (read == MLX90632_ID_EXTENDED) {
|
||||
dev_dbg(&client->dev,
|
||||
"Detected Extended range EEPROM calibration %x\n", read);
|
||||
mlx90632->mtyp = MLX90632_MTYP_EXTENDED;
|
||||
} else if ((read & MLX90632_DSP_MASK) == MLX90632_DSP_VERSION) {
|
||||
dev_dbg(&client->dev,
|
||||
"Detected Unknown EEPROM calibration %x\n", read);
|
||||
"Detected Unknown EEPROM calibration %x\n", read);
|
||||
} else {
|
||||
dev_err(&client->dev,
|
||||
"Wrong DSP version %x (expected %x)\n",
|
||||
@ -679,6 +898,7 @@ static int mlx90632_probe(struct i2c_client *client,
|
||||
}
|
||||
|
||||
mlx90632->emissivity = 1000;
|
||||
mlx90632->object_ambient_temperature = 25000; /* 25 degrees milliCelsius */
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
ret = pm_runtime_set_active(&client->dev);
|
||||
|
@ -9,7 +9,7 @@ The aim is to fill the gap between the somewhat similar hwmon and
|
||||
input subsystems. Hwmon is very much directed at low sample rate
|
||||
sensors used in applications such as fan speed control and temperature
|
||||
measurement. Input is, as its name suggests focused on input
|
||||
devices. In some cases there is considerable overlap between these and
|
||||
devices. In some cases, there is considerable overlap between these and
|
||||
IIO.
|
||||
|
||||
A typical device falling into this category would be connected via SPI
|
||||
@ -38,7 +38,7 @@ series and Analog Devices ADXL345 accelerometers. Each buffer supports
|
||||
polling to establish when data is available.
|
||||
|
||||
* Trigger and software buffer support. In many data analysis
|
||||
applications it it useful to be able to capture data based on some
|
||||
applications it is useful to be able to capture data based on some
|
||||
external signal (trigger). These triggers might be a data ready
|
||||
signal, a gpio line connected to some external system or an on
|
||||
processor periodic interrupt. A single trigger may initialize data
|
||||
|
@ -397,7 +397,6 @@ static int ad9834_probe(struct spi_device *spi)
|
||||
struct regulator *reg;
|
||||
int ret;
|
||||
|
||||
|
||||
reg = devm_regulator_get(&spi->dev, "avdd");
|
||||
if (IS_ERR(reg))
|
||||
return PTR_ERR(reg);
|
||||
|
@ -40,7 +40,7 @@ enum ad7793_bias_voltage {
|
||||
* enum ad7793_refsel - AD7793 reference voltage selection
|
||||
* @AD7793_REFSEL_REFIN1: External reference applied between REFIN1(+)
|
||||
* and REFIN1(-).
|
||||
* @AD7793_REFSEL_REFIN2: External reference applied between REFIN2(+) and
|
||||
* @AD7793_REFSEL_REFIN2: External reference applied between REFIN2(+)
|
||||
* and REFIN1(-). Only valid for AD7795/AD7796.
|
||||
* @AD7793_REFSEL_INTERNAL: Internal 1.17 V reference.
|
||||
*/
|
||||
|
@ -94,6 +94,7 @@ enum iio_modifier {
|
||||
IIO_MOD_PM10,
|
||||
IIO_MOD_ETHANOL,
|
||||
IIO_MOD_H2,
|
||||
IIO_MOD_O2,
|
||||
};
|
||||
|
||||
enum iio_event_type {
|
||||
|
@ -119,6 +119,7 @@ static const char * const iio_modifier_names[] = {
|
||||
[IIO_MOD_PM2P5] = "pm2p5",
|
||||
[IIO_MOD_PM4] = "pm4",
|
||||
[IIO_MOD_PM10] = "pm10",
|
||||
[IIO_MOD_O2] = "o2",
|
||||
};
|
||||
|
||||
static bool event_is_known(struct iio_event_data *event)
|
||||
@ -211,6 +212,7 @@ static bool event_is_known(struct iio_event_data *event)
|
||||
case IIO_MOD_PM2P5:
|
||||
case IIO_MOD_PM4:
|
||||
case IIO_MOD_PM10:
|
||||
case IIO_MOD_O2:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user