Second set of IIO new device support, features and cleanups.
There are also a couple of fixes that can wait for the coming merge window. Core new features * Support for phase channels (used in time of flight sensors amongst other things) * Support for deep UV light channel modifier. New Device Support * AD4758 DAC - New driver and dt bindings. * adxl345 - Support the adxl375 +-200g part which is register compatible. * isl29501 Time of flight sensor. - New driver * meson-saradc - Support the Meson8m2 Socs - right now this is just an ID, but there will be additional difference in future. * mpu6050 - New ID for 6515 variant. * si1133 UV sensor. - New driver * Spreadtrum SC27xx PMIC ADC - New driver and dt bindings. Features * adxl345 - Add calibration offset readback and writing. - Add sampling frequency control. Fixes and Cleanups * ad5933 - Use a macro for the channel definition to reduce duplication. * ad9523 - Replace use of core mlock with a local lock. Part of ongoing efforts to avoid confusing the purpose of mlock which is only about iio core state changes. - Fix displayed phase which was out by a factor of 10. * adxl345 - Add a link to the datasheet. - Rework the use of the address field in the chan_spec structures to allow addition of more per channel information. * adis imu - Mark switch fall throughs. * at91-sama5d2 - Fix some casting on big endian systems. * bmp280 - Drop some DT elements that aren't used and should mostly be done from userspace rather than in DT. * hx711 - add clock-frequency dt binding and resulting delay to deal with capacitance issue on some boards. - fix a spurious unit-address in the example. * ina2xx - Avoid a possible kthread_stop with a stale task_struct. * ltc2632 - Remove some unused local variables (assigned but value never used). * max1363 - Use device_get_match_data to remove some boilerplate. * mma8452 - Mark switch fall throughs. * sca3000 - Fix a missing return in a switch statement (a bad fallthrough previously!) * sigma-delta-modulator - Drop incorrect unit address from the DT example. * st_accel - Use device_get_match_data to drop some boiler plate. - Move to probe_new for i2c driver as second parameter not used. * st_sensors library - Use a strlcpy (safe in this case). * st_lsm6dsx - Add some error logging. * ti-ads7950 - SPDX - Allow simultaneous buffered and polled reads. Needed on a Lego Mindstorms EV3 where some channels are used for power supply monitoring at a very low rate. * ti-dac5571 - Remove an unused variable. * xadc - Drop some dead code. -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAltXZAkRHGppYzIzQGtl cm5lbC5vcmcACgkQVIU0mcT0FohYZQ//VAjpDBYjLzYTvTJy5bDt61fbh8KabhBf oxLIpwYrCeleLnpbrY7nU8shdIL7Vm755jtsHbTtQPCKSQ0RGnhLLDoqoWcmn70J rF9iVaSv+S2lZO+9+hv2eeqyX+kSM+74fkWRuLmDbaSZWYO4Jt9zFER1zizmPypY DnxLcViw1kwOLbiZKwmcaK0MqlWHRPhEEcNVKy7VGZHznbylujh8evkzzQNVWOol QrR2NG7V8BcLTflmsYCErQDvgciGjscnVZUAyY3yNLIpceGCSHZfUsE8ld6iPrS+ aPeuiIxDhHAKyoOTQwsGi9ex7KEOUOkoDHhKdR3Jr74mtfcPF5B+TxgXU0p5UZ9g GummuvSX0izYjUZ9P4keVgu3W4bvmR9Kd8oJUHNByWI1iecoXP9bQf33tEyb26R6 G1zvGSDXPNK1V7OEaGvzGkgxOY0ZAIWLRX/+wasErdJnt3lmOV9+cCSkJAFSNrk3 jQ922q2ZWLfYAL6nNIAx2dIiJirxTQ2JIq/bys2BHiYvkuvqNcKoBIDAGlQ4xBKm /c5z9Dm/DxQpdlKFQugHmc5awLEZxpq2LCTBLlgM8z6+uRWXui+slPfIrfX5RWun BHaLmPNm6tKQLadjwWCoxXYjKqgK0wm35Yq5d5He7d45d3QWKvtUgZAj33pcIgTE wKmwF5oaLiU= =T+hS -----END PGP SIGNATURE----- Merge tag 'iio-for-4.19b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: Second set of IIO new device support, features and cleanups. There are also a couple of fixes that can wait for the coming merge window. Core new features * Support for phase channels (used in time of flight sensors amongst other things) * Support for deep UV light channel modifier. New Device Support * AD4758 DAC - New driver and dt bindings. * adxl345 - Support the adxl375 +-200g part which is register compatible. * isl29501 Time of flight sensor. - New driver * meson-saradc - Support the Meson8m2 Socs - right now this is just an ID, but there will be additional difference in future. * mpu6050 - New ID for 6515 variant. * si1133 UV sensor. - New driver * Spreadtrum SC27xx PMIC ADC - New driver and dt bindings. Features * adxl345 - Add calibration offset readback and writing. - Add sampling frequency control. Fixes and Cleanups * ad5933 - Use a macro for the channel definition to reduce duplication. * ad9523 - Replace use of core mlock with a local lock. Part of ongoing efforts to avoid confusing the purpose of mlock which is only about iio core state changes. - Fix displayed phase which was out by a factor of 10. * adxl345 - Add a link to the datasheet. - Rework the use of the address field in the chan_spec structures to allow addition of more per channel information. * adis imu - Mark switch fall throughs. * at91-sama5d2 - Fix some casting on big endian systems. * bmp280 - Drop some DT elements that aren't used and should mostly be done from userspace rather than in DT. * hx711 - add clock-frequency dt binding and resulting delay to deal with capacitance issue on some boards. - fix a spurious unit-address in the example. * ina2xx - Avoid a possible kthread_stop with a stale task_struct. * ltc2632 - Remove some unused local variables (assigned but value never used). * max1363 - Use device_get_match_data to remove some boilerplate. * mma8452 - Mark switch fall throughs. * sca3000 - Fix a missing return in a switch statement (a bad fallthrough previously!) * sigma-delta-modulator - Drop incorrect unit address from the DT example. * st_accel - Use device_get_match_data to drop some boiler plate. - Move to probe_new for i2c driver as second parameter not used. * st_sensors library - Use a strlcpy (safe in this case). * st_lsm6dsx - Add some error logging. * ti-ads7950 - SPDX - Allow simultaneous buffered and polled reads. Needed on a Lego Mindstorms EV3 where some channels are used for power supply monitoring at a very low rate. * ti-dac5571 - Remove an unused variable. * xadc - Drop some dead code.
This commit is contained in:
commit
3ceefa3ffd
54 changed files with 4139 additions and 175 deletions
|
@ -1307,13 +1307,16 @@ What: /sys/.../iio:deviceX/in_intensityY_raw
|
|||
What: /sys/.../iio:deviceX/in_intensityY_ir_raw
|
||||
What: /sys/.../iio:deviceX/in_intensityY_both_raw
|
||||
What: /sys/.../iio:deviceX/in_intensityY_uv_raw
|
||||
What: /sys/.../iio:deviceX/in_intensityY_duv_raw
|
||||
KernelVersion: 3.4
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Unit-less light intensity. Modifiers both and ir indicate
|
||||
that measurements contain visible and infrared light
|
||||
components or just infrared light, respectively. Modifier uv indicates
|
||||
that measurements contain ultraviolet light components.
|
||||
components or just infrared light, respectively. Modifier
|
||||
uv indicates that measurements contain ultraviolet light
|
||||
components. Modifier duv indicates that measurements
|
||||
contain deep ultraviolet light components.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_uvindex_input
|
||||
KernelVersion: 4.6
|
||||
|
@ -1675,3 +1678,10 @@ KernelVersion: 4.12
|
|||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Raw counter device counters direction for channel Y.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_phaseY_raw
|
||||
KernelVersion: 4.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Raw (unscaled) phase difference reading from channel Y
|
||||
that can be processed to radians.
|
47
Documentation/ABI/testing/sysfs-bus-iio-isl29501
Normal file
47
Documentation/ABI/testing/sysfs-bus-iio-isl29501
Normal file
|
@ -0,0 +1,47 @@
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_agc_gain
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_agc_gain_bias
|
||||
KernelVersion: 4.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This sensor has an automatic gain control (agc) loop
|
||||
which sets the analog signal levels at an optimum
|
||||
level by controlling programmable gain amplifiers. The
|
||||
criteria for optimal gain is determined by the sensor.
|
||||
|
||||
Return the actual gain value as an integer in [0; 65536]
|
||||
range when read from.
|
||||
|
||||
The agc gain read when measuring crosstalk shall be
|
||||
written into in_proximity0_agc_gain_bias.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_temp_a
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_temp_b
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_light_a
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_light_b
|
||||
KernelVersion: 4.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
The sensor is able to perform correction of distance
|
||||
measurements due to changing temperature and ambient
|
||||
light conditions. It can be programmed to correct for
|
||||
a second order error polynomial.
|
||||
|
||||
Phase data has to be collected when temperature and
|
||||
ambient light are modulated independently.
|
||||
|
||||
Then a least squares curve fit to a second order
|
||||
polynomial has to be generated from the data. The
|
||||
resultant curves have the form ax^2 + bx + c.
|
||||
|
||||
From those two curves, a and b coefficients shall be
|
||||
stored in in_proximity0_calib_phase_temp_a and
|
||||
in_proximity0_calib_phase_temp_b for temperature and
|
||||
in in_proximity0_calib_phase_light_a and
|
||||
in_proximity0_calib_phase_light_b for ambient light.
|
||||
|
||||
Those values must be integer in [0; 8355840] range.
|
||||
|
||||
Finally, the c constant is set by the sensor
|
||||
internally.
|
||||
|
||||
The value stored in sensor is displayed when read from.
|
22
Documentation/ABI/testing/sysfs-bus-iio-light-si1133
Normal file
22
Documentation/ABI/testing/sysfs-bus-iio-light-si1133
Normal file
|
@ -0,0 +1,22 @@
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ir_small_raw
|
||||
KernelVersion: 4.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Unit-less infrared intensity. The intensity is measured from 1
|
||||
dark photodiode. "small" indicate the surface area capturing
|
||||
infrared.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ir_large_raw
|
||||
KernelVersion: 4.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Unit-less infrared intensity. The intensity is measured from 4
|
||||
dark photodiodes. "large" indicate the surface area capturing
|
||||
infrared.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_large_raw
|
||||
KernelVersion: 4.18
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Unit-less light intensity with more diodes.
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
Analog Devices ADXL345 3-Axis, +/-(2g/4g/8g/16g) Digital Accelerometer
|
||||
Analog Devices ADXL345/ADXL375 3-Axis Digital Accelerometers
|
||||
|
||||
http://www.analog.com/en/products/mems/accelerometers/adxl345.html
|
||||
http://www.analog.com/en/products/sensors-mems/accelerometers/adxl375.html
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "adi,adxl345"
|
||||
- compatible : should be one of
|
||||
"adi,adxl345"
|
||||
"adi,adxl375"
|
||||
- reg : the I2C address or SPI chip select number of the sensor
|
||||
|
||||
Required properties for SPI bus usage:
|
||||
|
|
|
@ -4,6 +4,7 @@ Required properties:
|
|||
- compatible: depending on the SoC this should be one of:
|
||||
- "amlogic,meson8-saradc" for Meson8
|
||||
- "amlogic,meson8b-saradc" for Meson8b
|
||||
- "amlogic,meson8m2-saradc" for Meson8m2
|
||||
- "amlogic,meson-gxbb-saradc" for GXBB
|
||||
- "amlogic,meson-gxl-saradc" for GXL
|
||||
- "amlogic,meson-gxm-saradc" for GXM
|
||||
|
|
|
@ -8,11 +8,17 @@ Required properties:
|
|||
See Documentation/devicetree/bindings/gpio/gpio.txt
|
||||
- avdd-supply: Definition of the regulator used as analog supply
|
||||
|
||||
Optional properties:
|
||||
- clock-frequency: Frequency of PD_SCK in Hz
|
||||
Minimum value allowed is 10 kHz because of maximum
|
||||
high time of 50 microseconds.
|
||||
|
||||
Example:
|
||||
weight@0 {
|
||||
weight {
|
||||
compatible = "avia,hx711";
|
||||
sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>;
|
||||
dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
|
||||
avdd-suppy = <&avdd>;
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ Required properties:
|
|||
|
||||
Example node:
|
||||
|
||||
ads1202: adc@0 {
|
||||
ads1202: adc {
|
||||
compatible = "sd-modulator";
|
||||
#io-channel-cells = <0>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
Spreadtrum SC27XX series PMICs ADC binding
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following.
|
||||
"sprd,sc2720-adc"
|
||||
"sprd,sc2721-adc"
|
||||
"sprd,sc2723-adc"
|
||||
"sprd,sc2730-adc"
|
||||
"sprd,sc2731-adc"
|
||||
- reg: The address offset of ADC controller.
|
||||
- interrupt-parent: The interrupt controller.
|
||||
- interrupts: The interrupt number for the ADC device.
|
||||
- #io-channel-cells: Number of cells in an IIO specifier.
|
||||
- hwlocks: Reference to a phandle of a hwlock provider node.
|
||||
|
||||
Example:
|
||||
|
||||
sc2731_pmic: pmic@0 {
|
||||
compatible = "sprd,sc2731";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <26000000>;
|
||||
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pmic_adc: adc@480 {
|
||||
compatible = "sprd,sc2731-adc";
|
||||
reg = <0x480>;
|
||||
interrupt-parent = <&sc2731_pmic>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#io-channel-cells = <1>;
|
||||
hwlocks = <&hwlock 4>;
|
||||
};
|
||||
};
|
78
Documentation/devicetree/bindings/iio/dac/ad5758.txt
Normal file
78
Documentation/devicetree/bindings/iio/dac/ad5758.txt
Normal file
|
@ -0,0 +1,78 @@
|
|||
Analog Devices AD5758 DAC device driver
|
||||
|
||||
Required properties for the AD5758:
|
||||
- compatible: Must be "adi,ad5758"
|
||||
- reg: SPI chip select number for the device
|
||||
- spi-max-frequency: Max SPI frequency to use (< 50000000)
|
||||
- spi-cpha: is the only mode that is supported
|
||||
|
||||
Required properties:
|
||||
|
||||
- adi,dc-dc-mode: Mode of operation of the dc-to-dc converter
|
||||
Dynamic Power Control (DPC)
|
||||
In this mode, the AD5758 circuitry senses the output
|
||||
voltage and dynamically regulates the supply voltage,
|
||||
VDPC+, to meet compliance requirements plus an optimized
|
||||
headroom voltage for the output buffer.
|
||||
|
||||
Programmable Power Control (PPC)
|
||||
In this mode, the VDPC+ voltage is user-programmable to
|
||||
a fixed level that needs to accommodate the maximum output
|
||||
load required.
|
||||
|
||||
The output of the DAC core is either converted to a
|
||||
current or voltage output at the VIOUT pin. Only one mode
|
||||
can be enabled at any one time.
|
||||
|
||||
The following values are currently supported:
|
||||
* 1: DPC current mode
|
||||
* 2: DPC voltage mode
|
||||
* 3: PPC current mode
|
||||
|
||||
Depending on the selected output mode (voltage or current) one of the
|
||||
two properties must
|
||||
be present:
|
||||
|
||||
- adi,range-microvolt: Voltage output range
|
||||
The array of voltage output ranges must contain two fields:
|
||||
* <0 5000000>: 0 V to 5 V voltage range
|
||||
* <0 10000000>: 0 V to 10 V voltage range
|
||||
* <(-5000000) 5000000>: ±5 V voltage range
|
||||
* <(-10000000) 10000000>: ±10 V voltage range
|
||||
- adi,range-microamp: Current output range
|
||||
The array of current output ranges must contain two fields:
|
||||
* <0 20000>: 0 mA to 20 mA current range
|
||||
* <0 24000>: 0 mA to 24 mA current range
|
||||
* <4 24000>: 4 mA to 20 mA current range
|
||||
* <(-20000) 20000>: ±20 mA current range
|
||||
* <(-24000) 24000>: ±24 mA current range
|
||||
* <(-1000) 22000>: −1 mA to +22 mA current range
|
||||
|
||||
Optional properties:
|
||||
|
||||
- adi,dc-dc-ilim-microamp: The dc-to-dc converter current limit
|
||||
The following values are currently supported [uA]:
|
||||
* 150000
|
||||
* 200000
|
||||
* 250000
|
||||
* 300000
|
||||
* 350000
|
||||
* 400000
|
||||
|
||||
- adi,slew-time-us: The time it takes for the output to reach the
|
||||
full scale [uS]
|
||||
The supported range is between 133us up to 1023984375us
|
||||
|
||||
AD5758 Example:
|
||||
|
||||
dac@0 {
|
||||
compatible = "adi,ad5758";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
spi-cpha;
|
||||
|
||||
adi,dc-dc-mode = <2>;
|
||||
adi,range-microvolt = <0 10000000>;
|
||||
adi,dc-dc-ilim-microamp = <200000>;
|
||||
adi,slew-time-us = <125000>;
|
||||
};
|
|
@ -6,6 +6,7 @@ Required properties:
|
|||
- compatible : should be one of
|
||||
"invensense,mpu6050"
|
||||
"invensense,mpu6500"
|
||||
"invensense,mpu6515"
|
||||
"invensense,mpu9150"
|
||||
"invensense,mpu9250"
|
||||
"invensense,mpu9255"
|
||||
|
|
13
Documentation/devicetree/bindings/iio/light/isl29501.txt
Normal file
13
Documentation/devicetree/bindings/iio/light/isl29501.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
* ISL29501 Time-of-flight sensor.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "renesas,isl29501"
|
||||
- reg : the I2C address of the sensor
|
||||
|
||||
Example:
|
||||
|
||||
isl29501@57 {
|
||||
compatible = "renesas,isl29501";
|
||||
reg = <0x57>;
|
||||
};
|
|
@ -8,10 +8,6 @@ Required properties:
|
|||
"bosch,bme280"
|
||||
|
||||
Optional properties:
|
||||
- chip-id: configurable chip id for non-default chip revisions
|
||||
- temp-measurement-period: temperature measurement period (milliseconds)
|
||||
- default-oversampling: default oversampling value to be used at startup,
|
||||
value range is 0-3 with rising sensitivity.
|
||||
- interrupt-parent: should be the phandle for the interrupt controller
|
||||
- interrupts: interrupt mapping for IRQ
|
||||
- reset-gpios: a GPIO line handling reset of the sensor: as the line is
|
||||
|
@ -24,9 +20,6 @@ Example:
|
|||
pressure@77 {
|
||||
compatible = "bosch,bmp085";
|
||||
reg = <0x77>;
|
||||
chip-id = <10>;
|
||||
temp-measurement-period = <100>;
|
||||
default-oversampling = <2>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
|
||||
reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>;
|
||||
|
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 816 B |
|
@ -796,6 +796,14 @@ M: Michael Hanselmann <linux-kernel@hansmi.ch>
|
|||
S: Supported
|
||||
F: drivers/macintosh/ams/
|
||||
|
||||
ANALOG DEVICES INC AD5758 DRIVER
|
||||
M: Stefan Popa <stefan.popa@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
W: http://ez.analog.com/community/linux-device-drivers
|
||||
S: Supported
|
||||
F: drivers/iio/dac/ad5758.c
|
||||
F: Documentation/devicetree/bindings/iio/dac/ad5758.txt
|
||||
|
||||
ANALOG DEVICES INC AD5686 DRIVER
|
||||
M: Stefan Popa <stefan.popa@analog.com>
|
||||
L: linux-pm@vger.kernel.org
|
||||
|
|
|
@ -40,7 +40,7 @@ config ADXL345_I2C
|
|||
select REGMAP_I2C
|
||||
help
|
||||
Say Y here if you want to build support for the Analog Devices
|
||||
ADXL345 3-axis digital accelerometer.
|
||||
ADXL345 or ADXL375 3-axis digital accelerometer.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called adxl345_i2c and you will also get adxl345_core
|
||||
|
@ -54,7 +54,7 @@ config ADXL345_SPI
|
|||
select REGMAP_SPI
|
||||
help
|
||||
Say Y here if you want to build support for the Analog Devices
|
||||
ADXL345 3-axis digital accelerometer.
|
||||
ADXL345 or ADXL375 3-axis digital accelerometer.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called adxl345_spi and you will also get adxl345_core
|
||||
|
|
|
@ -11,8 +11,13 @@
|
|||
#ifndef _ADXL345_H_
|
||||
#define _ADXL345_H_
|
||||
|
||||
enum adxl345_device_type {
|
||||
ADXL345,
|
||||
ADXL375,
|
||||
};
|
||||
|
||||
int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
||||
const char *name);
|
||||
enum adxl345_device_type type, const char *name);
|
||||
int adxl345_core_remove(struct device *dev);
|
||||
|
||||
#endif /* _ADXL345_H_ */
|
||||
|
|
|
@ -6,21 +6,35 @@
|
|||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* Datasheet: http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#include "adxl345.h"
|
||||
|
||||
#define ADXL345_REG_DEVID 0x00
|
||||
#define ADXL345_REG_OFSX 0x1e
|
||||
#define ADXL345_REG_OFSY 0x1f
|
||||
#define ADXL345_REG_OFSZ 0x20
|
||||
#define ADXL345_REG_OFS_AXIS(index) (ADXL345_REG_OFSX + (index))
|
||||
#define ADXL345_REG_BW_RATE 0x2C
|
||||
#define ADXL345_REG_POWER_CTL 0x2D
|
||||
#define ADXL345_REG_DATA_FORMAT 0x31
|
||||
#define ADXL345_REG_DATAX0 0x32
|
||||
#define ADXL345_REG_DATAY0 0x34
|
||||
#define ADXL345_REG_DATAZ0 0x36
|
||||
#define ADXL345_REG_DATA_AXIS(index) \
|
||||
(ADXL345_REG_DATAX0 + (index) * sizeof(__le16))
|
||||
|
||||
#define ADXL345_BW_RATE GENMASK(3, 0)
|
||||
#define ADXL345_BASE_RATE_NANO_HZ 97656250LL
|
||||
#define NHZ_PER_HZ 1000000000LL
|
||||
|
||||
#define ADXL345_POWER_CTL_MEASURE BIT(3)
|
||||
#define ADXL345_POWER_CTL_STANDBY 0x00
|
||||
|
@ -42,24 +56,33 @@
|
|||
*/
|
||||
static const int adxl345_uscale = 38300;
|
||||
|
||||
/*
|
||||
* The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's
|
||||
* ~480mm/s**2 per LSB.
|
||||
*/
|
||||
static const int adxl375_uscale = 480000;
|
||||
|
||||
struct adxl345_data {
|
||||
struct regmap *regmap;
|
||||
u8 data_range;
|
||||
enum adxl345_device_type type;
|
||||
};
|
||||
|
||||
#define ADXL345_CHANNEL(reg, axis) { \
|
||||
#define ADXL345_CHANNEL(index, axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.address = reg, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.address = index, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec adxl345_channels[] = {
|
||||
ADXL345_CHANNEL(ADXL345_REG_DATAX0, X),
|
||||
ADXL345_CHANNEL(ADXL345_REG_DATAY0, Y),
|
||||
ADXL345_CHANNEL(ADXL345_REG_DATAZ0, Z),
|
||||
ADXL345_CHANNEL(0, X),
|
||||
ADXL345_CHANNEL(1, Y),
|
||||
ADXL345_CHANNEL(2, Z),
|
||||
};
|
||||
|
||||
static int adxl345_read_raw(struct iio_dev *indio_dev,
|
||||
|
@ -67,7 +90,9 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
|
|||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct adxl345_data *data = iio_priv(indio_dev);
|
||||
__le16 regval;
|
||||
__le16 accel;
|
||||
long long samp_freq_nhz;
|
||||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
|
@ -77,29 +102,117 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
|
|||
* ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte
|
||||
* and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte
|
||||
*/
|
||||
ret = regmap_bulk_read(data->regmap, chan->address, ®val,
|
||||
sizeof(regval));
|
||||
ret = regmap_bulk_read(data->regmap,
|
||||
ADXL345_REG_DATA_AXIS(chan->address),
|
||||
&accel, sizeof(accel));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = sign_extend32(le16_to_cpu(regval), 12);
|
||||
*val = sign_extend32(le16_to_cpu(accel), 12);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
*val2 = adxl345_uscale;
|
||||
switch (data->type) {
|
||||
case ADXL345:
|
||||
*val2 = adxl345_uscale;
|
||||
break;
|
||||
case ADXL375:
|
||||
*val2 = adxl375_uscale;
|
||||
break;
|
||||
}
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
ret = regmap_read(data->regmap,
|
||||
ADXL345_REG_OFS_AXIS(chan->address), ®val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/*
|
||||
* 8-bit resolution at +/- 2g, that is 4x accel data scale
|
||||
* factor
|
||||
*/
|
||||
*val = sign_extend32(regval, 7) * 4;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = regmap_read(data->regmap, ADXL345_REG_BW_RATE, ®val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
samp_freq_nhz = ADXL345_BASE_RATE_NANO_HZ <<
|
||||
(regval & ADXL345_BW_RATE);
|
||||
*val = div_s64_rem(samp_freq_nhz, NHZ_PER_HZ, val2);
|
||||
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adxl345_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct adxl345_data *data = iio_priv(indio_dev);
|
||||
s64 n;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
/*
|
||||
* 8-bit resolution at +/- 2g, that is 4x accel data scale
|
||||
* factor
|
||||
*/
|
||||
return regmap_write(data->regmap,
|
||||
ADXL345_REG_OFS_AXIS(chan->address),
|
||||
val / 4);
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
n = div_s64(val * NHZ_PER_HZ + val2, ADXL345_BASE_RATE_NANO_HZ);
|
||||
|
||||
return regmap_update_bits(data->regmap, ADXL345_REG_BW_RATE,
|
||||
ADXL345_BW_RATE,
|
||||
clamp_val(ilog2(n), 0,
|
||||
ADXL345_BW_RATE));
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
long mask)
|
||||
{
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
|
||||
"0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200"
|
||||
);
|
||||
|
||||
static struct attribute *adxl345_attrs[] = {
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group adxl345_attrs_group = {
|
||||
.attrs = adxl345_attrs,
|
||||
};
|
||||
|
||||
static const struct iio_info adxl345_info = {
|
||||
.attrs = &adxl345_attrs_group,
|
||||
.read_raw = adxl345_read_raw,
|
||||
.write_raw = adxl345_write_raw,
|
||||
.write_raw_get_fmt = adxl345_write_raw_get_fmt,
|
||||
};
|
||||
|
||||
int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
||||
const char *name)
|
||||
enum adxl345_device_type type, const char *name)
|
||||
{
|
||||
struct adxl345_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
|
@ -125,6 +238,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
|||
data = iio_priv(indio_dev);
|
||||
dev_set_drvdata(dev, indio_dev);
|
||||
data->regmap = regmap;
|
||||
data->type = type;
|
||||
/* Enable full-resolution mode */
|
||||
data->data_range = ADXL345_DATA_FORMAT_FULL_RES;
|
||||
|
||||
|
|
|
@ -34,7 +34,8 @@ static int adxl345_i2c_probe(struct i2c_client *client,
|
|||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return adxl345_core_probe(&client->dev, regmap, id ? id->name : NULL);
|
||||
return adxl345_core_probe(&client->dev, regmap, id->driver_data,
|
||||
id ? id->name : NULL);
|
||||
}
|
||||
|
||||
static int adxl345_i2c_remove(struct i2c_client *client)
|
||||
|
@ -43,7 +44,8 @@ static int adxl345_i2c_remove(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id adxl345_i2c_id[] = {
|
||||
{ "adxl345", 0 },
|
||||
{ "adxl345", ADXL345 },
|
||||
{ "adxl375", ADXL375 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -51,6 +53,7 @@ MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id);
|
|||
|
||||
static const struct of_device_id adxl345_of_match[] = {
|
||||
{ .compatible = "adi,adxl345" },
|
||||
{ .compatible = "adi,adxl375" },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ static int adxl345_spi_probe(struct spi_device *spi)
|
|||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return adxl345_core_probe(&spi->dev, regmap, id->name);
|
||||
return adxl345_core_probe(&spi->dev, regmap, id->driver_data, id->name);
|
||||
}
|
||||
|
||||
static int adxl345_spi_remove(struct spi_device *spi)
|
||||
|
@ -51,7 +51,8 @@ static int adxl345_spi_remove(struct spi_device *spi)
|
|||
}
|
||||
|
||||
static const struct spi_device_id adxl345_spi_id[] = {
|
||||
{ "adxl345", 0 },
|
||||
{ "adxl345", ADXL345 },
|
||||
{ "adxl375", ADXL375 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -59,6 +60,7 @@ MODULE_DEVICE_TABLE(spi, adxl345_spi_id);
|
|||
|
||||
static const struct of_device_id adxl345_of_match[] = {
|
||||
{ .compatible = "adi,adxl345" },
|
||||
{ .compatible = "adi,adxl375" },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
|
@ -1547,6 +1547,7 @@ static int mma8452_probe(struct i2c_client *client,
|
|||
case FXLS8471_DEVICE_ID:
|
||||
if (ret == data->chip_info->chip_id)
|
||||
break;
|
||||
/* else: fall through */
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -797,6 +797,7 @@ static int sca3000_write_raw(struct iio_dev *indio_dev,
|
|||
mutex_lock(&st->lock);
|
||||
ret = sca3000_write_3db_freq(st, val);
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
#include <linux/iio/common/st_sensors_i2c.h>
|
||||
#include "st_accel.h"
|
||||
|
||||
|
@ -107,8 +107,8 @@ MODULE_DEVICE_TABLE(of, st_accel_of_match);
|
|||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id st_accel_acpi_match[] = {
|
||||
{"SMO8840", LNG2DM},
|
||||
{"SMO8A90", LNG2DM},
|
||||
{"SMO8840", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
|
||||
{"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
|
||||
|
@ -117,33 +117,33 @@ MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
|
|||
#endif
|
||||
|
||||
static const struct i2c_device_id st_accel_id_table[] = {
|
||||
{ LSM303DLH_ACCEL_DEV_NAME, LSM303DLH },
|
||||
{ LSM303DLHC_ACCEL_DEV_NAME, LSM303DLHC },
|
||||
{ LIS3DH_ACCEL_DEV_NAME, LIS3DH },
|
||||
{ LSM330D_ACCEL_DEV_NAME, LSM330D },
|
||||
{ LSM330DL_ACCEL_DEV_NAME, LSM330DL },
|
||||
{ LSM330DLC_ACCEL_DEV_NAME, LSM330DLC },
|
||||
{ LIS331DLH_ACCEL_DEV_NAME, LIS331DLH },
|
||||
{ LSM303DL_ACCEL_DEV_NAME, LSM303DL },
|
||||
{ LSM303DLM_ACCEL_DEV_NAME, LSM303DLM },
|
||||
{ LSM330_ACCEL_DEV_NAME, LSM330 },
|
||||
{ LSM303AGR_ACCEL_DEV_NAME, LSM303AGR },
|
||||
{ LIS2DH12_ACCEL_DEV_NAME, LIS2DH12 },
|
||||
{ LIS3L02DQ_ACCEL_DEV_NAME, LIS3L02DQ },
|
||||
{ LNG2DM_ACCEL_DEV_NAME, LNG2DM },
|
||||
{ H3LIS331DL_ACCEL_DEV_NAME, H3LIS331DL },
|
||||
{ LIS331DL_ACCEL_DEV_NAME, LIS331DL },
|
||||
{ LIS3LV02DL_ACCEL_DEV_NAME, LIS3LV02DL },
|
||||
{ LIS2DW12_ACCEL_DEV_NAME, LIS2DW12 },
|
||||
{ LSM303DLH_ACCEL_DEV_NAME },
|
||||
{ LSM303DLHC_ACCEL_DEV_NAME },
|
||||
{ LIS3DH_ACCEL_DEV_NAME },
|
||||
{ LSM330D_ACCEL_DEV_NAME },
|
||||
{ LSM330DL_ACCEL_DEV_NAME },
|
||||
{ LSM330DLC_ACCEL_DEV_NAME },
|
||||
{ LIS331DLH_ACCEL_DEV_NAME },
|
||||
{ LSM303DL_ACCEL_DEV_NAME },
|
||||
{ LSM303DLM_ACCEL_DEV_NAME },
|
||||
{ LSM330_ACCEL_DEV_NAME },
|
||||
{ LSM303AGR_ACCEL_DEV_NAME },
|
||||
{ LIS2DH12_ACCEL_DEV_NAME },
|
||||
{ LIS3L02DQ_ACCEL_DEV_NAME },
|
||||
{ LNG2DM_ACCEL_DEV_NAME },
|
||||
{ H3LIS331DL_ACCEL_DEV_NAME },
|
||||
{ LIS331DL_ACCEL_DEV_NAME },
|
||||
{ LIS3LV02DL_ACCEL_DEV_NAME },
|
||||
{ LIS2DW12_ACCEL_DEV_NAME },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
|
||||
|
||||
static int st_accel_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static int st_accel_i2c_probe(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct st_sensor_data *adata;
|
||||
const char *match;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata));
|
||||
|
@ -152,19 +152,9 @@ static int st_accel_i2c_probe(struct i2c_client *client,
|
|||
|
||||
adata = iio_priv(indio_dev);
|
||||
|
||||
if (client->dev.of_node) {
|
||||
st_sensors_of_name_probe(&client->dev, st_accel_of_match,
|
||||
client->name, sizeof(client->name));
|
||||
} else if (ACPI_HANDLE(&client->dev)) {
|
||||
ret = st_sensors_match_acpi_device(&client->dev);
|
||||
if ((ret < 0) || (ret >= ST_ACCEL_MAX))
|
||||
return -ENODEV;
|
||||
|
||||
strlcpy(client->name, st_accel_id_table[ret].name,
|
||||
sizeof(client->name));
|
||||
} else if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
match = device_get_match_data(&client->dev);
|
||||
if (match)
|
||||
strlcpy(client->name, match, sizeof(client->name));
|
||||
|
||||
st_sensors_i2c_configure(indio_dev, client, adata);
|
||||
|
||||
|
@ -188,7 +178,7 @@ static struct i2c_driver st_accel_driver = {
|
|||
.of_match_table = of_match_ptr(st_accel_of_match),
|
||||
.acpi_match_table = ACPI_PTR(st_accel_acpi_match),
|
||||
},
|
||||
.probe = st_accel_i2c_probe,
|
||||
.probe_new = st_accel_i2c_probe,
|
||||
.remove = st_accel_i2c_remove,
|
||||
.id_table = st_accel_id_table,
|
||||
};
|
||||
|
|
|
@ -620,6 +620,16 @@ config ROCKCHIP_SARADC
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called rockchip_saradc.
|
||||
|
||||
config SC27XX_ADC
|
||||
tristate "Spreadtrum SC27xx series PMICs ADC"
|
||||
depends on MFD_SC27XX_PMIC || COMPILE_TEST
|
||||
help
|
||||
Say yes here to build support for the integrated ADC inside the
|
||||
Spreadtrum SC27xx series PMICs.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called sc27xx_adc.
|
||||
|
||||
config SPEAR_ADC
|
||||
tristate "ST SPEAr ADC"
|
||||
depends on PLAT_SPEAR || COMPILE_TEST
|
||||
|
|
|
@ -59,6 +59,7 @@ obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
|
|||
obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
|
||||
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
|
||||
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
|
||||
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
|
||||
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
|
||||
obj-$(CONFIG_STX104) += stx104.o
|
||||
obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o
|
||||
|
|
|
@ -1296,6 +1296,7 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
|
|||
{
|
||||
struct at91_adc_state *st = iio_priv(indio_dev);
|
||||
u32 cor = 0;
|
||||
u16 tmp_val;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
|
@ -1309,7 +1310,8 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
|
|||
mutex_lock(&st->lock);
|
||||
|
||||
ret = at91_adc_read_position(st, chan->channel,
|
||||
(u16 *)val);
|
||||
&tmp_val);
|
||||
*val = tmp_val;
|
||||
mutex_unlock(&st->lock);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
|
||||
|
@ -1322,7 +1324,8 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
|
|||
mutex_lock(&st->lock);
|
||||
|
||||
ret = at91_adc_read_pressure(st, chan->channel,
|
||||
(u16 *)val);
|
||||
&tmp_val);
|
||||
*val = tmp_val;
|
||||
mutex_unlock(&st->lock);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
|
||||
|
|
|
@ -97,6 +97,14 @@ struct hx711_data {
|
|||
* 2x32-bit channel + 64-bit timestamp
|
||||
*/
|
||||
u32 buffer[4];
|
||||
/*
|
||||
* delay after a rising edge on SCK until the data is ready DOUT
|
||||
* this is dependent on the hx711 where the datasheet tells a
|
||||
* maximum value of 100 ns
|
||||
* but also on potential parasitic capacities on the wiring
|
||||
*/
|
||||
u32 data_ready_delay_ns;
|
||||
u32 clock_frequency;
|
||||
};
|
||||
|
||||
static int hx711_cycle(struct hx711_data *hx711_data)
|
||||
|
@ -110,6 +118,14 @@ static int hx711_cycle(struct hx711_data *hx711_data)
|
|||
*/
|
||||
preempt_disable();
|
||||
gpiod_set_value(hx711_data->gpiod_pd_sck, 1);
|
||||
|
||||
/*
|
||||
* wait until DOUT is ready
|
||||
* it turned out that parasitic capacities are extending the time
|
||||
* until DOUT has reached it's value
|
||||
*/
|
||||
ndelay(hx711_data->data_ready_delay_ns);
|
||||
|
||||
val = gpiod_get_value(hx711_data->gpiod_dout);
|
||||
/*
|
||||
* here we are not waiting for 0.2 us as suggested by the datasheet,
|
||||
|
@ -120,6 +136,12 @@ static int hx711_cycle(struct hx711_data *hx711_data)
|
|||
gpiod_set_value(hx711_data->gpiod_pd_sck, 0);
|
||||
preempt_enable();
|
||||
|
||||
/*
|
||||
* make it a square wave for addressing cases with capacitance on
|
||||
* PC_SCK
|
||||
*/
|
||||
ndelay(hx711_data->data_ready_delay_ns);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
@ -458,6 +480,7 @@ static const struct iio_chan_spec hx711_chan_spec[] = {
|
|||
static int hx711_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct hx711_data *hx711_data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
@ -530,6 +553,22 @@ static int hx711_probe(struct platform_device *pdev)
|
|||
hx711_data->gain_set = 128;
|
||||
hx711_data->gain_chan_a = 128;
|
||||
|
||||
hx711_data->clock_frequency = 400000;
|
||||
ret = of_property_read_u32(np, "clock-frequency",
|
||||
&hx711_data->clock_frequency);
|
||||
|
||||
/*
|
||||
* datasheet says the high level of PD_SCK has a maximum duration
|
||||
* of 50 microseconds
|
||||
*/
|
||||
if (hx711_data->clock_frequency < 20000) {
|
||||
dev_warn(dev, "clock-frequency too low - assuming 400 kHz\n");
|
||||
hx711_data->clock_frequency = 400000;
|
||||
}
|
||||
|
||||
hx711_data->data_ready_delay_ns =
|
||||
1000000000 / hx711_data->clock_frequency;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
indio_dev->name = "hx711";
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sched/task.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
#include <linux/platform_data/ina2xx.h>
|
||||
|
@ -826,6 +827,7 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
|
|||
{
|
||||
struct ina2xx_chip_info *chip = iio_priv(indio_dev);
|
||||
unsigned int sampling_us = SAMPLING_PERIOD(chip);
|
||||
struct task_struct *task;
|
||||
|
||||
dev_dbg(&indio_dev->dev, "Enabling buffer w/ scan_mask %02x, freq = %d, avg =%u\n",
|
||||
(unsigned int)(*indio_dev->active_scan_mask),
|
||||
|
@ -835,11 +837,17 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
|
|||
dev_dbg(&indio_dev->dev, "Async readout mode: %d\n",
|
||||
chip->allow_async_readout);
|
||||
|
||||
chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev,
|
||||
"%s:%d-%uus", indio_dev->name, indio_dev->id,
|
||||
sampling_us);
|
||||
task = kthread_create(ina2xx_capture_thread, (void *)indio_dev,
|
||||
"%s:%d-%uus", indio_dev->name, indio_dev->id,
|
||||
sampling_us);
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
|
||||
return PTR_ERR_OR_ZERO(chip->task);
|
||||
get_task_struct(task);
|
||||
wake_up_process(task);
|
||||
chip->task = task;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ina2xx_buffer_disable(struct iio_dev *indio_dev)
|
||||
|
@ -848,6 +856,7 @@ static int ina2xx_buffer_disable(struct iio_dev *indio_dev)
|
|||
|
||||
if (chip->task) {
|
||||
kthread_stop(chip->task);
|
||||
put_task_struct(chip->task);
|
||||
chip->task = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -1577,7 +1577,6 @@ static int max1363_probe(struct i2c_client *client,
|
|||
struct max1363_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
struct regulator *vref;
|
||||
const struct of_device_id *match;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev,
|
||||
sizeof(struct max1363_state));
|
||||
|
@ -1604,11 +1603,8 @@ static int max1363_probe(struct i2c_client *client,
|
|||
/* this is only used for device removal purposes */
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
match = of_match_device(of_match_ptr(max1363_of_match),
|
||||
&client->dev);
|
||||
if (match)
|
||||
st->chip_info = of_device_get_match_data(&client->dev);
|
||||
else
|
||||
st->chip_info = of_device_get_match_data(&client->dev);
|
||||
if (!st->chip_info)
|
||||
st->chip_info = &max1363_chip_info_tbl[id->driver_data];
|
||||
st->client = client;
|
||||
|
||||
|
|
|
@ -922,6 +922,11 @@ static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = {
|
|||
.name = "meson-meson8b-saradc",
|
||||
};
|
||||
|
||||
static const struct meson_sar_adc_data meson_sar_adc_meson8m2_data = {
|
||||
.param = &meson_sar_adc_meson8_param,
|
||||
.name = "meson-meson8m2-saradc",
|
||||
};
|
||||
|
||||
static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = {
|
||||
.param = &meson_sar_adc_gxbb_param,
|
||||
.name = "meson-gxbb-saradc",
|
||||
|
@ -951,6 +956,10 @@ static const struct of_device_id meson_sar_adc_of_match[] = {
|
|||
.compatible = "amlogic,meson8b-saradc",
|
||||
.data = &meson_sar_adc_meson8b_data,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic,meson8m2-saradc",
|
||||
.data = &meson_sar_adc_meson8m2_data,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic,meson-gxbb-saradc",
|
||||
.data = &meson_sar_adc_gxbb_data,
|
||||
|
|
522
drivers/iio/adc/sc27xx_adc.c
Normal file
522
drivers/iio/adc/sc27xx_adc.c
Normal file
|
@ -0,0 +1,522 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2018 Spreadtrum Communications Inc.
|
||||
|
||||
#include <linux/hwspinlock.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* PMIC global registers definition */
|
||||
#define SC27XX_MODULE_EN 0xc08
|
||||
#define SC27XX_MODULE_ADC_EN BIT(5)
|
||||
#define SC27XX_ARM_CLK_EN 0xc10
|
||||
#define SC27XX_CLK_ADC_EN BIT(5)
|
||||
#define SC27XX_CLK_ADC_CLK_EN BIT(6)
|
||||
|
||||
/* ADC controller registers definition */
|
||||
#define SC27XX_ADC_CTL 0x0
|
||||
#define SC27XX_ADC_CH_CFG 0x4
|
||||
#define SC27XX_ADC_DATA 0x4c
|
||||
#define SC27XX_ADC_INT_EN 0x50
|
||||
#define SC27XX_ADC_INT_CLR 0x54
|
||||
#define SC27XX_ADC_INT_STS 0x58
|
||||
#define SC27XX_ADC_INT_RAW 0x5c
|
||||
|
||||
/* Bits and mask definition for SC27XX_ADC_CTL register */
|
||||
#define SC27XX_ADC_EN BIT(0)
|
||||
#define SC27XX_ADC_CHN_RUN BIT(1)
|
||||
#define SC27XX_ADC_12BIT_MODE BIT(2)
|
||||
#define SC27XX_ADC_RUN_NUM_MASK GENMASK(7, 4)
|
||||
#define SC27XX_ADC_RUN_NUM_SHIFT 4
|
||||
|
||||
/* Bits and mask definition for SC27XX_ADC_CH_CFG register */
|
||||
#define SC27XX_ADC_CHN_ID_MASK GENMASK(4, 0)
|
||||
#define SC27XX_ADC_SCALE_MASK GENMASK(10, 8)
|
||||
#define SC27XX_ADC_SCALE_SHIFT 8
|
||||
|
||||
/* Bits definitions for SC27XX_ADC_INT_EN registers */
|
||||
#define SC27XX_ADC_IRQ_EN BIT(0)
|
||||
|
||||
/* Bits definitions for SC27XX_ADC_INT_CLR registers */
|
||||
#define SC27XX_ADC_IRQ_CLR BIT(0)
|
||||
|
||||
/* Mask definition for SC27XX_ADC_DATA register */
|
||||
#define SC27XX_ADC_DATA_MASK GENMASK(11, 0)
|
||||
|
||||
/* Timeout (ms) for the trylock of hardware spinlocks */
|
||||
#define SC27XX_ADC_HWLOCK_TIMEOUT 5000
|
||||
|
||||
/* Maximum ADC channel number */
|
||||
#define SC27XX_ADC_CHANNEL_MAX 32
|
||||
|
||||
/* ADC voltage ratio definition */
|
||||
#define SC27XX_VOLT_RATIO(n, d) \
|
||||
(((n) << SC27XX_RATIO_NUMERATOR_OFFSET) | (d))
|
||||
#define SC27XX_RATIO_NUMERATOR_OFFSET 16
|
||||
#define SC27XX_RATIO_DENOMINATOR_MASK GENMASK(15, 0)
|
||||
|
||||
struct sc27xx_adc_data {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
/*
|
||||
* One hardware spinlock to synchronize between the multiple
|
||||
* subsystems which will access the unique ADC controller.
|
||||
*/
|
||||
struct hwspinlock *hwlock;
|
||||
struct completion completion;
|
||||
int channel_scale[SC27XX_ADC_CHANNEL_MAX];
|
||||
u32 base;
|
||||
int value;
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct sc27xx_adc_linear_graph {
|
||||
int volt0;
|
||||
int adc0;
|
||||
int volt1;
|
||||
int adc1;
|
||||
};
|
||||
|
||||
/*
|
||||
* According to the datasheet, we can convert one ADC value to one voltage value
|
||||
* through 2 points in the linear graph. If the voltage is less than 1.2v, we
|
||||
* should use the small-scale graph, and if more than 1.2v, we should use the
|
||||
* big-scale graph.
|
||||
*/
|
||||
static const struct sc27xx_adc_linear_graph big_scale_graph = {
|
||||
4200, 3310,
|
||||
3600, 2832,
|
||||
};
|
||||
|
||||
static const struct sc27xx_adc_linear_graph small_scale_graph = {
|
||||
1000, 3413,
|
||||
100, 341,
|
||||
};
|
||||
|
||||
static int sc27xx_adc_get_ratio(int channel, int scale)
|
||||
{
|
||||
switch (channel) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
return scale ? SC27XX_VOLT_RATIO(400, 1025) :
|
||||
SC27XX_VOLT_RATIO(1, 1);
|
||||
case 5:
|
||||
return SC27XX_VOLT_RATIO(7, 29);
|
||||
case 6:
|
||||
return SC27XX_VOLT_RATIO(375, 9000);
|
||||
case 7:
|
||||
case 8:
|
||||
return scale ? SC27XX_VOLT_RATIO(100, 125) :
|
||||
SC27XX_VOLT_RATIO(1, 1);
|
||||
case 19:
|
||||
return SC27XX_VOLT_RATIO(1, 3);
|
||||
default:
|
||||
return SC27XX_VOLT_RATIO(1, 1);
|
||||
}
|
||||
return SC27XX_VOLT_RATIO(1, 1);
|
||||
}
|
||||
|
||||
static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
|
||||
int scale, int *val)
|
||||
{
|
||||
int ret;
|
||||
u32 tmp;
|
||||
|
||||
reinit_completion(&data->completion);
|
||||
|
||||
ret = hwspin_lock_timeout_raw(data->hwlock, SC27XX_ADC_HWLOCK_TIMEOUT);
|
||||
if (ret) {
|
||||
dev_err(data->dev, "timeout to get the hwspinlock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
|
||||
SC27XX_ADC_EN, SC27XX_ADC_EN);
|
||||
if (ret)
|
||||
goto unlock_adc;
|
||||
|
||||
/* Configure the channel id and scale */
|
||||
tmp = (scale << SC27XX_ADC_SCALE_SHIFT) & SC27XX_ADC_SCALE_MASK;
|
||||
tmp |= channel & SC27XX_ADC_CHN_ID_MASK;
|
||||
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CH_CFG,
|
||||
SC27XX_ADC_CHN_ID_MASK | SC27XX_ADC_SCALE_MASK,
|
||||
tmp);
|
||||
if (ret)
|
||||
goto disable_adc;
|
||||
|
||||
/* Select 12bit conversion mode, and only sample 1 time */
|
||||
tmp = SC27XX_ADC_12BIT_MODE;
|
||||
tmp |= (0 << SC27XX_ADC_RUN_NUM_SHIFT) & SC27XX_ADC_RUN_NUM_MASK;
|
||||
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
|
||||
SC27XX_ADC_RUN_NUM_MASK | SC27XX_ADC_12BIT_MODE,
|
||||
tmp);
|
||||
if (ret)
|
||||
goto disable_adc;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
|
||||
SC27XX_ADC_CHN_RUN, SC27XX_ADC_CHN_RUN);
|
||||
if (ret)
|
||||
goto disable_adc;
|
||||
|
||||
wait_for_completion(&data->completion);
|
||||
|
||||
disable_adc:
|
||||
regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
|
||||
SC27XX_ADC_EN, 0);
|
||||
unlock_adc:
|
||||
hwspin_unlock_raw(data->hwlock);
|
||||
|
||||
if (!ret)
|
||||
*val = data->value;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t sc27xx_adc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct sc27xx_adc_data *data = dev_id;
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR,
|
||||
SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR);
|
||||
if (ret)
|
||||
return IRQ_RETVAL(ret);
|
||||
|
||||
ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA,
|
||||
&data->value);
|
||||
if (ret)
|
||||
return IRQ_RETVAL(ret);
|
||||
|
||||
data->value &= SC27XX_ADC_DATA_MASK;
|
||||
complete(&data->completion);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void sc27xx_adc_volt_ratio(struct sc27xx_adc_data *data,
|
||||
int channel, int scale,
|
||||
u32 *div_numerator, u32 *div_denominator)
|
||||
{
|
||||
u32 ratio = sc27xx_adc_get_ratio(channel, scale);
|
||||
|
||||
*div_numerator = ratio >> SC27XX_RATIO_NUMERATOR_OFFSET;
|
||||
*div_denominator = ratio & SC27XX_RATIO_DENOMINATOR_MASK;
|
||||
}
|
||||
|
||||
static int sc27xx_adc_to_volt(const struct sc27xx_adc_linear_graph *graph,
|
||||
int raw_adc)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
tmp = (graph->volt0 - graph->volt1) * (raw_adc - graph->adc1);
|
||||
tmp /= (graph->adc0 - graph->adc1);
|
||||
tmp += graph->volt1;
|
||||
|
||||
return tmp < 0 ? 0 : tmp;
|
||||
}
|
||||
|
||||
static int sc27xx_adc_convert_volt(struct sc27xx_adc_data *data, int channel,
|
||||
int scale, int raw_adc)
|
||||
{
|
||||
u32 numerator, denominator;
|
||||
u32 volt;
|
||||
|
||||
/*
|
||||
* Convert ADC values to voltage values according to the linear graph,
|
||||
* and channel 5 and channel 1 has been calibrated, so we can just
|
||||
* return the voltage values calculated by the linear graph. But other
|
||||
* channels need be calculated to the real voltage values with the
|
||||
* voltage ratio.
|
||||
*/
|
||||
switch (channel) {
|
||||
case 5:
|
||||
return sc27xx_adc_to_volt(&big_scale_graph, raw_adc);
|
||||
|
||||
case 1:
|
||||
return sc27xx_adc_to_volt(&small_scale_graph, raw_adc);
|
||||
|
||||
default:
|
||||
volt = sc27xx_adc_to_volt(&small_scale_graph, raw_adc);
|
||||
break;
|
||||
}
|
||||
|
||||
sc27xx_adc_volt_ratio(data, channel, scale, &numerator, &denominator);
|
||||
|
||||
return (volt * denominator + numerator / 2) / numerator;
|
||||
}
|
||||
|
||||
static int sc27xx_adc_read_processed(struct sc27xx_adc_data *data,
|
||||
int channel, int scale, int *val)
|
||||
{
|
||||
int ret, raw_adc;
|
||||
|
||||
ret = sc27xx_adc_read(data, channel, scale, &raw_adc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = sc27xx_adc_convert_volt(data, channel, scale, raw_adc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sc27xx_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct sc27xx_adc_data *data = iio_priv(indio_dev);
|
||||
int scale = data->channel_scale[chan->channel];
|
||||
int ret, tmp;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = sc27xx_adc_read_processed(data, chan->channel, scale,
|
||||
&tmp);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = tmp;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = scale;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int sc27xx_adc_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct sc27xx_adc_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
data->channel_scale[chan->channel] = val;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info sc27xx_info = {
|
||||
.read_raw = &sc27xx_adc_read_raw,
|
||||
.write_raw = &sc27xx_adc_write_raw,
|
||||
};
|
||||
|
||||
#define SC27XX_ADC_CHANNEL(index) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.channel = index, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.datasheet_name = "CH##index", \
|
||||
.indexed = 1, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec sc27xx_channels[] = {
|
||||
SC27XX_ADC_CHANNEL(0),
|
||||
SC27XX_ADC_CHANNEL(1),
|
||||
SC27XX_ADC_CHANNEL(2),
|
||||
SC27XX_ADC_CHANNEL(3),
|
||||
SC27XX_ADC_CHANNEL(4),
|
||||
SC27XX_ADC_CHANNEL(5),
|
||||
SC27XX_ADC_CHANNEL(6),
|
||||
SC27XX_ADC_CHANNEL(7),
|
||||
SC27XX_ADC_CHANNEL(8),
|
||||
SC27XX_ADC_CHANNEL(9),
|
||||
SC27XX_ADC_CHANNEL(10),
|
||||
SC27XX_ADC_CHANNEL(11),
|
||||
SC27XX_ADC_CHANNEL(12),
|
||||
SC27XX_ADC_CHANNEL(13),
|
||||
SC27XX_ADC_CHANNEL(14),
|
||||
SC27XX_ADC_CHANNEL(15),
|
||||
SC27XX_ADC_CHANNEL(16),
|
||||
SC27XX_ADC_CHANNEL(17),
|
||||
SC27XX_ADC_CHANNEL(18),
|
||||
SC27XX_ADC_CHANNEL(19),
|
||||
SC27XX_ADC_CHANNEL(20),
|
||||
SC27XX_ADC_CHANNEL(21),
|
||||
SC27XX_ADC_CHANNEL(22),
|
||||
SC27XX_ADC_CHANNEL(23),
|
||||
SC27XX_ADC_CHANNEL(24),
|
||||
SC27XX_ADC_CHANNEL(25),
|
||||
SC27XX_ADC_CHANNEL(26),
|
||||
SC27XX_ADC_CHANNEL(27),
|
||||
SC27XX_ADC_CHANNEL(28),
|
||||
SC27XX_ADC_CHANNEL(29),
|
||||
SC27XX_ADC_CHANNEL(30),
|
||||
SC27XX_ADC_CHANNEL(31),
|
||||
};
|
||||
|
||||
static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, SC27XX_MODULE_EN,
|
||||
SC27XX_MODULE_ADC_EN, SC27XX_MODULE_ADC_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable ADC work clock and controller clock */
|
||||
ret = regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN,
|
||||
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN,
|
||||
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN);
|
||||
if (ret)
|
||||
goto disable_adc;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN,
|
||||
SC27XX_ADC_IRQ_EN, SC27XX_ADC_IRQ_EN);
|
||||
if (ret)
|
||||
goto disable_clk;
|
||||
|
||||
return 0;
|
||||
|
||||
disable_clk:
|
||||
regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN,
|
||||
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0);
|
||||
disable_adc:
|
||||
regmap_update_bits(data->regmap, SC27XX_MODULE_EN,
|
||||
SC27XX_MODULE_ADC_EN, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sc27xx_adc_disable(void *_data)
|
||||
{
|
||||
struct sc27xx_adc_data *data = _data;
|
||||
|
||||
regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN,
|
||||
SC27XX_ADC_IRQ_EN, 0);
|
||||
|
||||
/* Disable ADC work clock and controller clock */
|
||||
regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN,
|
||||
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0);
|
||||
|
||||
regmap_update_bits(data->regmap, SC27XX_MODULE_EN,
|
||||
SC27XX_MODULE_ADC_EN, 0);
|
||||
}
|
||||
|
||||
static void sc27xx_adc_free_hwlock(void *_data)
|
||||
{
|
||||
struct hwspinlock *hwlock = _data;
|
||||
|
||||
hwspin_lock_free(hwlock);
|
||||
}
|
||||
|
||||
static int sc27xx_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct sc27xx_adc_data *sc27xx_data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*sc27xx_data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
sc27xx_data = iio_priv(indio_dev);
|
||||
|
||||
sc27xx_data->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!sc27xx_data->regmap) {
|
||||
dev_err(&pdev->dev, "failed to get ADC regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "reg", &sc27xx_data->base);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to get ADC base address\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
sc27xx_data->irq = platform_get_irq(pdev, 0);
|
||||
if (sc27xx_data->irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get ADC irq number\n");
|
||||
return sc27xx_data->irq;
|
||||
}
|
||||
|
||||
ret = of_hwspin_lock_get_id(np, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get hwspinlock id\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
sc27xx_data->hwlock = hwspin_lock_request_specific(ret);
|
||||
if (!sc27xx_data->hwlock) {
|
||||
dev_err(&pdev->dev, "failed to request hwspinlock\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = devm_add_action(&pdev->dev, sc27xx_adc_free_hwlock,
|
||||
sc27xx_data->hwlock);
|
||||
if (ret) {
|
||||
sc27xx_adc_free_hwlock(sc27xx_data->hwlock);
|
||||
dev_err(&pdev->dev, "failed to add hwspinlock action\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
init_completion(&sc27xx_data->completion);
|
||||
sc27xx_data->dev = &pdev->dev;
|
||||
|
||||
ret = sc27xx_adc_enable(sc27xx_data);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable ADC module\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action(&pdev->dev, sc27xx_adc_disable, sc27xx_data);
|
||||
if (ret) {
|
||||
sc27xx_adc_disable(sc27xx_data);
|
||||
dev_err(&pdev->dev, "failed to add ADC disable action\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, sc27xx_data->irq, NULL,
|
||||
sc27xx_adc_isr, IRQF_ONESHOT,
|
||||
pdev->name, sc27xx_data);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request ADC irq\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->name = dev_name(&pdev->dev);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &sc27xx_info;
|
||||
indio_dev->channels = sc27xx_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(sc27xx_channels);
|
||||
ret = devm_iio_device_register(&pdev->dev, indio_dev);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "could not register iio (ADC)");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id sc27xx_adc_of_match[] = {
|
||||
{ .compatible = "sprd,sc2731-adc", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver sc27xx_adc_driver = {
|
||||
.probe = sc27xx_adc_probe,
|
||||
.driver = {
|
||||
.name = "sc27xx-adc",
|
||||
.of_match_table = sc27xx_adc_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(sc27xx_adc_driver);
|
||||
|
||||
MODULE_AUTHOR("Freeman Liu <freeman.liu@spreadtrum.com>");
|
||||
MODULE_DESCRIPTION("Spreadtrum SC27XX ADC Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Texas Instruments ADS7950 SPI ADC driver
|
||||
*
|
||||
|
@ -10,15 +11,6 @@
|
|||
* And also on hwmon/ads79xx.c
|
||||
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Nishanth Menon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
|
@ -76,6 +68,9 @@ struct ti_ads7950_state {
|
|||
__be16 rx_buf[TI_ADS7950_MAX_CHAN + TI_ADS7950_TIMESTAMP_SIZE]
|
||||
____cacheline_aligned;
|
||||
__be16 tx_buf[TI_ADS7950_MAX_CHAN];
|
||||
__be16 single_tx;
|
||||
__be16 single_rx;
|
||||
|
||||
};
|
||||
|
||||
struct ti_ads7950_chip_info {
|
||||
|
@ -295,18 +290,26 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ti_ads7950_scan_direct(struct ti_ads7950_state *st, unsigned int ch)
|
||||
static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
|
||||
{
|
||||
struct ti_ads7950_state *st = iio_priv(indio_dev);
|
||||
int ret, cmd;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
|
||||
cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings;
|
||||
st->tx_buf[0] = cpu_to_be16(cmd);
|
||||
st->single_tx = cpu_to_be16(cmd);
|
||||
|
||||
ret = spi_sync(st->spi, &st->scan_single_msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
return be16_to_cpu(st->rx_buf[0]);
|
||||
ret = be16_to_cpu(st->single_rx);
|
||||
|
||||
out:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_ads7950_get_range(struct ti_ads7950_state *st)
|
||||
|
@ -338,13 +341,7 @@ static int ti_ads7950_read_raw(struct iio_dev *indio_dev,
|
|||
|
||||
switch (m) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ti_ads7950_scan_direct(st, chan->address);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
ret = ti_ads7950_scan_direct(indio_dev, chan->address);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -410,13 +407,13 @@ static int ti_ads7950_probe(struct spi_device *spi)
|
|||
* was read at the end of the first transfer.
|
||||
*/
|
||||
|
||||
st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
|
||||
st->scan_single_xfer[0].tx_buf = &st->single_tx;
|
||||
st->scan_single_xfer[0].len = 2;
|
||||
st->scan_single_xfer[0].cs_change = 1;
|
||||
st->scan_single_xfer[1].tx_buf = &st->tx_buf[0];
|
||||
st->scan_single_xfer[1].tx_buf = &st->single_tx;
|
||||
st->scan_single_xfer[1].len = 2;
|
||||
st->scan_single_xfer[1].cs_change = 1;
|
||||
st->scan_single_xfer[2].rx_buf = &st->rx_buf[0];
|
||||
st->scan_single_xfer[2].rx_buf = &st->single_rx;
|
||||
st->scan_single_xfer[2].len = 2;
|
||||
|
||||
spi_message_init_with_transfers(&st->scan_single_msg,
|
||||
|
|
|
@ -341,8 +341,6 @@ static int xadc_zynq_setup(struct platform_device *pdev,
|
|||
|
||||
pcap_rate = clk_get_rate(xadc->clk);
|
||||
|
||||
if (tck_rate > XADC_ZYNQ_TCK_RATE_MAX)
|
||||
tck_rate = XADC_ZYNQ_TCK_RATE_MAX;
|
||||
if (tck_rate > pcap_rate / 2) {
|
||||
div = 2;
|
||||
} else {
|
||||
|
@ -1045,7 +1043,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
|
|||
unsigned int num_channels;
|
||||
const char *external_mux;
|
||||
u32 ext_mux_chan;
|
||||
int reg;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
*conf = 0;
|
||||
|
|
|
@ -380,8 +380,7 @@ void st_sensors_of_name_probe(struct device *dev,
|
|||
return;
|
||||
|
||||
/* The name from the OF match takes precedence if present */
|
||||
strncpy(name, of_id->data, len);
|
||||
name[len - 1] = '\0';
|
||||
strlcpy(name, of_id->data, len);
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_of_name_probe);
|
||||
#else
|
||||
|
|
|
@ -167,6 +167,16 @@ config AD5755
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad5755.
|
||||
|
||||
config AD5758
|
||||
tristate "Analog Devices AD5758 DAC driver"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD5758 single channel
|
||||
Digital to Analog Converter.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad5758.
|
||||
|
||||
config AD5761
|
||||
tristate "Analog Devices AD5761/61R/21/21R DAC driver"
|
||||
depends on SPI_MASTER
|
||||
|
|
|
@ -16,6 +16,7 @@ obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o
|
|||
obj-$(CONFIG_AD5592R) += ad5592r.o
|
||||
obj-$(CONFIG_AD5593R) += ad5593r.o
|
||||
obj-$(CONFIG_AD5755) += ad5755.o
|
||||
obj-$(CONFIG_AD5755) += ad5758.o
|
||||
obj-$(CONFIG_AD5761) += ad5761.o
|
||||
obj-$(CONFIG_AD5764) += ad5764.o
|
||||
obj-$(CONFIG_AD5791) += ad5791.o
|
||||
|
|
897
drivers/iio/dac/ad5758.c
Normal file
897
drivers/iio/dac/ad5758.c
Normal file
|
@ -0,0 +1,897 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* AD5758 Digital to analog converters driver
|
||||
*
|
||||
* Copyright 2018 Analog Devices Inc.
|
||||
*
|
||||
* TODO: Currently CRC is not supported in this driver
|
||||
*/
|
||||
#include <linux/bsearch.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
/* AD5758 registers definition */
|
||||
#define AD5758_NOP 0x00
|
||||
#define AD5758_DAC_INPUT 0x01
|
||||
#define AD5758_DAC_OUTPUT 0x02
|
||||
#define AD5758_CLEAR_CODE 0x03
|
||||
#define AD5758_USER_GAIN 0x04
|
||||
#define AD5758_USER_OFFSET 0x05
|
||||
#define AD5758_DAC_CONFIG 0x06
|
||||
#define AD5758_SW_LDAC 0x07
|
||||
#define AD5758_KEY 0x08
|
||||
#define AD5758_GP_CONFIG1 0x09
|
||||
#define AD5758_GP_CONFIG2 0x0A
|
||||
#define AD5758_DCDC_CONFIG1 0x0B
|
||||
#define AD5758_DCDC_CONFIG2 0x0C
|
||||
#define AD5758_WDT_CONFIG 0x0F
|
||||
#define AD5758_DIGITAL_DIAG_CONFIG 0x10
|
||||
#define AD5758_ADC_CONFIG 0x11
|
||||
#define AD5758_FAULT_PIN_CONFIG 0x12
|
||||
#define AD5758_TWO_STAGE_READBACK_SELECT 0x13
|
||||
#define AD5758_DIGITAL_DIAG_RESULTS 0x14
|
||||
#define AD5758_ANALOG_DIAG_RESULTS 0x15
|
||||
#define AD5758_STATUS 0x16
|
||||
#define AD5758_CHIP_ID 0x17
|
||||
#define AD5758_FREQ_MONITOR 0x18
|
||||
#define AD5758_DEVICE_ID_0 0x19
|
||||
#define AD5758_DEVICE_ID_1 0x1A
|
||||
#define AD5758_DEVICE_ID_2 0x1B
|
||||
#define AD5758_DEVICE_ID_3 0x1C
|
||||
|
||||
/* AD5758_DAC_CONFIG */
|
||||
#define AD5758_DAC_CONFIG_RANGE_MSK GENMASK(3, 0)
|
||||
#define AD5758_DAC_CONFIG_RANGE_MODE(x) (((x) & 0xF) << 0)
|
||||
#define AD5758_DAC_CONFIG_INT_EN_MSK BIT(5)
|
||||
#define AD5758_DAC_CONFIG_INT_EN_MODE(x) (((x) & 0x1) << 5)
|
||||
#define AD5758_DAC_CONFIG_OUT_EN_MSK BIT(6)
|
||||
#define AD5758_DAC_CONFIG_OUT_EN_MODE(x) (((x) & 0x1) << 6)
|
||||
#define AD5758_DAC_CONFIG_SR_EN_MSK BIT(8)
|
||||
#define AD5758_DAC_CONFIG_SR_EN_MODE(x) (((x) & 0x1) << 8)
|
||||
#define AD5758_DAC_CONFIG_SR_CLOCK_MSK GENMASK(12, 9)
|
||||
#define AD5758_DAC_CONFIG_SR_CLOCK_MODE(x) (((x) & 0xF) << 9)
|
||||
#define AD5758_DAC_CONFIG_SR_STEP_MSK GENMASK(15, 13)
|
||||
#define AD5758_DAC_CONFIG_SR_STEP_MODE(x) (((x) & 0x7) << 13)
|
||||
|
||||
/* AD5758_KEY */
|
||||
#define AD5758_KEY_CODE_RESET_1 0x15FA
|
||||
#define AD5758_KEY_CODE_RESET_2 0xAF51
|
||||
#define AD5758_KEY_CODE_SINGLE_ADC_CONV 0x1ADC
|
||||
#define AD5758_KEY_CODE_RESET_WDT 0x0D06
|
||||
#define AD5758_KEY_CODE_CALIB_MEM_REFRESH 0xFCBA
|
||||
|
||||
/* AD5758_DCDC_CONFIG1 */
|
||||
#define AD5758_DCDC_CONFIG1_DCDC_VPROG_MSK GENMASK(4, 0)
|
||||
#define AD5758_DCDC_CONFIG1_DCDC_VPROG_MODE(x) (((x) & 0x1F) << 0)
|
||||
#define AD5758_DCDC_CONFIG1_DCDC_MODE_MSK GENMASK(6, 5)
|
||||
#define AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(x) (((x) & 0x3) << 5)
|
||||
#define AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK BIT(7)
|
||||
#define AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(x) (((x) & 0x1) << 7)
|
||||
|
||||
/* AD5758_DCDC_CONFIG2 */
|
||||
#define AD5758_DCDC_CONFIG2_ILIMIT_MSK GENMASK(3, 1)
|
||||
#define AD5758_DCDC_CONFIG2_ILIMIT_MODE(x) (((x) & 0x7) << 1)
|
||||
#define AD5758_DCDC_CONFIG2_INTR_SAT_3WI_MSK BIT(11)
|
||||
#define AD5758_DCDC_CONFIG2_BUSY_3WI_MSK BIT(12)
|
||||
|
||||
/* AD5758_DIGITAL_DIAG_RESULTS */
|
||||
#define AD5758_CAL_MEM_UNREFRESHED_MSK BIT(15)
|
||||
|
||||
#define AD5758_WR_FLAG_MSK(x) (0x80 | ((x) & 0x1F))
|
||||
|
||||
#define AD5758_FULL_SCALE_MICRO 65535000000ULL
|
||||
|
||||
/**
|
||||
* struct ad5758_state - driver instance specific data
|
||||
* @spi: spi_device
|
||||
* @lock: mutex lock
|
||||
* @out_range: struct which stores the output range
|
||||
* @dc_dc_mode: variable which stores the mode of operation
|
||||
* @dc_dc_ilim: variable which stores the dc-to-dc converter current limit
|
||||
* @slew_time: variable which stores the target slew time
|
||||
* @pwr_down: variable which contains whether a channel is powered down or not
|
||||
* @data: spi transfer buffers
|
||||
*/
|
||||
|
||||
struct ad5758_range {
|
||||
int reg;
|
||||
int min;
|
||||
int max;
|
||||
};
|
||||
|
||||
struct ad5758_state {
|
||||
struct spi_device *spi;
|
||||
struct mutex lock;
|
||||
struct ad5758_range out_range;
|
||||
unsigned int dc_dc_mode;
|
||||
unsigned int dc_dc_ilim;
|
||||
unsigned int slew_time;
|
||||
bool pwr_down;
|
||||
__be32 d32[3];
|
||||
};
|
||||
|
||||
/**
|
||||
* Output ranges corresponding to bits [3:0] from DAC_CONFIG register
|
||||
* 0000: 0 V to 5 V voltage range
|
||||
* 0001: 0 V to 10 V voltage range
|
||||
* 0010: ±5 V voltage range
|
||||
* 0011: ±10 V voltage range
|
||||
* 1000: 0 mA to 20 mA current range
|
||||
* 1001: 0 mA to 24 mA current range
|
||||
* 1010: 4 mA to 20 mA current range
|
||||
* 1011: ±20 mA current range
|
||||
* 1100: ±24 mA current range
|
||||
* 1101: -1 mA to +22 mA current range
|
||||
*/
|
||||
enum ad5758_output_range {
|
||||
AD5758_RANGE_0V_5V,
|
||||
AD5758_RANGE_0V_10V,
|
||||
AD5758_RANGE_PLUSMINUS_5V,
|
||||
AD5758_RANGE_PLUSMINUS_10V,
|
||||
AD5758_RANGE_0mA_20mA = 8,
|
||||
AD5758_RANGE_0mA_24mA,
|
||||
AD5758_RANGE_4mA_24mA,
|
||||
AD5758_RANGE_PLUSMINUS_20mA,
|
||||
AD5758_RANGE_PLUSMINUS_24mA,
|
||||
AD5758_RANGE_MINUS_1mA_PLUS_22mA,
|
||||
};
|
||||
|
||||
enum ad5758_dc_dc_mode {
|
||||
AD5758_DCDC_MODE_POWER_OFF,
|
||||
AD5758_DCDC_MODE_DPC_CURRENT,
|
||||
AD5758_DCDC_MODE_DPC_VOLTAGE,
|
||||
AD5758_DCDC_MODE_PPC_CURRENT,
|
||||
};
|
||||
|
||||
static const struct ad5758_range ad5758_voltage_range[] = {
|
||||
{ AD5758_RANGE_0V_5V, 0, 5000000 },
|
||||
{ AD5758_RANGE_0V_10V, 0, 10000000 },
|
||||
{ AD5758_RANGE_PLUSMINUS_5V, -5000000, 5000000 },
|
||||
{ AD5758_RANGE_PLUSMINUS_10V, -10000000, 10000000 }
|
||||
};
|
||||
|
||||
static const struct ad5758_range ad5758_current_range[] = {
|
||||
{ AD5758_RANGE_0mA_20mA, 0, 20000},
|
||||
{ AD5758_RANGE_0mA_24mA, 0, 24000 },
|
||||
{ AD5758_RANGE_4mA_24mA, 4, 24000 },
|
||||
{ AD5758_RANGE_PLUSMINUS_20mA, -20000, 20000 },
|
||||
{ AD5758_RANGE_PLUSMINUS_24mA, -24000, 24000 },
|
||||
{ AD5758_RANGE_MINUS_1mA_PLUS_22mA, -1000, 22000 },
|
||||
};
|
||||
|
||||
static const int ad5758_sr_clk[16] = {
|
||||
240000, 200000, 150000, 128000, 64000, 32000, 16000, 8000, 4000, 2000,
|
||||
1000, 512, 256, 128, 64, 16
|
||||
};
|
||||
|
||||
static const int ad5758_sr_step[8] = {
|
||||
4, 12, 64, 120, 256, 500, 1820, 2048
|
||||
};
|
||||
|
||||
static const int ad5758_dc_dc_ilim[6] = {
|
||||
150000, 200000, 250000, 300000, 350000, 400000
|
||||
};
|
||||
|
||||
static int ad5758_spi_reg_read(struct ad5758_state *st, unsigned int addr)
|
||||
{
|
||||
struct spi_transfer t[] = {
|
||||
{
|
||||
.tx_buf = &st->d32[0],
|
||||
.len = 4,
|
||||
.cs_change = 1,
|
||||
}, {
|
||||
.tx_buf = &st->d32[1],
|
||||
.rx_buf = &st->d32[2],
|
||||
.len = 4,
|
||||
},
|
||||
};
|
||||
int ret;
|
||||
|
||||
st->d32[0] = cpu_to_be32(
|
||||
(AD5758_WR_FLAG_MSK(AD5758_TWO_STAGE_READBACK_SELECT) << 24) |
|
||||
(addr << 8));
|
||||
st->d32[1] = cpu_to_be32(AD5758_WR_FLAG_MSK(AD5758_NOP) << 24);
|
||||
|
||||
ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return (be32_to_cpu(st->d32[2]) >> 8) & 0xFFFF;
|
||||
}
|
||||
|
||||
static int ad5758_spi_reg_write(struct ad5758_state *st,
|
||||
unsigned int addr,
|
||||
unsigned int val)
|
||||
{
|
||||
st->d32[0] = cpu_to_be32((AD5758_WR_FLAG_MSK(addr) << 24) |
|
||||
((val & 0xFFFF) << 8));
|
||||
|
||||
return spi_write(st->spi, &st->d32[0], sizeof(st->d32[0]));
|
||||
}
|
||||
|
||||
static int ad5758_spi_write_mask(struct ad5758_state *st,
|
||||
unsigned int addr,
|
||||
unsigned long int mask,
|
||||
unsigned int val)
|
||||
{
|
||||
int regval;
|
||||
|
||||
regval = ad5758_spi_reg_read(st, addr);
|
||||
if (regval < 0)
|
||||
return regval;
|
||||
|
||||
regval &= ~mask;
|
||||
regval |= val;
|
||||
|
||||
return ad5758_spi_reg_write(st, addr, regval);
|
||||
}
|
||||
|
||||
static int cmpfunc(const void *a, const void *b)
|
||||
{
|
||||
return *(int *)a - *(int *)b;
|
||||
}
|
||||
|
||||
static int ad5758_find_closest_match(const int *array,
|
||||
unsigned int size, int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (val <= array[i])
|
||||
return i;
|
||||
}
|
||||
|
||||
return size - 1;
|
||||
}
|
||||
|
||||
static int ad5758_wait_for_task_complete(struct ad5758_state *st,
|
||||
unsigned int reg,
|
||||
unsigned int mask)
|
||||
{
|
||||
unsigned int timeout;
|
||||
int ret;
|
||||
|
||||
timeout = 10;
|
||||
do {
|
||||
ret = ad5758_spi_reg_read(st, reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!(ret & mask))
|
||||
return 0;
|
||||
|
||||
usleep_range(100, 1000);
|
||||
} while (--timeout);
|
||||
|
||||
dev_err(&st->spi->dev,
|
||||
"Error reading bit 0x%x in 0x%x register\n", mask, reg);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int ad5758_calib_mem_refresh(struct ad5758_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ad5758_spi_reg_write(st, AD5758_KEY,
|
||||
AD5758_KEY_CODE_CALIB_MEM_REFRESH);
|
||||
if (ret < 0) {
|
||||
dev_err(&st->spi->dev,
|
||||
"Failed to initiate a calibration memory refresh\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait to allow time for the internal calibrations to complete */
|
||||
return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS,
|
||||
AD5758_CAL_MEM_UNREFRESHED_MSK);
|
||||
}
|
||||
|
||||
static int ad5758_soft_reset(struct ad5758_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ad5758_spi_reg_write(st, AD5758_KEY, AD5758_KEY_CODE_RESET_1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad5758_spi_reg_write(st, AD5758_KEY, AD5758_KEY_CODE_RESET_2);
|
||||
|
||||
/* Perform a software reset and wait at least 100us */
|
||||
usleep_range(100, 1000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad5758_set_dc_dc_conv_mode(struct ad5758_state *st,
|
||||
enum ad5758_dc_dc_mode mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1,
|
||||
AD5758_DCDC_CONFIG1_DCDC_MODE_MSK,
|
||||
AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(mode));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0.
|
||||
* This allows the 3-wire interface communication to complete.
|
||||
*/
|
||||
ret = ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2,
|
||||
AD5758_DCDC_CONFIG2_BUSY_3WI_MSK);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st->dc_dc_mode = mode;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad5758_set_dc_dc_ilim(struct ad5758_state *st, unsigned int ilim)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG2,
|
||||
AD5758_DCDC_CONFIG2_ILIMIT_MSK,
|
||||
AD5758_DCDC_CONFIG2_ILIMIT_MODE(ilim));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/*
|
||||
* Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0.
|
||||
* This allows the 3-wire interface communication to complete.
|
||||
*/
|
||||
return ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2,
|
||||
AD5758_DCDC_CONFIG2_BUSY_3WI_MSK);
|
||||
}
|
||||
|
||||
static int ad5758_slew_rate_set(struct ad5758_state *st,
|
||||
unsigned int sr_clk_idx,
|
||||
unsigned int sr_step_idx)
|
||||
{
|
||||
unsigned int mode;
|
||||
unsigned long int mask;
|
||||
int ret;
|
||||
|
||||
mask = AD5758_DAC_CONFIG_SR_EN_MSK |
|
||||
AD5758_DAC_CONFIG_SR_CLOCK_MSK |
|
||||
AD5758_DAC_CONFIG_SR_STEP_MSK;
|
||||
mode = AD5758_DAC_CONFIG_SR_EN_MODE(1) |
|
||||
AD5758_DAC_CONFIG_SR_STEP_MODE(sr_step_idx) |
|
||||
AD5758_DAC_CONFIG_SR_CLOCK_MODE(sr_clk_idx);
|
||||
|
||||
ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, mask, mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Wait to allow time for the internal calibrations to complete */
|
||||
return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS,
|
||||
AD5758_CAL_MEM_UNREFRESHED_MSK);
|
||||
}
|
||||
|
||||
static int ad5758_slew_rate_config(struct ad5758_state *st)
|
||||
{
|
||||
unsigned int sr_clk_idx, sr_step_idx;
|
||||
int i, res;
|
||||
s64 diff_new, diff_old;
|
||||
u64 sr_step, calc_slew_time;
|
||||
|
||||
sr_clk_idx = 0;
|
||||
sr_step_idx = 0;
|
||||
diff_old = S64_MAX;
|
||||
/*
|
||||
* The slew time can be determined by using the formula:
|
||||
* Slew Time = (Full Scale Out / (Step Size x Update Clk Freq))
|
||||
* where Slew time is expressed in microseconds
|
||||
* Given the desired slew time, the following algorithm determines the
|
||||
* best match for the step size and the update clock frequency.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(ad5758_sr_clk); i++) {
|
||||
/*
|
||||
* Go through each valid update clock freq and determine a raw
|
||||
* value for the step size by using the formula:
|
||||
* Step Size = Full Scale Out / (Update Clk Freq * Slew Time)
|
||||
*/
|
||||
sr_step = AD5758_FULL_SCALE_MICRO;
|
||||
do_div(sr_step, ad5758_sr_clk[i]);
|
||||
do_div(sr_step, st->slew_time);
|
||||
/*
|
||||
* After a raw value for step size was determined, find the
|
||||
* closest valid match
|
||||
*/
|
||||
res = ad5758_find_closest_match(ad5758_sr_step,
|
||||
ARRAY_SIZE(ad5758_sr_step),
|
||||
sr_step);
|
||||
/* Calculate the slew time */
|
||||
calc_slew_time = AD5758_FULL_SCALE_MICRO;
|
||||
do_div(calc_slew_time, ad5758_sr_step[res]);
|
||||
do_div(calc_slew_time, ad5758_sr_clk[i]);
|
||||
/*
|
||||
* Determine with how many microseconds the calculated slew time
|
||||
* is different from the desired slew time and store the diff
|
||||
* for the next iteration
|
||||
*/
|
||||
diff_new = abs(st->slew_time - calc_slew_time);
|
||||
if (diff_new < diff_old) {
|
||||
diff_old = diff_new;
|
||||
sr_clk_idx = i;
|
||||
sr_step_idx = res;
|
||||
}
|
||||
}
|
||||
|
||||
return ad5758_slew_rate_set(st, sr_clk_idx, sr_step_idx);
|
||||
}
|
||||
|
||||
static int ad5758_set_out_range(struct ad5758_state *st, int range)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG,
|
||||
AD5758_DAC_CONFIG_RANGE_MSK,
|
||||
AD5758_DAC_CONFIG_RANGE_MODE(range));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Wait to allow time for the internal calibrations to complete */
|
||||
return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS,
|
||||
AD5758_CAL_MEM_UNREFRESHED_MSK);
|
||||
}
|
||||
|
||||
static int ad5758_fault_prot_switch_en(struct ad5758_state *st, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1,
|
||||
AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK,
|
||||
AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(enable));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/*
|
||||
* Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0.
|
||||
* This allows the 3-wire interface communication to complete.
|
||||
*/
|
||||
return ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2,
|
||||
AD5758_DCDC_CONFIG2_BUSY_3WI_MSK);
|
||||
}
|
||||
|
||||
static int ad5758_internal_buffers_en(struct ad5758_state *st, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG,
|
||||
AD5758_DAC_CONFIG_INT_EN_MSK,
|
||||
AD5758_DAC_CONFIG_INT_EN_MODE(enable));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Wait to allow time for the internal calibrations to complete */
|
||||
return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS,
|
||||
AD5758_CAL_MEM_UNREFRESHED_MSK);
|
||||
}
|
||||
|
||||
static int ad5758_reg_access(struct iio_dev *indio_dev,
|
||||
unsigned int reg,
|
||||
unsigned int writeval,
|
||||
unsigned int *readval)
|
||||
{
|
||||
struct ad5758_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
if (readval) {
|
||||
ret = ad5758_spi_reg_read(st, reg);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*readval = ret;
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = ad5758_spi_reg_write(st, reg, writeval);
|
||||
}
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad5758_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long info)
|
||||
{
|
||||
struct ad5758_state *st = iio_priv(indio_dev);
|
||||
int max, min, ret;
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&st->lock);
|
||||
ret = ad5758_spi_reg_read(st, AD5758_DAC_INPUT);
|
||||
mutex_unlock(&st->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
min = st->out_range.min;
|
||||
max = st->out_range.max;
|
||||
*val = (max - min) / 1000;
|
||||
*val2 = 16;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
min = st->out_range.min;
|
||||
max = st->out_range.max;
|
||||
*val = ((min * (1 << 16)) / (max - min)) / 1000;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad5758_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long info)
|
||||
{
|
||||
struct ad5758_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&st->lock);
|
||||
ret = ad5758_spi_reg_write(st, AD5758_DAC_INPUT, val);
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t ad5758_read_powerdown(struct iio_dev *indio_dev,
|
||||
uintptr_t priv,
|
||||
const struct iio_chan_spec *chan,
|
||||
char *buf)
|
||||
{
|
||||
struct ad5758_state *st = iio_priv(indio_dev);
|
||||
|
||||
return sprintf(buf, "%d\n", st->pwr_down);
|
||||
}
|
||||
|
||||
static ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev,
|
||||
uintptr_t priv,
|
||||
struct iio_chan_spec const *chan,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct ad5758_state *st = iio_priv(indio_dev);
|
||||
bool pwr_down;
|
||||
unsigned int dcdc_config1_mode, dc_dc_mode, dac_config_mode, val;
|
||||
unsigned long int dcdc_config1_msk, dac_config_msk;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &pwr_down);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
if (pwr_down) {
|
||||
dc_dc_mode = AD5758_DCDC_MODE_POWER_OFF;
|
||||
val = 0;
|
||||
} else {
|
||||
dc_dc_mode = st->dc_dc_mode;
|
||||
val = 1;
|
||||
}
|
||||
|
||||
dcdc_config1_mode = AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(dc_dc_mode) |
|
||||
AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(val);
|
||||
dcdc_config1_msk = AD5758_DCDC_CONFIG1_DCDC_MODE_MSK |
|
||||
AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK;
|
||||
|
||||
ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1,
|
||||
dcdc_config1_msk,
|
||||
dcdc_config1_mode);
|
||||
if (ret < 0)
|
||||
goto err_unlock;
|
||||
|
||||
dac_config_mode = AD5758_DAC_CONFIG_OUT_EN_MODE(val) |
|
||||
AD5758_DAC_CONFIG_INT_EN_MODE(val);
|
||||
dac_config_msk = AD5758_DAC_CONFIG_OUT_EN_MSK |
|
||||
AD5758_DAC_CONFIG_INT_EN_MSK;
|
||||
|
||||
ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG,
|
||||
dac_config_msk,
|
||||
dac_config_mode);
|
||||
if (ret < 0)
|
||||
goto err_unlock;
|
||||
|
||||
st->pwr_down = pwr_down;
|
||||
|
||||
err_unlock:
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
static const struct iio_info ad5758_info = {
|
||||
.read_raw = ad5758_read_raw,
|
||||
.write_raw = ad5758_write_raw,
|
||||
.debugfs_reg_access = &ad5758_reg_access,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info ad5758_ext_info[] = {
|
||||
{
|
||||
.name = "powerdown",
|
||||
.read = ad5758_read_powerdown,
|
||||
.write = ad5758_write_powerdown,
|
||||
.shared = IIO_SHARED_BY_TYPE,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
#define AD5758_DAC_CHAN(_chan_type) { \
|
||||
.type = (_chan_type), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET), \
|
||||
.indexed = 1, \
|
||||
.output = 1, \
|
||||
.ext_info = ad5758_ext_info, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec ad5758_voltage_ch[] = {
|
||||
AD5758_DAC_CHAN(IIO_VOLTAGE)
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad5758_current_ch[] = {
|
||||
AD5758_DAC_CHAN(IIO_CURRENT)
|
||||
};
|
||||
|
||||
static bool ad5758_is_valid_mode(enum ad5758_dc_dc_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case AD5758_DCDC_MODE_DPC_CURRENT:
|
||||
case AD5758_DCDC_MODE_DPC_VOLTAGE:
|
||||
case AD5758_DCDC_MODE_PPC_CURRENT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad5758_crc_disable(struct ad5758_state *st)
|
||||
{
|
||||
unsigned int mask;
|
||||
|
||||
mask = (AD5758_WR_FLAG_MSK(AD5758_DIGITAL_DIAG_CONFIG) << 24) | 0x5C3A;
|
||||
st->d32[0] = cpu_to_be32(mask);
|
||||
|
||||
return spi_write(st->spi, &st->d32[0], 4);
|
||||
}
|
||||
|
||||
static int ad5758_find_out_range(struct ad5758_state *st,
|
||||
const struct ad5758_range *range,
|
||||
unsigned int size,
|
||||
int min, int max)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((min == range[i].min) && (max == range[i].max)) {
|
||||
st->out_range.reg = range[i].reg;
|
||||
st->out_range.min = range[i].min;
|
||||
st->out_range.max = range[i].max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ad5758_parse_dt(struct ad5758_state *st)
|
||||
{
|
||||
unsigned int tmp, tmparray[2], size;
|
||||
const struct ad5758_range *range;
|
||||
int *index, ret;
|
||||
|
||||
st->dc_dc_ilim = 0;
|
||||
ret = device_property_read_u32(&st->spi->dev,
|
||||
"adi,dc-dc-ilim-microamp", &tmp);
|
||||
if (ret) {
|
||||
dev_dbg(&st->spi->dev,
|
||||
"Missing \"dc-dc-ilim-microamp\" property\n");
|
||||
} else {
|
||||
index = bsearch(&tmp, ad5758_dc_dc_ilim,
|
||||
ARRAY_SIZE(ad5758_dc_dc_ilim),
|
||||
sizeof(int), cmpfunc);
|
||||
if (!index)
|
||||
dev_dbg(&st->spi->dev, "dc-dc-ilim out of range\n");
|
||||
else
|
||||
st->dc_dc_ilim = index - ad5758_dc_dc_ilim;
|
||||
}
|
||||
|
||||
ret = device_property_read_u32(&st->spi->dev, "adi,dc-dc-mode",
|
||||
&st->dc_dc_mode);
|
||||
if (ret) {
|
||||
dev_err(&st->spi->dev, "Missing \"dc-dc-mode\" property\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!ad5758_is_valid_mode(st->dc_dc_mode))
|
||||
return -EINVAL;
|
||||
|
||||
if (st->dc_dc_mode == AD5758_DCDC_MODE_DPC_VOLTAGE) {
|
||||
ret = device_property_read_u32_array(&st->spi->dev,
|
||||
"adi,range-microvolt",
|
||||
tmparray, 2);
|
||||
if (ret) {
|
||||
dev_err(&st->spi->dev,
|
||||
"Missing \"range-microvolt\" property\n");
|
||||
return ret;
|
||||
}
|
||||
range = ad5758_voltage_range;
|
||||
size = ARRAY_SIZE(ad5758_voltage_range);
|
||||
} else {
|
||||
ret = device_property_read_u32_array(&st->spi->dev,
|
||||
"adi,range-microamp",
|
||||
tmparray, 2);
|
||||
if (ret) {
|
||||
dev_err(&st->spi->dev,
|
||||
"Missing \"range-microamp\" property\n");
|
||||
return ret;
|
||||
}
|
||||
range = ad5758_current_range;
|
||||
size = ARRAY_SIZE(ad5758_current_range);
|
||||
}
|
||||
|
||||
ret = ad5758_find_out_range(st, range, size, tmparray[0], tmparray[1]);
|
||||
if (ret) {
|
||||
dev_err(&st->spi->dev, "range invalid\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_property_read_u32(&st->spi->dev, "adi,slew-time-us", &tmp);
|
||||
if (ret) {
|
||||
dev_dbg(&st->spi->dev, "Missing \"slew-time-us\" property\n");
|
||||
st->slew_time = 0;
|
||||
} else {
|
||||
st->slew_time = tmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad5758_init(struct ad5758_state *st)
|
||||
{
|
||||
int regval, ret;
|
||||
|
||||
/* Disable CRC checks */
|
||||
ret = ad5758_crc_disable(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Perform a software reset */
|
||||
ret = ad5758_soft_reset(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Disable CRC checks */
|
||||
ret = ad5758_crc_disable(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Perform a calibration memory refresh */
|
||||
ret = ad5758_calib_mem_refresh(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
regval = ad5758_spi_reg_read(st, AD5758_DIGITAL_DIAG_RESULTS);
|
||||
if (regval < 0)
|
||||
return regval;
|
||||
|
||||
/* Clear all the error flags */
|
||||
ret = ad5758_spi_reg_write(st, AD5758_DIGITAL_DIAG_RESULTS, regval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set the dc-to-dc current limit */
|
||||
ret = ad5758_set_dc_dc_ilim(st, st->dc_dc_ilim);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure the dc-to-dc controller mode */
|
||||
ret = ad5758_set_dc_dc_conv_mode(st, st->dc_dc_mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure the output range */
|
||||
ret = ad5758_set_out_range(st, st->out_range.reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Enable Slew Rate Control, set the slew rate clock and step */
|
||||
if (st->slew_time) {
|
||||
ret = ad5758_slew_rate_config(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable the VIOUT fault protection switch (FPS is closed) */
|
||||
ret = ad5758_fault_prot_switch_en(st, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Power up the DAC and internal (INT) amplifiers */
|
||||
ret = ad5758_internal_buffers_en(st, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Enable VIOUT */
|
||||
return ad5758_spi_write_mask(st, AD5758_DAC_CONFIG,
|
||||
AD5758_DAC_CONFIG_OUT_EN_MSK,
|
||||
AD5758_DAC_CONFIG_OUT_EN_MODE(1));
|
||||
}
|
||||
|
||||
static int ad5758_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad5758_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
st->spi = spi;
|
||||
|
||||
mutex_init(&st->lock);
|
||||
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->info = &ad5758_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->num_channels = 1;
|
||||
|
||||
ret = ad5758_parse_dt(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (st->dc_dc_mode == AD5758_DCDC_MODE_DPC_VOLTAGE)
|
||||
indio_dev->channels = ad5758_voltage_ch;
|
||||
else
|
||||
indio_dev->channels = ad5758_current_ch;
|
||||
|
||||
ret = ad5758_init(st);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "AD5758 init failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(&st->spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad5758_id[] = {
|
||||
{ "ad5758", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad5758_id);
|
||||
|
||||
static struct spi_driver ad5758_driver = {
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
},
|
||||
.probe = ad5758_probe,
|
||||
.id_table = ad5758_id,
|
||||
};
|
||||
|
||||
module_spi_driver(ad5758_driver);
|
||||
|
||||
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD5758 DAC");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -87,12 +87,7 @@ static int ltc2632_read_raw(struct iio_dev *indio_dev,
|
|||
int *val2,
|
||||
long m)
|
||||
{
|
||||
struct ltc2632_chip_info *chip_info;
|
||||
|
||||
const struct ltc2632_state *st = iio_priv(indio_dev);
|
||||
const struct spi_device_id *spi_dev_id = spi_get_device_id(st->spi_dev);
|
||||
|
||||
chip_info = (struct ltc2632_chip_info *)spi_dev_id->driver_data;
|
||||
|
||||
switch (m) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
|
|
|
@ -97,9 +97,6 @@ static int dac5571_cmd_quad(struct dac5571_data *data, int channel, u16 val)
|
|||
|
||||
static int dac5571_pwrdwn_single(struct dac5571_data *data, int channel, u8 pwrdwn)
|
||||
{
|
||||
unsigned int shift;
|
||||
|
||||
shift = 12 - data->spec->resolution;
|
||||
data->buf[1] = 0;
|
||||
data->buf[0] = pwrdwn << DAC5571_SINGLE_PWRDWN_BITS;
|
||||
|
||||
|
@ -111,9 +108,6 @@ static int dac5571_pwrdwn_single(struct dac5571_data *data, int channel, u8 pwrd
|
|||
|
||||
static int dac5571_pwrdwn_quad(struct dac5571_data *data, int channel, u8 pwrdwn)
|
||||
{
|
||||
unsigned int shift;
|
||||
|
||||
shift = 16 - data->spec->resolution;
|
||||
data->buf[2] = 0;
|
||||
data->buf[1] = pwrdwn << DAC5571_QUAD_PWRDWN_BITS;
|
||||
data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) |
|
||||
|
|
|
@ -274,6 +274,15 @@ struct ad9523_state {
|
|||
unsigned long vco_out_freq[AD9523_NUM_CLK_SRC];
|
||||
unsigned char vco_out_map[AD9523_NUM_CHAN_ALT_CLK_SRC];
|
||||
|
||||
/*
|
||||
* Lock for accessing device registers. Some operations require
|
||||
* multiple consecutive R/W operations, during which the device
|
||||
* shouldn't be interrupted. The buffers are also shared across
|
||||
* all operations so need to be protected on stand alone reads and
|
||||
* writes.
|
||||
*/
|
||||
struct mutex lock;
|
||||
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires the
|
||||
* transfer buffers to live in their own cache lines.
|
||||
|
@ -500,6 +509,7 @@ static ssize_t ad9523_store(struct device *dev,
|
|||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
struct ad9523_state *st = iio_priv(indio_dev);
|
||||
bool state;
|
||||
int ret;
|
||||
|
||||
|
@ -510,7 +520,7 @@ static ssize_t ad9523_store(struct device *dev,
|
|||
if (!state)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->lock);
|
||||
switch ((u32)this_attr->address) {
|
||||
case AD9523_SYNC:
|
||||
ret = ad9523_sync(indio_dev);
|
||||
|
@ -521,7 +531,7 @@ static ssize_t ad9523_store(struct device *dev,
|
|||
default:
|
||||
ret = -ENODEV;
|
||||
}
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
@ -532,15 +542,16 @@ static ssize_t ad9523_show(struct device *dev,
|
|||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
struct ad9523_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->lock);
|
||||
ret = ad9523_read(indio_dev, AD9523_READBACK_0);
|
||||
if (ret >= 0) {
|
||||
ret = sprintf(buf, "%d\n", !!(ret & (1 <<
|
||||
(u32)this_attr->address)));
|
||||
}
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -623,9 +634,9 @@ static int ad9523_read_raw(struct iio_dev *indio_dev,
|
|||
unsigned int code;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->lock);
|
||||
ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel));
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -642,7 +653,7 @@ static int ad9523_read_raw(struct iio_dev *indio_dev,
|
|||
code = (AD9523_CLK_DIST_DIV_PHASE_REV(ret) * 3141592) /
|
||||
AD9523_CLK_DIST_DIV_REV(ret);
|
||||
*val = code / 1000000;
|
||||
*val2 = (code % 1000000) * 10;
|
||||
*val2 = code % 1000000;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -659,7 +670,7 @@ static int ad9523_write_raw(struct iio_dev *indio_dev,
|
|||
unsigned int reg;
|
||||
int ret, tmp, code;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->lock);
|
||||
ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel));
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -705,7 +716,7 @@ static int ad9523_write_raw(struct iio_dev *indio_dev,
|
|||
|
||||
ad9523_io_update(indio_dev);
|
||||
out:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -713,9 +724,10 @@ static int ad9523_reg_access(struct iio_dev *indio_dev,
|
|||
unsigned int reg, unsigned int writeval,
|
||||
unsigned int *readval)
|
||||
{
|
||||
struct ad9523_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->lock);
|
||||
if (readval == NULL) {
|
||||
ret = ad9523_write(indio_dev, reg | AD9523_R1B, writeval);
|
||||
ad9523_io_update(indio_dev);
|
||||
|
@ -728,7 +740,7 @@ static int ad9523_reg_access(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -967,6 +979,8 @@ static int ad9523_probe(struct spi_device *spi)
|
|||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
mutex_init(&st->lock);
|
||||
|
||||
st->reg = devm_regulator_get(&spi->dev, "vcc");
|
||||
if (!IS_ERR(st->reg)) {
|
||||
ret = regulator_enable(st->reg);
|
||||
|
|
|
@ -81,9 +81,11 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
|
|||
adis->tx[9] = (value >> 24) & 0xff;
|
||||
adis->tx[6] = ADIS_WRITE_REG(reg + 2);
|
||||
adis->tx[7] = (value >> 16) & 0xff;
|
||||
/* fall through */
|
||||
case 2:
|
||||
adis->tx[4] = ADIS_WRITE_REG(reg + 1);
|
||||
adis->tx[5] = (value >> 8) & 0xff;
|
||||
/* fall through */
|
||||
case 1:
|
||||
adis->tx[2] = ADIS_WRITE_REG(reg);
|
||||
adis->tx[3] = value & 0xff;
|
||||
|
@ -167,6 +169,7 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
|
|||
adis->tx[2] = ADIS_READ_REG(reg + 2);
|
||||
adis->tx[3] = 0;
|
||||
spi_message_add_tail(&xfers[1], &msg);
|
||||
/* fall through */
|
||||
case 2:
|
||||
adis->tx[4] = ADIS_READ_REG(reg);
|
||||
adis->tx[5] = 0;
|
||||
|
|
|
@ -103,6 +103,12 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.reg = ®_set_6500,
|
||||
.config = &chip_config_6050,
|
||||
},
|
||||
{
|
||||
.whoami = INV_MPU6515_WHOAMI_VALUE,
|
||||
.name = "MPU6515",
|
||||
.reg = ®_set_6500,
|
||||
.config = &chip_config_6050,
|
||||
},
|
||||
{
|
||||
.whoami = INV_MPU6000_WHOAMI_VALUE,
|
||||
.name = "MPU6000",
|
||||
|
|
|
@ -174,6 +174,7 @@ static int inv_mpu_remove(struct i2c_client *client)
|
|||
static const struct i2c_device_id inv_mpu_id[] = {
|
||||
{"mpu6050", INV_MPU6050},
|
||||
{"mpu6500", INV_MPU6500},
|
||||
{"mpu6515", INV_MPU6515},
|
||||
{"mpu9150", INV_MPU9150},
|
||||
{"mpu9250", INV_MPU9250},
|
||||
{"mpu9255", INV_MPU9255},
|
||||
|
@ -192,6 +193,10 @@ static const struct of_device_id inv_of_match[] = {
|
|||
.compatible = "invensense,mpu6500",
|
||||
.data = (void *)INV_MPU6500
|
||||
},
|
||||
{
|
||||
.compatible = "invensense,mpu6515",
|
||||
.data = (void *)INV_MPU6515
|
||||
},
|
||||
{
|
||||
.compatible = "invensense,mpu9150",
|
||||
.data = (void *)INV_MPU9150
|
||||
|
|
|
@ -71,6 +71,7 @@ struct inv_mpu6050_reg_map {
|
|||
enum inv_devices {
|
||||
INV_MPU6050,
|
||||
INV_MPU6500,
|
||||
INV_MPU6515,
|
||||
INV_MPU6000,
|
||||
INV_MPU9150,
|
||||
INV_MPU9250,
|
||||
|
@ -256,6 +257,7 @@ struct inv_mpu6050_state {
|
|||
#define INV_MPU9150_WHOAMI_VALUE 0x68
|
||||
#define INV_MPU9250_WHOAMI_VALUE 0x71
|
||||
#define INV_MPU9255_WHOAMI_VALUE 0x73
|
||||
#define INV_MPU6515_WHOAMI_VALUE 0x74
|
||||
#define INV_ICM20608_WHOAMI_VALUE 0xAF
|
||||
|
||||
/* scan element definition */
|
||||
|
|
|
@ -298,8 +298,11 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
|
|||
err = regmap_bulk_read(hw->regmap,
|
||||
hw->settings->fifo_ops.fifo_diff.addr,
|
||||
&fifo_status, sizeof(fifo_status));
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
dev_err(hw->dev, "failed to read fifo status (err=%d)\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK))
|
||||
return 0;
|
||||
|
@ -313,8 +316,12 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
|
|||
|
||||
for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
|
||||
err = st_lsm6dsx_read_block(hw, hw->buff, pattern_len);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
dev_err(hw->dev,
|
||||
"failed to read pattern from fifo (err=%d)\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Data are written to the FIFO with a specific pattern
|
||||
|
@ -385,8 +392,11 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
|
|||
|
||||
if (unlikely(reset_ts)) {
|
||||
err = st_lsm6dsx_reset_hw_ts(hw);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
dev_err(hw->dev, "failed to reset hw ts (err=%d)\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return read_len;
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ static const char * const iio_chan_type_name_spec[] = {
|
|||
[IIO_INDEX] = "index",
|
||||
[IIO_GRAVITY] = "gravity",
|
||||
[IIO_POSITIONRELATIVE] = "positionrelative",
|
||||
[IIO_PHASE] = "phase",
|
||||
};
|
||||
|
||||
static const char * const iio_modifier_names[] = {
|
||||
|
@ -109,6 +110,7 @@ static const char * const iio_modifier_names[] = {
|
|||
[IIO_MOD_LIGHT_GREEN] = "green",
|
||||
[IIO_MOD_LIGHT_BLUE] = "blue",
|
||||
[IIO_MOD_LIGHT_UV] = "uv",
|
||||
[IIO_MOD_LIGHT_DUV] = "duv",
|
||||
[IIO_MOD_QUATERNION] = "quaternion",
|
||||
[IIO_MOD_TEMP_AMBIENT] = "ambient",
|
||||
[IIO_MOD_TEMP_OBJECT] = "object",
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
#
|
||||
# Light sensors
|
||||
#
|
||||
|
@ -319,6 +320,17 @@ config PA12203001
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called pa12203001.
|
||||
|
||||
config SI1133
|
||||
tristate "SI1133 UV Index Sensor and Ambient Light Sensor"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y here if you want to build a driver for the Silicon Labs SI1133
|
||||
UV Index Sensor and Ambient Light Sensor chip.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called si1133.
|
||||
|
||||
config SI1145
|
||||
tristate "SI1132 and SI1141/2/3/5/6/7 combined ALS, UV index and proximity sensor"
|
||||
depends on I2C
|
||||
|
|
|
@ -32,6 +32,7 @@ obj-$(CONFIG_OPT3001) += opt3001.o
|
|||
obj-$(CONFIG_PA12203001) += pa12203001.o
|
||||
obj-$(CONFIG_RPR0521) += rpr0521.o
|
||||
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
|
||||
obj-$(CONFIG_SI1133) += si1133.o
|
||||
obj-$(CONFIG_SI1145) += si1145.o
|
||||
obj-$(CONFIG_STK3310) += stk3310.o
|
||||
obj-$(CONFIG_ST_UVIS25) += st_uvis25_core.o
|
||||
|
|
1068
drivers/iio/light/si1133.c
Normal file
1068
drivers/iio/light/si1133.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -94,9 +94,8 @@ static int st_press_i2c_probe(struct i2c_client *client,
|
|||
if ((ret < 0) || (ret >= ST_PRESS_MAX))
|
||||
return -ENODEV;
|
||||
|
||||
strncpy(client->name, st_press_id_table[ret].name,
|
||||
strlcpy(client->name, st_press_id_table[ret].name,
|
||||
sizeof(client->name));
|
||||
client->name[sizeof(client->name) - 1] = '\0';
|
||||
} else if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
|
|
|
@ -20,6 +20,19 @@ endmenu
|
|||
|
||||
menu "Proximity and distance sensors"
|
||||
|
||||
config ISL29501
|
||||
tristate "Intersil ISL29501 Time Of Flight sensor"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select IIO_KFIFO_BUF
|
||||
help
|
||||
Say Y here if you want to build a driver for the Intersil ISL29501
|
||||
Time of Flight sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called isl29501.
|
||||
|
||||
config LIDAR_LITE_V2
|
||||
tristate "PulsedLight LIDAR sensor"
|
||||
select IIO_BUFFER
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_AS3935) += as3935.o
|
||||
obj-$(CONFIG_ISL29501) += isl29501.o
|
||||
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
|
||||
obj-$(CONFIG_RFD77402) += rfd77402.o
|
||||
obj-$(CONFIG_SRF04) += srf04.o
|
||||
|
|
1027
drivers/iio/proximity/isl29501.c
Normal file
1027
drivers/iio/proximity/isl29501.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -116,45 +116,26 @@ static struct ad5933_platform_data ad5933_default_pdata = {
|
|||
.vref_mv = 3300,
|
||||
};
|
||||
|
||||
#define AD5933_CHANNEL(_type, _extend_name, _info_mask_separate, _address, \
|
||||
_scan_index, _realbits) { \
|
||||
.type = (_type), \
|
||||
.extend_name = (_extend_name), \
|
||||
.info_mask_separate = (_info_mask_separate), \
|
||||
.address = (_address), \
|
||||
.scan_index = (_scan_index), \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = (_realbits), \
|
||||
.storagebits = 16, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec ad5933_channels[] = {
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.indexed = 1,
|
||||
.channel = 0,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.address = AD5933_REG_TEMP_DATA,
|
||||
.scan_index = -1,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 14,
|
||||
.storagebits = 16,
|
||||
},
|
||||
}, { /* Ring Channels */
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.channel = 0,
|
||||
.extend_name = "real",
|
||||
.address = AD5933_REG_REAL_DATA,
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
},
|
||||
}, {
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.channel = 0,
|
||||
.extend_name = "imag",
|
||||
.address = AD5933_REG_IMAG_DATA,
|
||||
.scan_index = 1,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
},
|
||||
},
|
||||
AD5933_CHANNEL(IIO_TEMP, NULL, BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE), AD5933_REG_TEMP_DATA, -1, 14),
|
||||
/* Ring Channels */
|
||||
AD5933_CHANNEL(IIO_VOLTAGE, "real", 0, AD5933_REG_REAL_DATA, 0, 16),
|
||||
AD5933_CHANNEL(IIO_VOLTAGE, "imag", 0, AD5933_REG_IMAG_DATA, 1, 16),
|
||||
};
|
||||
|
||||
static int ad5933_i2c_write(struct i2c_client *client, u8 reg, u8 len, u8 *data)
|
||||
|
|
|
@ -45,6 +45,7 @@ enum iio_chan_type {
|
|||
IIO_INDEX,
|
||||
IIO_GRAVITY,
|
||||
IIO_POSITIONRELATIVE,
|
||||
IIO_PHASE,
|
||||
};
|
||||
|
||||
enum iio_modifier {
|
||||
|
@ -85,6 +86,7 @@ enum iio_modifier {
|
|||
IIO_MOD_CO2,
|
||||
IIO_MOD_VOC,
|
||||
IIO_MOD_LIGHT_UV,
|
||||
IIO_MOD_LIGHT_DUV,
|
||||
};
|
||||
|
||||
enum iio_event_type {
|
||||
|
|
|
@ -59,6 +59,7 @@ static const char * const iio_chan_type_name_spec[] = {
|
|||
[IIO_UVINDEX] = "uvindex",
|
||||
[IIO_GRAVITY] = "gravity",
|
||||
[IIO_POSITIONRELATIVE] = "positionrelative",
|
||||
[IIO_PHASE] = "phase",
|
||||
};
|
||||
|
||||
static const char * const iio_ev_type_text[] = {
|
||||
|
@ -97,6 +98,7 @@ static const char * const iio_modifier_names[] = {
|
|||
[IIO_MOD_LIGHT_GREEN] = "green",
|
||||
[IIO_MOD_LIGHT_BLUE] = "blue",
|
||||
[IIO_MOD_LIGHT_UV] = "uv",
|
||||
[IIO_MOD_LIGHT_DUV] = "duv",
|
||||
[IIO_MOD_QUATERNION] = "quaternion",
|
||||
[IIO_MOD_TEMP_AMBIENT] = "ambient",
|
||||
[IIO_MOD_TEMP_OBJECT] = "object",
|
||||
|
@ -153,6 +155,7 @@ static bool event_is_known(struct iio_event_data *event)
|
|||
case IIO_UVINDEX:
|
||||
case IIO_GRAVITY:
|
||||
case IIO_POSITIONRELATIVE:
|
||||
case IIO_PHASE:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
@ -180,6 +183,7 @@ static bool event_is_known(struct iio_event_data *event)
|
|||
case IIO_MOD_LIGHT_GREEN:
|
||||
case IIO_MOD_LIGHT_BLUE:
|
||||
case IIO_MOD_LIGHT_UV:
|
||||
case IIO_MOD_LIGHT_DUV:
|
||||
case IIO_MOD_QUATERNION:
|
||||
case IIO_MOD_TEMP_AMBIENT:
|
||||
case IIO_MOD_TEMP_OBJECT:
|
||||
|
|
Loading…
Reference in a new issue