mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 10:11:38 -04:00
Merge tag 'iio-for-7.1a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes: IIO: New devices support, features and cleanup for 7.1 Includes merge of v7.0-rc4 to pull in a fix and a merge of ib-iio-thermal-qcom-pmic5 immutable branch (provided from the IIO tree so thermal could also pick this up and add thermal specific remainder of the series on top. New device support ------------------ adi,ad4030 - Add support for ADA4316 and ADAQ4224 ADCs with PGAs. adi,ad4080 - Add support for AD4082, AD4085 and AD4088 ADCs. adi,ad8366 - Add ADRF5702 and ADRF5703 digital step attenuators. adi,adxl372 - Add support for the ADXL371 accelerometer after refactors to allow multiple device variants to be supported by the driver. In particular a silicon issue means the hardware FIFO doesn't work on the ADXL371 bosch,bma255/bmg160 - Add support for BMX055 gyroscope and magnetometer (effectively separate devices from point of view of interface). lltc,ltc2309 - Add support for LTC2305 2 channel 12-bit ADC. lltc,ltc2532 - Add support for 4 variants of the LTC2654 quad DAC. maxim,ds4424 - Add IDs for DS4402 and DS4404 parts. Initially patch is ID only but additional features also added that are device dependent. qcom,spmi-adc-gen3 - New driver supporting this generation of Qualcomm's SoC ADC. st,vl53l1 - New driver for this Time Of Flight (TOF) sensor. ti,ina2xx - Support the INA236 digital power monitor. vishay,vcnl4000 - Add support for CM36686 ambient light and proximity sensor. - Add support for CM36672P proximity sensors. ID only additions. amlogic,meson-adc - Support the Meson S4. Features -------- iio-backend framework - Add capability discovery so front end drivers can know what features are available from the backend and adjust how they operate. adi,ad4030 - Add SPI offload support requiring a non trivial PWM setup. adi,ad7380 - Add support for multiple SPI lanes to improve throughput. adi,ad7768-1 - Support SPI offload and always use continuous mode, enabling more filter options. adi,ad8366 - Device tree bindings and support. aspeed,adc - Handle battery channel. maxim,ds4424 - Add external resistor controlled scale and per-variant limits. - Handle per variant range limits. - Move it to regmap. motorola,cpcap-adc - Support for the ADC found on the Motorola Mot board. Effectively some board specific configuration handled in the driver. vishay,vcnl4000 - Support explicit power supply regulators. tyhx,hx9023s - Allow device tree specification of firmware file name. Cleanup and minor fixes ----------------------- treewide - Remove a bunch of unused structure elements. - Replaces standard fixed width integers with kernel types. - Replace some other error values that were returned on allocation failure with -ENOMEM iio-core - Replace a few custom devm implementations for devm_add_action_or_reset() iio-trigger - Use put_device() to cleanup on error. iio-backend - Use __free(fwmode_handle) to simplify some code. hw-consumer - Use separate allocation for scan mask bitmap to simplify code. acpi-als - Switch from ACPI driver to platform driver. adi,ad4030 - Use BIT() to replace values that are always a power of 2 to slightly improve readability. adi,ad4062 - Add a missing check for error form iio_get_current_scan_type() adi,ad5933 - Use div64_ul() rather than do_div() as remainder was not used. adi,ad7191 - Documentation fixes related to clocks adi,ad7816 - Use sysfs_emit() adi,ad8366 - General driver modernization adi,adf4350 - Change a TOOD to NOTE in a comment to avoid anyone from walking into a tricky to improve corner case. adi,admv1013 - Avoid a null pointer dereference if device_property_read_string() fails. adi,admv4420 - Return error code rather than -1.. adi,adxl345 - Add separate scaling for events from that of raw channels. amlogic,meson-adc - Don't bother keeping nvmem cell access around when only used in probe. atmel,at91-sama5d - Don't bother keeping nvmem cell access around when only used in probe. bosch,bmc150 - Use sysfs_emit() in a few places. honeywell,hsc030pa - Improve handling of return values from i2c_transfer. liteon,ltr501 - Return error values rather than -1 replaced by -EINVAL at higher levels of the callstack. maxim,ds4424 - A bunch of general minor improvements prior to adding new features. maxim,max11410 - Make some const string arrays static. maxim,max5522 - Use devm_regulator_get_enable_read_voltage() at probe to cache the voltage rather than keeping the regulator around to access and query later. vishay,vcnl4000 - Various code improvements. sharp,gp2ap020a00f - General driver modernization. silabs,si7210 - Use devm_regulator_get_enable_read_voltage() at probe to cache the voltage rather than keeping the regulator around to access and query later. st,lsm6dsx - Add SMOCF00 ACPI ID seen on products by SHIFT. st,st_sensors - Fix up various kernel-doc issues. - Avoid kmalloc of a single use buffer and instead reused existing buffer_data. taos,tsl2772 - Fix some kernel-doc warnings due to missing : ti,ads7950 - Use iio_push_to_buffers_with_ts_unaligned() as first few elements of array are not the data that is pushed. - Move from array of chip_info structures to individual named ones. This is part of slowly replacing use of a code pattern that we don't want replicated in new drivers. vti,sca3000 - General driver modernization included use of devm and guard(). Various other more minor stuff not called out explicitly. Includes things like typo fixes, use of dev_err_probe() and local variables to avoid repeated dereferencing of the same member as well as increasing use of guard() to simplify release of locks. Another slow improvement to code quality is both standardizing on header order and ensure all appropriate headers are included. * tag 'iio-for-7.1a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (217 commits) Docs: iio: ad7191 Correct clock configuration iio: amplifiers: ad8366: add support for adrf5702/3 dt-bindings: iio: amplifiers: ad8366: add adrf5702/3 support iio: adc: meson-saradc: add support for Meson S4 dt-bindings: iio: adc: amlogic,meson-saradc: add S4 compatible iio: imu: st_lsm6dsx: Add ACPI ID for SHIFT13mi gyroscope iio: proximity: add driver for ST VL53L1X ToF sensor dt-bindings: iio: proximity: add ST VL53L1X ToF sensor iio: adc: max11410: make vref register name arrays static const iio: accel: bmc150-accel-core: use sysfs_emit() in show functions iio: frequency: adf4350: replace TODO with NOTE in adf4350_set_freq() iio: adc: ltc2309: add support for ltc2305 iio: adc: ltc2309: explicitly assign hex values to channel enums dt-bindings: adc: ltc2497: add support for ltc2305 iio: accel: adxl380: fix typo in PART_ID register macro iio: dac: ds4424: add Rfs-based scale and per-variant limits dt-bindings: iio: dac: maxim,ds4424: add maxim,rfs-ohms property iio: dac: ds4424: convert to regmap iio: dac: ds4424: support per-variant output range limits iio: dac: ds4424: add DS4402/DS4404 device IDs ...
This commit is contained in:
@@ -1428,7 +1428,7 @@ KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
The name of the trigger source being used, as per string given
|
||||
in /sys/class/iio/triggerY/name.
|
||||
in /sys/bus/iio/devices/triggerY/name.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/bufferY/length
|
||||
KernelVersion: 5.11
|
||||
|
||||
@@ -4,20 +4,23 @@
|
||||
$id: http://devicetree.org/schemas/iio/accel/adi,adxl372.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices ADXL372 3-Axis, +/-(200g) Digital Accelerometer
|
||||
title: Analog Devices ADXL371/ADXL372 3-Axis, +/-(200g) Digital Accelerometer
|
||||
|
||||
maintainers:
|
||||
- Marcelo Schmitt <marcelo.schmitt@analog.com>
|
||||
- Nuno Sá <nuno.sa@analog.com>
|
||||
- Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
|
||||
description: |
|
||||
Analog Devices ADXL372 3-Axis, +/-(200g) Digital Accelerometer that supports
|
||||
both I2C & SPI interfaces
|
||||
Analog Devices ADXL371/ADXL372 3-Axis, +/-(200g) Digital Accelerometer that
|
||||
supports both I2C & SPI interfaces
|
||||
https://www.analog.com/en/products/adxl371.html
|
||||
https://www.analog.com/en/products/adxl372.html
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,adxl371
|
||||
- adi,adxl372
|
||||
|
||||
reg:
|
||||
|
||||
@@ -16,25 +16,27 @@ description:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
# bmc150-accel driver in Linux
|
||||
- bosch,bma222
|
||||
- bosch,bma222e
|
||||
- bosch,bma250e
|
||||
- bosch,bma253
|
||||
- bosch,bma254
|
||||
- bosch,bma255
|
||||
- bosch,bma280
|
||||
- bosch,bmc150_accel
|
||||
- bosch,bmc156_accel
|
||||
- bosch,bmi055_accel
|
||||
oneOf:
|
||||
- enum:
|
||||
- bosch,bma222
|
||||
- bosch,bma222e
|
||||
- bosch,bma250e
|
||||
- bosch,bma253
|
||||
- bosch,bma254
|
||||
- bosch,bma255
|
||||
- bosch,bma280
|
||||
- bosch,bmc150_accel
|
||||
- bosch,bmc156_accel
|
||||
- bosch,bmi055_accel
|
||||
|
||||
# bma180 driver in Linux
|
||||
- bosch,bma023
|
||||
- bosch,bma150
|
||||
- bosch,bma180
|
||||
- bosch,bma250
|
||||
- bosch,smb380
|
||||
- bosch,bma023
|
||||
- bosch,bma150
|
||||
- bosch,bma180
|
||||
- bosch,bma250
|
||||
- bosch,smb380
|
||||
- items:
|
||||
- const: bosch,bmx055-accel
|
||||
- const: bosch,bmc150_accel
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -19,6 +19,10 @@ description: |
|
||||
* https://www.analog.com/media/en/technical-documentation/data-sheets/ad4030-24-4032-24.pdf
|
||||
* https://www.analog.com/media/en/technical-documentation/data-sheets/ad4630-24_ad4632-24.pdf
|
||||
* https://www.analog.com/media/en/technical-documentation/data-sheets/ad4630-16-4632-16.pdf
|
||||
* https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4216.pdf
|
||||
* https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4224.pdf
|
||||
|
||||
$ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@@ -29,6 +33,8 @@ properties:
|
||||
- adi,ad4630-24
|
||||
- adi,ad4632-16
|
||||
- adi,ad4632-24
|
||||
- adi,adaq4216
|
||||
- adi,adaq4224
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -60,6 +66,14 @@ properties:
|
||||
description:
|
||||
Internal buffered Reference. Used when ref-supply is not connected.
|
||||
|
||||
vddh-supply:
|
||||
description:
|
||||
PGIA Positive Power Supply.
|
||||
|
||||
vdd-fda-supply:
|
||||
description:
|
||||
FDA Positive Power Supply.
|
||||
|
||||
cnv-gpios:
|
||||
description:
|
||||
The Convert Input (CNV). It initiates the sampling conversions.
|
||||
@@ -70,6 +84,17 @@ properties:
|
||||
The Reset Input (/RST). Used for asynchronous device reset.
|
||||
maxItems: 1
|
||||
|
||||
pga-gpios:
|
||||
description:
|
||||
A0 and A1 pins for gain selection. For devices that have PGA configuration
|
||||
input pins, pga-gpios should be defined.
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
pwms:
|
||||
description: PWM signal connected to the CNV pin.
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
The BUSY pin is used to signal that the conversions results are available
|
||||
@@ -107,6 +132,22 @@ allOf:
|
||||
properties:
|
||||
spi-rx-bus-width:
|
||||
maxItems: 1
|
||||
# ADAQ devices require a gain property to indicate how hardware PGA is set
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
pattern: ^adi,adaq
|
||||
then:
|
||||
required:
|
||||
- vddh-supply
|
||||
- vdd-fda-supply
|
||||
- pga-gpios
|
||||
properties:
|
||||
ref-supply: false
|
||||
else:
|
||||
properties:
|
||||
pga-gpios: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
@@ -148,3 +189,26 @@ examples:
|
||||
reset-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "adi,adaq4216";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <80000000>;
|
||||
vdd-5v-supply = <&supply_5V>;
|
||||
vdd-1v8-supply = <&supply_1_8V>;
|
||||
vio-supply = <&supply_1_8V>;
|
||||
refin-supply = <&refin_sup>;
|
||||
vddh-supply = <&vddh>;
|
||||
vdd-fda-supply = <&vdd_fda>;
|
||||
cnv-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
|
||||
pga-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio0 3 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -27,10 +27,13 @@ properties:
|
||||
enum:
|
||||
- adi,ad4080
|
||||
- adi,ad4081
|
||||
- adi,ad4082
|
||||
- adi,ad4083
|
||||
- adi,ad4084
|
||||
- adi,ad4085
|
||||
- adi,ad4086
|
||||
- adi,ad4087
|
||||
- adi,ad4088
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -62,6 +62,11 @@ properties:
|
||||
spi-cpol: true
|
||||
spi-cpha: true
|
||||
|
||||
spi-rx-bus-width:
|
||||
maxItems: 4
|
||||
items:
|
||||
maximum: 1
|
||||
|
||||
vcc-supply:
|
||||
description: A 3V to 3.6V supply that powers the chip.
|
||||
|
||||
@@ -160,6 +165,23 @@ patternProperties:
|
||||
unevaluatedProperties: false
|
||||
|
||||
allOf:
|
||||
# 2-channel chips only have two SDO lines
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad7380
|
||||
- adi,ad7381
|
||||
- adi,ad7383
|
||||
- adi,ad7384
|
||||
- adi,ad7386
|
||||
- adi,ad7387
|
||||
- adi,ad7388
|
||||
then:
|
||||
properties:
|
||||
spi-rx-bus-width:
|
||||
maxItems: 2
|
||||
|
||||
# pseudo-differential chips require common mode voltage supplies,
|
||||
# true differential chips don't use them
|
||||
- if:
|
||||
@@ -284,6 +306,7 @@ examples:
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
spi-max-frequency = <80000000>;
|
||||
spi-rx-bus-width = <1>, <1>, <1>, <1>;
|
||||
|
||||
interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
|
||||
@@ -27,7 +27,11 @@ properties:
|
||||
- amlogic,meson-gxm-saradc
|
||||
- amlogic,meson-axg-saradc
|
||||
- amlogic,meson-g12a-saradc
|
||||
# Usage of this generic fallback is not allowed for new devices
|
||||
- const: amlogic,meson-saradc
|
||||
- items:
|
||||
- const: amlogic,meson-s4-saradc
|
||||
- const: amlogic,meson-g12a-saradc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -11,6 +11,12 @@ maintainers:
|
||||
- Liam Beguin <liambeguin@gmail.com>
|
||||
|
||||
description: |
|
||||
LTC2305:
|
||||
low noise, low power, 2-channel, 12-bit successive approximation ADC with an
|
||||
I2C compatible serial interface.
|
||||
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/23015fb.pdf
|
||||
|
||||
LTC2309:
|
||||
low noise, low power, 8-channel, 12-bit successive approximation ADC with an
|
||||
I2C compatible serial interface.
|
||||
@@ -28,6 +34,7 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- lltc,ltc2305
|
||||
- lltc,ltc2309
|
||||
- lltc,ltc2497
|
||||
- lltc,ltc2499
|
||||
|
||||
@@ -19,6 +19,7 @@ properties:
|
||||
enum:
|
||||
- motorola,cpcap-adc
|
||||
- motorola,mapphone-cpcap-adc
|
||||
- motorola,mot-cpcap-adc
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/qcom,spmi-adc5-gen3.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm's SPMI PMIC ADC5 Gen3
|
||||
|
||||
maintainers:
|
||||
- Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
|
||||
|
||||
description: |
|
||||
SPMI PMIC5 Gen3 voltage ADC (ADC) provides interface to clients to read
|
||||
voltage. It is a 16-bit sigma-delta ADC. It also performs the same thermal
|
||||
monitoring function as the existing ADC_TM devices.
|
||||
|
||||
The interface is implemented on SDAM (Shared Direct Access Memory) peripherals
|
||||
on the master PMIC rather than a dedicated ADC peripheral. The number of PMIC
|
||||
SDAM peripherals allocated for ADC is not correlated with the PMIC used, it is
|
||||
programmed in FW (PBS) and is fixed per SOC, based on the SOC requirements.
|
||||
All boards using a particular (SOC + master PMIC) combination will have the
|
||||
same number of ADC SDAMs supported on that PMIC.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,spmi-adc5-gen3
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: SDAM0 base address in the SPMI PMIC register map
|
||||
- description: SDAM1 base address
|
||||
minItems: 1
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 1
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: SDAM0 end of conversion (EOC) interrupt
|
||||
- description: SDAM1 EOC interrupt
|
||||
minItems: 1
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-9a-f]+$":
|
||||
type: object
|
||||
unevaluatedProperties: false
|
||||
$ref: /schemas/iio/adc/qcom,spmi-vadc-common.yaml
|
||||
description:
|
||||
Represents the external channels which are connected to the ADC.
|
||||
|
||||
properties:
|
||||
qcom,decimation:
|
||||
enum: [ 85, 340, 1360 ]
|
||||
default: 1360
|
||||
|
||||
qcom,hw-settle-time:
|
||||
enum: [ 15, 100, 200, 300, 400, 500, 600, 700,
|
||||
1000, 2000, 4000, 8000, 16000, 32000, 64000, 128000 ]
|
||||
default: 15
|
||||
|
||||
qcom,avg-samples:
|
||||
enum: [ 1, 2, 4, 8, 16 ]
|
||||
default: 1
|
||||
|
||||
qcom,adc-tm:
|
||||
description:
|
||||
ADC_TM is a threshold monitoring feature in HW which can be enabled
|
||||
on any ADC channel, to trigger an IRQ for threshold violation. In
|
||||
earlier ADC generations, it was implemented in a separate device
|
||||
(documented in Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml.)
|
||||
In Gen3, this feature can be enabled in the same ADC device for any
|
||||
channel and threshold monitoring and IRQ triggering are handled in FW
|
||||
(PBS) instead of another dedicated HW block.
|
||||
This property indicates ADC_TM monitoring is done on this channel.
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- "#io-channel-cells"
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
pmic {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@9000 {
|
||||
compatible = "qcom,spmi-adc5-gen3";
|
||||
reg = <0x9000>, <0x9100>;
|
||||
interrupts = <0x0 0x90 0x1 IRQ_TYPE_EDGE_RISING>,
|
||||
<0x0 0x91 0x1 IRQ_TYPE_EDGE_RISING>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#io-channel-cells = <1>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
|
||||
/* PMK8550 Channel nodes */
|
||||
channel@3 {
|
||||
reg = <0x3>;
|
||||
label = "pmk8550_die_temp";
|
||||
qcom,pre-scaling = <1 1>;
|
||||
};
|
||||
|
||||
channel@44 {
|
||||
reg = <0x44>;
|
||||
label = "pmk8550_xo_therm";
|
||||
qcom,pre-scaling = <1 1>;
|
||||
qcom,ratiometric;
|
||||
qcom,hw-settle-time = <200>;
|
||||
qcom,adc-tm;
|
||||
};
|
||||
|
||||
/* PM8550 Channel nodes */
|
||||
channel@103 {
|
||||
reg = <0x103>;
|
||||
label = "pm8550_die_temp";
|
||||
qcom,pre-scaling = <1 1>;
|
||||
};
|
||||
|
||||
/* PM8550B Channel nodes */
|
||||
channel@78f {
|
||||
reg = <0x78f>;
|
||||
label = "pm8550b_vbat_sns_qbg";
|
||||
qcom,pre-scaling = <1 3>;
|
||||
};
|
||||
|
||||
/* PM8550VS_C Channel nodes */
|
||||
channel@203 {
|
||||
reg = <0x203>;
|
||||
label = "pm8550vs_c_die_temp";
|
||||
qcom,pre-scaling = <1 1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/qcom,spmi-vadc-common.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Technologies, Inc. SPMI PMIC ADC channels
|
||||
|
||||
maintainers:
|
||||
- Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
|
||||
|
||||
description:
|
||||
This defines the common properties used to define Qualcomm VADC channels.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description:
|
||||
ADC channel number (PMIC-specific for versions after PMIC5 ADC).
|
||||
maxItems: 1
|
||||
|
||||
label:
|
||||
description:
|
||||
ADC input of the platform as seen in the schematics.
|
||||
For thermistor inputs connected to generic AMUX or GPIO inputs
|
||||
these can vary across platform for the same pins. Hence select
|
||||
the platform schematics name for this channel.
|
||||
|
||||
qcom,decimation:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
This parameter is used to decrease ADC sampling rate.
|
||||
Quicker measurements can be made by reducing decimation ratio.
|
||||
|
||||
qcom,pre-scaling:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description:
|
||||
Used for scaling the channel input signal before the signal is
|
||||
fed to VADC. The configuration for this node is to know the
|
||||
pre-determined ratio and use it for post scaling. It is a pair of
|
||||
integers, denoting the numerator and denominator of the fraction by which
|
||||
input signal is multiplied. For example, <1 3> indicates the signal is scaled
|
||||
down to 1/3 of its value before ADC measurement.
|
||||
If property is not found default value depending on chip will be used.
|
||||
oneOf:
|
||||
- items:
|
||||
- const: 1
|
||||
- enum: [ 1, 3, 4, 6, 20, 8, 10, 16 ]
|
||||
- items:
|
||||
- const: 10
|
||||
- const: 81
|
||||
|
||||
qcom,ratiometric:
|
||||
type: boolean
|
||||
description: |
|
||||
Channel calibration type.
|
||||
- For compatible property "qcom,spmi-vadc", if this property is
|
||||
specified VADC will use the VDD reference (1.8V) and GND for
|
||||
channel calibration. If property is not found, channel will be
|
||||
calibrated with 0.625V and 1.25V reference channels, also
|
||||
known as absolute calibration.
|
||||
- For other compatible properties, if this property is specified
|
||||
VADC will use the VDD reference (1.875V) and GND for channel
|
||||
calibration. If property is not found, channel will be calibrated
|
||||
with 0V and 1.25V reference channels, also known as absolute calibration.
|
||||
|
||||
qcom,hw-settle-time:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Time between AMUX getting configured and the ADC starting
|
||||
conversion. The 'hw_settle_time' is an index used from valid values
|
||||
and programmed in hardware to achieve the hardware settling delay.
|
||||
|
||||
qcom,avg-samples:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Number of samples to be used for measurement.
|
||||
Averaging provides the option to obtain a single measurement
|
||||
from the ADC that is an average of multiple samples. The value
|
||||
selected is 2^(value).
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
additionalProperties: true
|
||||
@@ -15,6 +15,8 @@ description: |
|
||||
voltage. The VADC is a 15-bit sigma-delta ADC.
|
||||
SPMI PMIC5/PMIC7 voltage ADC (ADC) provides interface to clients to read
|
||||
voltage. The VADC is a 16-bit sigma-delta ADC.
|
||||
Note that PMIC7 ADC is the generation between PMIC5 and PMIC5 Gen3 ADC,
|
||||
it can be considered like PMIC5 Gen2.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@@ -56,7 +58,7 @@ required:
|
||||
patternProperties:
|
||||
"^channel@[0-9a-f]+$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
description: |
|
||||
Represents the external channels which are connected to the ADC.
|
||||
For compatible property "qcom,spmi-vadc" following channels, also known as
|
||||
@@ -64,79 +66,7 @@ patternProperties:
|
||||
configuration nodes should be defined:
|
||||
VADC_REF_625MV and/or VADC_SPARE1(based on PMIC version) VADC_REF_1250MV,
|
||||
VADC_GND_REF and VADC_VDD_VADC.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: |
|
||||
ADC channel number.
|
||||
See include/dt-bindings/iio/qcom,spmi-vadc.h
|
||||
For PMIC7 ADC, the channel numbers are specified separately per PMIC
|
||||
in the PMIC-specific files in include/dt-bindings/iio/.
|
||||
|
||||
label:
|
||||
description: |
|
||||
ADC input of the platform as seen in the schematics.
|
||||
For thermistor inputs connected to generic AMUX or GPIO inputs
|
||||
these can vary across platform for the same pins. Hence select
|
||||
the platform schematics name for this channel.
|
||||
|
||||
qcom,decimation:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
This parameter is used to decrease ADC sampling rate.
|
||||
Quicker measurements can be made by reducing decimation ratio.
|
||||
|
||||
qcom,pre-scaling:
|
||||
description: |
|
||||
Used for scaling the channel input signal before the signal is
|
||||
fed to VADC. The configuration for this node is to know the
|
||||
pre-determined ratio and use it for post scaling. It is a pair of
|
||||
integers, denoting the numerator and denominator of the fraction by which
|
||||
input signal is multiplied. For example, <1 3> indicates the signal is scaled
|
||||
down to 1/3 of its value before ADC measurement.
|
||||
If property is not found default value depending on chip will be used.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
oneOf:
|
||||
- items:
|
||||
- const: 1
|
||||
- enum: [ 1, 3, 4, 6, 20, 8, 10, 16 ]
|
||||
- items:
|
||||
- const: 10
|
||||
- const: 81
|
||||
|
||||
qcom,ratiometric:
|
||||
description: |
|
||||
Channel calibration type.
|
||||
- For compatible property "qcom,spmi-vadc", if this property is
|
||||
specified VADC will use the VDD reference (1.8V) and GND for
|
||||
channel calibration. If property is not found, channel will be
|
||||
calibrated with 0.625V and 1.25V reference channels, also
|
||||
known as absolute calibration.
|
||||
- For compatible property "qcom,spmi-adc5", "qcom,spmi-adc7" and
|
||||
"qcom,spmi-adc-rev2", if this property is specified VADC will use
|
||||
the VDD reference (1.875V) and GND for channel calibration. If
|
||||
property is not found, channel will be calibrated with 0V and 1.25V
|
||||
reference channels, also known as absolute calibration.
|
||||
type: boolean
|
||||
|
||||
qcom,hw-settle-time:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Time between AMUX getting configured and the ADC starting
|
||||
conversion. The 'hw_settle_time' is an index used from valid values
|
||||
and programmed in hardware to achieve the hardware settling delay.
|
||||
|
||||
qcom,avg-samples:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Number of samples to be used for measurement.
|
||||
Averaging provides the option to obtain a single measurement
|
||||
from the ADC that is an average of multiple samples. The value
|
||||
selected is 2^(value).
|
||||
|
||||
required:
|
||||
- reg
|
||||
$ref: /schemas/iio/adc/qcom,spmi-vadc-common.yaml
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
|
||||
101
Documentation/devicetree/bindings/iio/amplifiers/adi,ad8366.yaml
Normal file
101
Documentation/devicetree/bindings/iio/amplifiers/adi,ad8366.yaml
Normal file
@@ -0,0 +1,101 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/amplifiers/adi,ad8366.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: AD8366 and similar Gain Amplifiers and Digital Attenuators
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
- Rodrigo Alencar <rodrigo.alencar@analog.com>
|
||||
|
||||
description:
|
||||
Digital Variable Gain Amplifiers (VGAs) and Digital Attenuators with
|
||||
SPI interface.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad8366
|
||||
- adi,ada4961
|
||||
- adi,adl5240
|
||||
- adi,adrf5702
|
||||
- adi,adrf5703
|
||||
- adi,adrf5720
|
||||
- adi,adrf5730
|
||||
- adi,adrf5731
|
||||
- adi,hmc271a
|
||||
- adi,hmc792a
|
||||
- adi,hmc1018a
|
||||
- adi,hmc1019a
|
||||
- adi,hmc1119
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vcc-supply:
|
||||
description: Regulator that provides power to the device.
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
enable-gpios:
|
||||
maxItems: 1
|
||||
description: Power-up or Serial Mode Enable GPIO.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vcc-supply
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: adi,hmc271a
|
||||
then:
|
||||
properties:
|
||||
reset-gpios: false
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
anyOf:
|
||||
- const: adi,ad8366
|
||||
- const: adi,ada4961
|
||||
- const: adi,adrf5702
|
||||
- const: adi,adrf5703
|
||||
- const: adi,adrf5720
|
||||
- const: adi,adrf5730
|
||||
- const: adi,adrf5731
|
||||
- const: adi,hmc792a
|
||||
- const: adi,hmc1018a
|
||||
- const: adi,hmc1019a
|
||||
- const: adi,hmc1119
|
||||
then:
|
||||
properties:
|
||||
enable-gpios: false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
amplifier@0 {
|
||||
compatible = "adi,ad8366";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
vcc-supply = <&vcc_3v3>;
|
||||
enable-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -4,36 +4,49 @@
|
||||
$id: http://devicetree.org/schemas/iio/dac/lltc,ltc2632.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Linear Technology LTC263x 12-/10-/8-Bit Rail-to-Rail DAC
|
||||
title: Linear Technology LTC263x and LTC2654 Rail-to-Rail DAC
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
|
||||
description: |
|
||||
Bindings for the Linear Technology LTC2632/2634/2636 DAC
|
||||
Datasheet can be found here: https://www.analog.com/media/en/technical-documentation/data-sheets/LTC263[246].pdf
|
||||
Bindings for the Linear Technology LTC2632/2634/2636/2654 DAC
|
||||
Datasheet can be found here:
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/LTC263[246].pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/2654f.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- lltc,ltc2632-l12
|
||||
- lltc,ltc2632-l10
|
||||
- lltc,ltc2632-l8
|
||||
- lltc,ltc2632-h12
|
||||
- lltc,ltc2632-h10
|
||||
- lltc,ltc2632-h8
|
||||
- lltc,ltc2634-l12
|
||||
- lltc,ltc2634-l10
|
||||
- lltc,ltc2634-l8
|
||||
- lltc,ltc2634-h12
|
||||
- lltc,ltc2634-h10
|
||||
- lltc,ltc2634-h8
|
||||
- lltc,ltc2636-l12
|
||||
- lltc,ltc2636-l10
|
||||
- lltc,ltc2636-l8
|
||||
- lltc,ltc2636-h12
|
||||
- lltc,ltc2636-h10
|
||||
- lltc,ltc2636-h8
|
||||
oneOf:
|
||||
- enum:
|
||||
- lltc,ltc2632-l12
|
||||
- lltc,ltc2632-l10
|
||||
- lltc,ltc2632-l8
|
||||
- lltc,ltc2632-h12
|
||||
- lltc,ltc2632-h10
|
||||
- lltc,ltc2632-h8
|
||||
- lltc,ltc2634-l12
|
||||
- lltc,ltc2634-l10
|
||||
- lltc,ltc2634-l8
|
||||
- lltc,ltc2634-h12
|
||||
- lltc,ltc2634-h10
|
||||
- lltc,ltc2634-h8
|
||||
- lltc,ltc2636-l12
|
||||
- lltc,ltc2636-l10
|
||||
- lltc,ltc2636-l8
|
||||
- lltc,ltc2636-h12
|
||||
- lltc,ltc2636-h10
|
||||
- lltc,ltc2636-h8
|
||||
- lltc,ltc2654-l16
|
||||
- lltc,ltc2654-h16
|
||||
- items:
|
||||
- enum:
|
||||
- lltc,ltc2654-l12
|
||||
- const: lltc,ltc2634-l12
|
||||
- items:
|
||||
- enum:
|
||||
- lltc,ltc2654-h12
|
||||
- const: lltc,ltc2634-h12
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -4,18 +4,21 @@
|
||||
$id: http://devicetree.org/schemas/iio/dac/maxim,ds4424.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim Integrated DS4422/DS4424 7-bit Sink/Source Current DAC
|
||||
title: Maxim Integrated DS4402/DS4404 and DS4422/DS4424 Current DACs
|
||||
|
||||
maintainers:
|
||||
- Ismail Kose <ihkose@gmail.com>
|
||||
|
||||
description: |
|
||||
Datasheet publicly available at:
|
||||
Datasheets publicly available at:
|
||||
https://datasheets.maximintegrated.com/en/ds/DS4402-DS4404.pdf
|
||||
https://datasheets.maximintegrated.com/en/ds/DS4422-DS4424.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- maxim,ds4402
|
||||
- maxim,ds4404
|
||||
- maxim,ds4422
|
||||
- maxim,ds4424
|
||||
|
||||
@@ -24,9 +27,43 @@ properties:
|
||||
|
||||
vcc-supply: true
|
||||
|
||||
maxim,rfs-ohms:
|
||||
description: |
|
||||
Array of resistance values in Ohms for the external Rfs resistors
|
||||
connected to the FS pins. These values determine the full-scale
|
||||
output current. The actual resistance depends on the chip variant
|
||||
and specific hardware design requirements.
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- maxim,rfs-ohms
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- maxim,ds4402
|
||||
- maxim,ds4422
|
||||
then:
|
||||
properties:
|
||||
maxim,rfs-ohms:
|
||||
maxItems: 2
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- maxim,ds4404
|
||||
- maxim,ds4424
|
||||
then:
|
||||
properties:
|
||||
maxim,rfs-ohms:
|
||||
minItems: 4
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@@ -40,6 +77,7 @@ examples:
|
||||
compatible = "maxim,ds4424";
|
||||
reg = <0x10>; /* When A0, A1 pins are ground */
|
||||
vcc-supply = <&vcc_3v3>;
|
||||
maxim,rfs-ohms = <40000>, <40000>, <40000>, <40000>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
||||
@@ -9,7 +9,7 @@ title: Texas Instruments DAC7612 family of DACs
|
||||
description:
|
||||
The DAC7612 is a dual, 12-bit digital-to-analog converter (DAC) with
|
||||
guaranteed 12-bit monotonicity performance over the industrial temperature
|
||||
range. Is is programmable through an SPI interface.
|
||||
range. It is programmable through an SPI interface.
|
||||
|
||||
maintainers:
|
||||
- Ricardo Ribalda Delgado <ricardo@ribalda.com>
|
||||
|
||||
@@ -11,10 +11,14 @@ maintainers:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- bosch,bmg160
|
||||
- bosch,bmi055_gyro
|
||||
- bosch,bmi088_gyro
|
||||
oneOf:
|
||||
- enum:
|
||||
- bosch,bmg160
|
||||
- bosch,bmi055_gyro
|
||||
- bosch,bmi088_gyro
|
||||
- items:
|
||||
- const: bosch,bmx055-gyro
|
||||
- const: bosch,bmg160
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -18,16 +18,32 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- vishay,vcnl4000
|
||||
- vishay,vcnl4010
|
||||
- vishay,vcnl4020
|
||||
- vishay,vcnl4040
|
||||
- vishay,vcnl4200
|
||||
oneOf:
|
||||
- enum:
|
||||
- capella,cm36672p
|
||||
- vishay,vcnl4000
|
||||
- vishay,vcnl4010
|
||||
- vishay,vcnl4020
|
||||
- vishay,vcnl4040
|
||||
- vishay,vcnl4200
|
||||
- items:
|
||||
- const: capella,cm36686
|
||||
- const: vishay,vcnl4040
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply:
|
||||
description: Regulator providing power to the "VDD" pin.
|
||||
|
||||
vio-supply:
|
||||
description: Regulator providing power for pull-up of the I/O lines.
|
||||
Does not connect to the sensor directly, but is needed for the
|
||||
correct operation of the I2C and interrupt lines.
|
||||
|
||||
vled-supply:
|
||||
description: Regulator providing power to the IR anode pin.
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -49,6 +65,9 @@ examples:
|
||||
compatible = "vishay,vcnl4200";
|
||||
reg = <0x51>;
|
||||
proximity-near-level = <220>;
|
||||
vdd-supply = <®_vdd>;
|
||||
vio-supply = <®_vio>;
|
||||
vled-supply = <®_vled>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
||||
@@ -21,11 +21,15 @@ properties:
|
||||
description:
|
||||
Note the bmm150_magn is a deprecated compatible as this part contains only
|
||||
a magnetometer.
|
||||
enum:
|
||||
- bosch,bmc150_magn
|
||||
- bosch,bmc156_magn
|
||||
- bosch,bmm150
|
||||
- bosch,bmm150_magn
|
||||
oneOf:
|
||||
- enum:
|
||||
- bosch,bmc150_magn
|
||||
- bosch,bmc156_magn
|
||||
- bosch,bmm150
|
||||
- bosch,bmm150_magn
|
||||
- items:
|
||||
- const: bosch,bmx055-magn
|
||||
- const: bosch,bmc150_magn
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -4,14 +4,17 @@
|
||||
$id: http://devicetree.org/schemas/iio/proximity/st,vl53l0x.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ST VL53L0X ToF ranging sensor
|
||||
title: ST VL53L0X/VL53L1X ToF ranging sensor
|
||||
|
||||
maintainers:
|
||||
- Song Qiang <songqiang1304521@gmail.com>
|
||||
- Siratul Islam <email@sirat.me>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: st,vl53l0x
|
||||
enum:
|
||||
- st,vl53l0x
|
||||
- st,vl53l1x
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -21,6 +24,8 @@ properties:
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
description:
|
||||
Phandle to the XSHUT GPIO. Used for hardware reset.
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
@@ -28,6 +33,16 @@ required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: st,vl53l1x
|
||||
then:
|
||||
required:
|
||||
- vdd-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
@@ -38,8 +53,9 @@ examples:
|
||||
#size-cells = <0>;
|
||||
|
||||
proximity@29 {
|
||||
compatible = "st,vl53l0x";
|
||||
compatible = "st,vl53l1x";
|
||||
reg = <0x29>;
|
||||
vdd-supply = <®_3v3>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <23 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,9 @@ properties:
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
firmware-name:
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
@@ -65,6 +68,7 @@ examples:
|
||||
interrupt-parent = <&pio>;
|
||||
interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
|
||||
vdd-supply = <&pp1800_prox>;
|
||||
firmware-name = "hx9023s.bin";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
@@ -135,6 +135,7 @@ patternProperties:
|
||||
"^adc@[0-9a-f]+$":
|
||||
type: object
|
||||
oneOf:
|
||||
- $ref: /schemas/iio/adc/qcom,spmi-adc5-gen3.yaml#
|
||||
- $ref: /schemas/iio/adc/qcom,spmi-iadc.yaml#
|
||||
- $ref: /schemas/iio/adc/qcom,spmi-rradc.yaml#
|
||||
- $ref: /schemas/iio/adc/qcom,spmi-vadc.yaml#
|
||||
|
||||
@@ -92,6 +92,45 @@ Interleaved mode
|
||||
In this mode, both channels conversion results are bit interleaved one SDO line.
|
||||
As such the wiring is the same as `One lane mode`_.
|
||||
|
||||
SPI offload wiring
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block::
|
||||
|
||||
+-------------+ +-------------+
|
||||
| CNV |<-----+--| GPIO |
|
||||
| | +--| PWM0 |
|
||||
| | | |
|
||||
| | +--| PWM1 |
|
||||
| | | +-------------+
|
||||
| | +->| TRIGGER |
|
||||
| CS |<--------| CS |
|
||||
| | | |
|
||||
| ADC | | SPI |
|
||||
| | | |
|
||||
| SDI |<--------| SDO |
|
||||
| SDO |-------->| SDI |
|
||||
| SCLK |<--------| SCLK |
|
||||
+-------------+ +-------------+
|
||||
|
||||
In this mode, both the ``cnv-gpios`` and a ``pwms`` properties are required.
|
||||
The ``pwms`` property specifies the PWM that is connected to the ADC CNV pin.
|
||||
The SPI offload will have a ``trigger-sources`` property to indicate the SPI
|
||||
offload (PWM) trigger source. For AD4030 and similar ADCs, there are two
|
||||
possible data transfer zones for sample N. One of them (zone 1) starts after the
|
||||
data conversion for sample N is complete while the other one (zone 2) starts 9.8
|
||||
nanoseconds after the rising edge of CNV for sample N + 1.
|
||||
|
||||
The configuration depicted in the above diagram is intended to perform data
|
||||
transfer in zone 2. To achieve high sample rates while meeting ADC timing
|
||||
requirements, an offset is added between the rising edges of PWM0 and PWM1 to
|
||||
delay the SPI transfer until 9.8 nanoseconds after CNV rising edge. This
|
||||
requires a specialized PWM controller that can provide such an offset.
|
||||
The `AD4630-FMC HDL project`_, for example, can be configured to sample AD4030
|
||||
data during zone 2 data read window.
|
||||
|
||||
.. _AD4630-FMC HDL project: https://analogdevicesinc.github.io/hdl/projects/ad4630_fmc/index.html
|
||||
|
||||
SPI Clock mode
|
||||
--------------
|
||||
|
||||
|
||||
@@ -63,11 +63,11 @@ Clock Configuration
|
||||
|
||||
The AD7191 supports both internal and external clock sources:
|
||||
|
||||
- When CLKSEL pin is tied LOW: Uses internal 4.92MHz clock (no clock property
|
||||
- When CLKSEL pin is ACTIVE: Uses internal 4.92MHz clock (no clock property
|
||||
needed)
|
||||
- When CLKSEL pin is tied HIGH: Requires external clock source
|
||||
- When CLKSEL pin is INACTIVE: Requires external clock source
|
||||
- Can be a crystal between MCLK1 and MCLK2 pins
|
||||
- Or a CMOS-compatible clock driving MCLK2 pin
|
||||
- Or a CMOS-compatible clock driving MCLK1 pin and MCLK2 left unconnected
|
||||
- Must specify the "clocks" property in device tree when using external clock
|
||||
|
||||
SPI Interface Requirements
|
||||
|
||||
@@ -12,16 +12,21 @@ This driver supports Analog Device's ADXL345/375 on SPI/I2C bus.
|
||||
* `ADXL345 <https://www.analog.com/ADXL345>`_
|
||||
* `ADXL375 <https://www.analog.com/ADXL375>`_
|
||||
|
||||
The ADXL345 is a generic purpose low power, 3-axis accelerometer with selectable
|
||||
measurement ranges. The ADXL345 supports the ±2 g, ±4 g, ±8 g, and ±16 g ranges.
|
||||
The ADXL345 is a general-purpose, low-power, 3-axis accelerometer with selectable
|
||||
measurement ranges. The ADXL345 supports the following ranges:
|
||||
|
||||
- ±2g (approx. ±19.61 m/s^2)
|
||||
- ±4g (approx. ±39.23 m/s^2)
|
||||
- ±8g (approx. ±78.45 m/s^2)
|
||||
- ±16g (approx. ±156.91 m/s^2)
|
||||
|
||||
2. Device Attributes
|
||||
====================
|
||||
|
||||
Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:deviceX``,
|
||||
Each IIO device has a device folder under ``/sys/bus/iio/devices/iio:deviceX``,
|
||||
where X is the IIO index of the device. Under these folders reside a set of
|
||||
device files, depending on the characteristics and features of the hardware
|
||||
device in questions. These files are consistently generalized and documented in
|
||||
device in question. These files are consistently generalized and documented in
|
||||
the IIO ABI documentation.
|
||||
|
||||
The following table shows the ADXL345 related device files, found in the
|
||||
@@ -42,7 +47,7 @@ specific device folder path ``/sys/bus/iio/devices/iio:deviceX``.
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_x_raw | Raw X-axis accelerometer channel value. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_y_calibbias | y-axis acceleration offset correction |
|
||||
| in_accel_y_calibbias | Y-axis acceleration offset correction |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_y_raw | Raw Y-axis accelerometer channel value. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
@@ -68,7 +73,7 @@ present, simply assume its value is 0.
|
||||
+-------------------------------------+---------------------------+
|
||||
| Channel type | Measurement unit |
|
||||
+-------------------------------------+---------------------------+
|
||||
| Acceleration on X, Y, and Z axis | Meters per second squared |
|
||||
| Acceleration on X, Y, and Z axes | Meters per second squared |
|
||||
+-------------------------------------+---------------------------+
|
||||
|
||||
Sensor Events
|
||||
@@ -78,8 +83,8 @@ Specific IIO events are triggered by their corresponding interrupts. The sensor
|
||||
driver supports either none or a single active interrupt (INT) line, selectable
|
||||
from the two available options: INT1 or INT2. The active INT line should be
|
||||
specified in the device tree. If no INT line is configured, the sensor defaults
|
||||
to FIFO bypass mode, where event detection is disabled and only X, Y, and Z axis
|
||||
measurements are available.
|
||||
to FIFO bypass mode, where event detection is disabled and only individual
|
||||
X, Y, and Z axis measurements are available.
|
||||
|
||||
The table below lists the ADXL345-related device files located in the
|
||||
device-specific path: ``/sys/bus/iio/devices/iio:deviceX/events``.
|
||||
@@ -90,38 +95,52 @@ listed.
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| Event handle | Description |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_gesture_doubletap_en | Enable double tap detection on all axis |
|
||||
| in_accel_gesture_doubletap_en | Enable double tap detection on all axes |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_gesture_doubletap_reset_timeout | Double tap window in [us] |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_gesture_doubletap_tap2_min_delay | Double tap latent in [us] |
|
||||
| in_accel_gesture_doubletap_scale | Double tap gesture threshold scale. |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_gesture_doubletap_tap2_min_delay | Double tap latency in [us] |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_gesture_doubletap_value | Double tap threshold value |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_gesture_singletap_scale | Single tap gesture threshold scale. |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_gesture_singletap_timeout | Single tap duration in [us] |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_gesture_singletap_value | Single tap threshold value in 62.5/LSB |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_falling_period | Inactivity time in seconds |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_falling_value | Inactivity threshold value in 62.5/LSB |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_adaptive_rising_en | Enable AC coupled activity on X axis |
|
||||
| in_accel_gesture_singletap_value | Single tap threshold value |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_adaptive_falling_period | AC coupled inactivity time in seconds |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_adaptive_falling_value | AC coupled inactivity threshold in 62.5/LSB |
|
||||
| in_accel_mag_adaptive_falling_scale | AC coupled inactivity threshold scale. |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_adaptive_rising_value | AC coupled activity threshold in 62.5/LSB |
|
||||
| in_accel_mag_adaptive_falling_value | AC coupled inactivity threshold |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_adaptive_rising_en | Enable AC coupled activity on X axis |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_adaptive_rising_scale | AC coupled activity threshold scale. |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_adaptive_rising_value | AC coupled activity threshold |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_falling_period | Inactivity time in seconds |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_falling_scale | DC coupled inactivity threshold scale. |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_falling_value | Inactivity threshold value |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_rising_en | Enable activity detection on X axis |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_rising_value | Activity threshold value in 62.5/LSB |
|
||||
| in_accel_mag_rising_scale | DC coupled activity threshold scale. |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_mag_rising_value | Activity threshold value |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_x&y&z_mag_adaptive_falling_en | Enable AC coupled inactivity on all axes |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_x&y&z_mag_falling_en | Enable inactivity detection on all axes |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_x_gesture_singletap_en | Enable single tap detection on X axis |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_x&y&z_mag_falling_en | Enable inactivity detection on all axis |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_x&y&z_mag_adaptive_falling_en | Enable AC coupled inactivity on all axis |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_y_gesture_singletap_en | Enable single tap detection on Y axis |
|
||||
+---------------------------------------------+---------------------------------------------+
|
||||
| in_accel_z_gesture_singletap_en | Enable single tap detection on Z axis |
|
||||
@@ -140,8 +159,8 @@ When changing the **g range** configuration, the driver attempts to estimate
|
||||
appropriate activity and inactivity thresholds by scaling the default values
|
||||
based on the ratio of the previous range to the new one. The resulting threshold
|
||||
will never be zero and will always fall between 1 and 255, corresponding to up
|
||||
to 62.5 g/LSB as specified in the datasheet. However, you can override these
|
||||
estimated thresholds by setting explicit values.
|
||||
to 62.5 mg/LSB (0.612915 m/s^2/LSB) as specified in the datasheet. However,
|
||||
you can override these estimated thresholds by setting explicit values.
|
||||
|
||||
When **activity** and **inactivity** events are enabled, the driver
|
||||
automatically manages hysteresis behavior by setting the **link** and
|
||||
@@ -270,13 +289,13 @@ Scale range configuration:
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_scale
|
||||
0.478899
|
||||
0.004789
|
||||
root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_scale_available
|
||||
0.478899 0.957798 1.915595 3.831190
|
||||
0.004789 0.009578 0.019156 0.038312
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1.915595 > ./in_accel_scale
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 0.019156 > ./in_accel_scale
|
||||
root:/sys/bus/iio/devices/iio:device0> cat ./in_accel_scale
|
||||
1.915595
|
||||
0.019156
|
||||
|
||||
Set output data rate (ODR):
|
||||
|
||||
@@ -312,10 +331,14 @@ Configure one or several events:
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 24 > ./buffer0/length
|
||||
|
||||
## AC coupled activity, threshold [62.5/LSB]
|
||||
## Check the event scale factor (0.0625 * 9.80665)
|
||||
root:/sys/bus/iio/devices/iio:device0> cat ./events/in_accel_gesture_doubletap_scale
|
||||
0.612915
|
||||
|
||||
## AC coupled activity, threshold [0.612915 m/s^2/LSB]
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 6 > ./events/in_accel_mag_adaptive_rising_value
|
||||
|
||||
## AC coupled inactivity, threshold, [62.5/LSB]
|
||||
## AC coupled inactivity, threshold, [0.612915 m/s^2/LSB]
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 4 > ./events/in_accel_mag_adaptive_falling_value
|
||||
|
||||
## AC coupled inactivity, time [s]
|
||||
@@ -330,7 +353,7 @@ Configure one or several events:
|
||||
## doubletap, window [us]
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 0.025 > ./events/in_accel_gesture_doubletap_reset_timeout
|
||||
|
||||
## doubletap, latent [us]
|
||||
## doubletap, latency [us]
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 0.025 > ./events/in_accel_gesture_doubletap_tap2_min_delay
|
||||
|
||||
## AC coupled activity, enable
|
||||
|
||||
29
MAINTAINERS
29
MAINTAINERS
@@ -651,8 +651,11 @@ W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml
|
||||
F: drivers/iio/accel/adxl367*
|
||||
|
||||
ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
|
||||
ADXL371/ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
|
||||
M: Michael Hennerich <michael.hennerich@analog.com>
|
||||
M: Marcelo Schmitt <marcelo.schmitt@analog.com>
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
M: Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml
|
||||
@@ -1591,6 +1594,15 @@ W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
|
||||
F: drivers/iio/adc/ad7780.c
|
||||
|
||||
ANALOG DEVICES INC AD8366 DRIVER
|
||||
M: Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
M: Rodrigo Alencar <rodrigo.alencar@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/amplifiers/adi,ad8366.yaml
|
||||
F: drivers/iio/amplifiers/ad8366.c
|
||||
|
||||
ANALOG DEVICES INC AD9467 DRIVER
|
||||
M: Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
M: Nuno Sa <nuno.sa@analog.com>
|
||||
@@ -1699,6 +1711,14 @@ S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/imu/adi,adis16550.yaml
|
||||
|
||||
ANALOG DEVICES INC ADL8113 DRIVER
|
||||
M: Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/amplifiers/adi,adl8113.yaml
|
||||
F: drivers/iio/amplifiers/adl8113.c
|
||||
|
||||
ANALOG DEVICES INC ADM1177 DRIVER
|
||||
M: Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
@@ -25085,6 +25105,13 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/proximity/st,vl53l0x.yaml
|
||||
F: drivers/iio/proximity/vl53l0x-i2c.c
|
||||
|
||||
ST VL53L1X ToF RANGER(I2C) IIO DRIVER
|
||||
M: Siratul Islam <email@sirat.me>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/proximity/st,vl53l0x.yaml
|
||||
F: drivers/iio/proximity/vl53l1x-i2c.c
|
||||
|
||||
STABLE BRANCH
|
||||
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
M: Sasha Levin <sashal@kernel.org>
|
||||
|
||||
@@ -158,24 +158,24 @@ config ADXL372
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
|
||||
config ADXL372_SPI
|
||||
tristate "Analog Devices ADXL372 3-Axis Accelerometer SPI Driver"
|
||||
tristate "Analog Devices ADXL371/ADXL372 3-Axis Accelerometer SPI Driver"
|
||||
depends on SPI
|
||||
select ADXL372
|
||||
select REGMAP_SPI
|
||||
help
|
||||
Say yes here to add support for the Analog Devices ADXL372 triaxial
|
||||
acceleration sensor.
|
||||
Say yes here to add support for the Analog Devices ADXL371/ADXL372
|
||||
triaxial acceleration sensor.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adxl372_spi.
|
||||
|
||||
config ADXL372_I2C
|
||||
tristate "Analog Devices ADXL372 3-Axis Accelerometer I2C Driver"
|
||||
tristate "Analog Devices ADXL371/ADXL372 3-Axis Accelerometer I2C Driver"
|
||||
depends on I2C
|
||||
select ADXL372
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say yes here to add support for the Analog Devices ADXL372 triaxial
|
||||
acceleration sensor.
|
||||
Say yes here to add support for the Analog Devices ADXL371/ADXL372
|
||||
triaxial acceleration sensor.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adxl372_i2c.
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
|
||||
/*
|
||||
* The raw ADC value is 1278 when the temperature
|
||||
* is 25 degrees and the scale factor per milli
|
||||
* degree celcius is -470.
|
||||
* degree Celsius is -470.
|
||||
*/
|
||||
*val = 25000 / -470 - 1278;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
@@ -186,7 +186,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
|
||||
/*
|
||||
* The raw ADC value is 0x4FE when the temperature
|
||||
* is 45 degrees and the scale factor per milli
|
||||
* degree celcius is -470.
|
||||
* degree Celsius is -470.
|
||||
*/
|
||||
*val = 25000 / -470 - 0x4FE;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/overflow.h>
|
||||
@@ -356,19 +357,15 @@ static int adxl313_read_axis(struct adxl313_data *data,
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
guard(mutex)(&data->lock);
|
||||
|
||||
ret = regmap_bulk_read(data->regmap,
|
||||
ADXL313_REG_DATA_AXIS(chan->address),
|
||||
&data->transf_buf, sizeof(data->transf_buf));
|
||||
if (ret)
|
||||
goto unlock_ret;
|
||||
return ret;
|
||||
|
||||
ret = le16_to_cpu(data->transf_buf);
|
||||
|
||||
unlock_ret:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
return le16_to_cpu(data->transf_buf);
|
||||
}
|
||||
|
||||
static int adxl313_read_freq_avail(struct iio_dev *indio_dev,
|
||||
|
||||
@@ -213,6 +213,7 @@ static const struct iio_event_spec adxl345_events[] = {
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_shared_by_type =
|
||||
BIT(IIO_EV_INFO_ENABLE) |
|
||||
BIT(IIO_EV_INFO_SCALE) |
|
||||
BIT(IIO_EV_INFO_VALUE),
|
||||
},
|
||||
{
|
||||
@@ -221,6 +222,7 @@ static const struct iio_event_spec adxl345_events[] = {
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_shared_by_type =
|
||||
BIT(IIO_EV_INFO_ENABLE) |
|
||||
BIT(IIO_EV_INFO_SCALE) |
|
||||
BIT(IIO_EV_INFO_VALUE),
|
||||
},
|
||||
{
|
||||
@@ -228,14 +230,19 @@ static const struct iio_event_spec adxl345_events[] = {
|
||||
.type = IIO_EV_TYPE_GESTURE,
|
||||
.dir = IIO_EV_DIR_SINGLETAP,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
|
||||
.mask_shared_by_type =
|
||||
BIT(IIO_EV_INFO_SCALE) |
|
||||
BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_TIMEOUT),
|
||||
},
|
||||
{
|
||||
/* double tap */
|
||||
.type = IIO_EV_TYPE_GESTURE,
|
||||
.dir = IIO_EV_DIR_DOUBLETAP,
|
||||
.mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
|
||||
.mask_shared_by_type =
|
||||
BIT(IIO_EV_INFO_ENABLE) |
|
||||
BIT(IIO_EV_INFO_SCALE) |
|
||||
BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_RESET_TIMEOUT) |
|
||||
BIT(IIO_EV_INFO_TAP2_MIN_DELAY),
|
||||
},
|
||||
@@ -274,6 +281,7 @@ static const struct iio_event_spec adxl345_fake_chan_events[] = {
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
.mask_shared_by_type =
|
||||
BIT(IIO_EV_INFO_SCALE) |
|
||||
BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_PERIOD),
|
||||
},
|
||||
@@ -283,6 +291,7 @@ static const struct iio_event_spec adxl345_fake_chan_events[] = {
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
.mask_shared_by_type =
|
||||
BIT(IIO_EV_INFO_SCALE) |
|
||||
BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_PERIOD),
|
||||
},
|
||||
@@ -1341,6 +1350,16 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev,
|
||||
unsigned int tap_threshold;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The event threshold LSB is fixed at 62.5 mg/LSB
|
||||
* 0.0625 * 9.80665 = 0.612915625 m/s^2
|
||||
*/
|
||||
if (info == IIO_EV_INFO_SCALE) {
|
||||
*val = 0;
|
||||
*val2 = 612915;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG:
|
||||
return adxl345_read_mag_value(st, dir, info,
|
||||
@@ -1355,12 +1374,6 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev,
|
||||
case IIO_EV_TYPE_GESTURE:
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
/*
|
||||
* The scale factor would be 62.5mg/LSB (i.e. 0xFF = 16g) but
|
||||
* not applied here. In context of this general purpose sensor,
|
||||
* what imports is rather signal intensity than the absolute
|
||||
* measured g value.
|
||||
*/
|
||||
ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP,
|
||||
&tap_threshold);
|
||||
if (ret)
|
||||
@@ -1401,6 +1414,9 @@ static int adxl345_write_event_value(struct iio_dev *indio_dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (info == IIO_EV_INFO_SCALE)
|
||||
return -EINVAL;
|
||||
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG:
|
||||
ret = adxl345_write_mag_value(st, dir, info,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ADXL372 3-Axis Digital Accelerometer core driver
|
||||
* ADXL371/ADXL372 3-Axis Digital Accelerometer core driver
|
||||
*
|
||||
* Copyright 2018 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
@@ -180,6 +181,16 @@ enum adxl372_odr {
|
||||
ADXL372_ODR_1600HZ,
|
||||
ADXL372_ODR_3200HZ,
|
||||
ADXL372_ODR_6400HZ,
|
||||
ADXL372_ODR_NUM
|
||||
};
|
||||
|
||||
enum adxl371_odr {
|
||||
ADXL371_ODR_320HZ,
|
||||
ADXL371_ODR_640HZ,
|
||||
ADXL371_ODR_1280HZ,
|
||||
ADXL371_ODR_2560HZ,
|
||||
ADXL371_ODR_5120HZ,
|
||||
ADXL371_ODR_NUM
|
||||
};
|
||||
|
||||
enum adxl372_bandwidth {
|
||||
@@ -214,14 +225,67 @@ enum adxl372_fifo_mode {
|
||||
ADXL372_FIFO_OLD_SAVED
|
||||
};
|
||||
|
||||
static const int adxl372_samp_freq_tbl[5] = {
|
||||
400, 800, 1600, 3200, 6400,
|
||||
static const int adxl372_samp_freq_tbl[ADXL372_ODR_NUM] = {
|
||||
[ADXL372_ODR_400HZ] = 400,
|
||||
[ADXL372_ODR_800HZ] = 800,
|
||||
[ADXL372_ODR_1600HZ] = 1600,
|
||||
[ADXL372_ODR_3200HZ] = 3200,
|
||||
[ADXL372_ODR_6400HZ] = 6400,
|
||||
};
|
||||
|
||||
static const int adxl372_bw_freq_tbl[5] = {
|
||||
200, 400, 800, 1600, 3200,
|
||||
static const int adxl372_bw_freq_tbl[ADXL372_ODR_NUM] = {
|
||||
[ADXL372_BW_200HZ] = 200,
|
||||
[ADXL372_BW_400HZ] = 400,
|
||||
[ADXL372_BW_800HZ] = 800,
|
||||
[ADXL372_BW_1600HZ] = 1600,
|
||||
[ADXL372_BW_3200HZ] = 3200,
|
||||
};
|
||||
|
||||
static const int adxl371_samp_freq_tbl[ADXL371_ODR_NUM] = {
|
||||
[ADXL371_ODR_320HZ] = 320,
|
||||
[ADXL371_ODR_640HZ] = 640,
|
||||
[ADXL371_ODR_1280HZ] = 1280,
|
||||
[ADXL371_ODR_2560HZ] = 2560,
|
||||
[ADXL371_ODR_5120HZ] = 5120,
|
||||
};
|
||||
|
||||
static const int adxl371_bw_freq_tbl[ADXL371_ODR_NUM] = {
|
||||
[ADXL371_ODR_320HZ] = 160,
|
||||
[ADXL371_ODR_640HZ] = 320,
|
||||
[ADXL371_ODR_1280HZ] = 640,
|
||||
[ADXL371_ODR_2560HZ] = 1280,
|
||||
[ADXL371_ODR_5120HZ] = 2560,
|
||||
};
|
||||
|
||||
const struct adxl372_chip_info adxl371_chip_info = {
|
||||
.name = "adxl371",
|
||||
.samp_freq_tbl = adxl371_samp_freq_tbl,
|
||||
.bw_freq_tbl = adxl371_bw_freq_tbl,
|
||||
.num_freqs = ARRAY_SIZE(adxl371_samp_freq_tbl),
|
||||
.act_time_scale_us = 4125,
|
||||
.act_time_scale_low_us = 8250,
|
||||
.inact_time_scale_ms = 16,
|
||||
.inact_time_scale_low_ms = 32,
|
||||
.max_odr = ADXL371_ODR_5120HZ,
|
||||
/* Silicon erratum (er001) causes FIFO data misalignment on ADXL371 */
|
||||
.fifo_supported = false,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(adxl371_chip_info, "IIO_ADXL372");
|
||||
|
||||
const struct adxl372_chip_info adxl372_chip_info = {
|
||||
.name = "adxl372",
|
||||
.samp_freq_tbl = adxl372_samp_freq_tbl,
|
||||
.bw_freq_tbl = adxl372_bw_freq_tbl,
|
||||
.num_freqs = ARRAY_SIZE(adxl372_samp_freq_tbl),
|
||||
.act_time_scale_us = 3300,
|
||||
.act_time_scale_low_us = 6600,
|
||||
.inact_time_scale_ms = 13,
|
||||
.inact_time_scale_low_ms = 26,
|
||||
.max_odr = ADXL372_ODR_6400HZ,
|
||||
.fifo_supported = true,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(adxl372_chip_info, "IIO_ADXL372");
|
||||
|
||||
struct adxl372_axis_lookup {
|
||||
unsigned int bits;
|
||||
enum adxl372_fifo_format fifo_format;
|
||||
@@ -257,8 +321,12 @@ static const struct iio_event_spec adxl372_events[] = {
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
|
||||
.info_mask_shared_by_type = \
|
||||
BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
|
||||
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
|
||||
.info_mask_shared_by_type_available = \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
|
||||
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
|
||||
.scan_index = index, \
|
||||
.scan_type = { \
|
||||
@@ -279,6 +347,7 @@ static const struct iio_chan_spec adxl372_channels[] = {
|
||||
};
|
||||
|
||||
struct adxl372_state {
|
||||
const struct adxl372_chip_info *chip_info;
|
||||
int irq;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
@@ -336,18 +405,14 @@ static ssize_t adxl372_write_threshold_value(struct iio_dev *indio_dev, unsigned
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->threshold_m);
|
||||
guard(mutex)(&st->threshold_m);
|
||||
|
||||
ret = regmap_write(st->regmap, addr, ADXL372_THRESH_VAL_H_SEL(threshold));
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5),
|
||||
ADXL372_THRESH_VAL_L_SEL(threshold) << 5);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&st->threshold_m);
|
||||
|
||||
return ret;
|
||||
return regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5),
|
||||
ADXL372_THRESH_VAL_L_SEL(threshold) << 5);
|
||||
}
|
||||
|
||||
static int adxl372_read_axis(struct adxl372_state *st, u8 addr)
|
||||
@@ -471,13 +536,14 @@ static int adxl372_set_activity_time_ms(struct adxl372_state *st,
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* 3.3 ms per code is the scale factor of the TIME_ACT register for
|
||||
* ODR = 6400 Hz. It is 6.6 ms per code for ODR = 3200 Hz and below.
|
||||
* The scale factor of the TIME_ACT register depends on the ODR.
|
||||
* A higher scale factor is used at the maximum ODR and a lower
|
||||
* one at all other rates.
|
||||
*/
|
||||
if (st->odr == ADXL372_ODR_6400HZ)
|
||||
scale_factor = 3300;
|
||||
if (st->odr == st->chip_info->max_odr)
|
||||
scale_factor = st->chip_info->act_time_scale_us;
|
||||
else
|
||||
scale_factor = 6600;
|
||||
scale_factor = st->chip_info->act_time_scale_low_us;
|
||||
|
||||
reg_val = DIV_ROUND_CLOSEST(act_time_ms * 1000, scale_factor);
|
||||
|
||||
@@ -501,13 +567,14 @@ static int adxl372_set_inactivity_time_ms(struct adxl372_state *st,
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* 13 ms per code is the scale factor of the TIME_INACT register for
|
||||
* ODR = 6400 Hz. It is 26 ms per code for ODR = 3200 Hz and below.
|
||||
* The scale factor of the TIME_INACT register depends on the ODR.
|
||||
* A higher scale factor is used at the maximum ODR and a lower
|
||||
* one at all other rates.
|
||||
*/
|
||||
if (st->odr == ADXL372_ODR_6400HZ)
|
||||
scale_factor = 13;
|
||||
if (st->odr == st->chip_info->max_odr)
|
||||
scale_factor = st->chip_info->inact_time_scale_ms;
|
||||
else
|
||||
scale_factor = 26;
|
||||
scale_factor = st->chip_info->inact_time_scale_low_ms;
|
||||
|
||||
res = DIV_ROUND_CLOSEST(inact_time_ms, scale_factor);
|
||||
reg_val_h = (res >> 8) & 0xFF;
|
||||
@@ -717,7 +784,7 @@ static int adxl372_setup(struct adxl372_state *st)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = adxl372_set_odr(st, ADXL372_ODR_6400HZ);
|
||||
ret = adxl372_set_odr(st, st->chip_info->max_odr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -777,10 +844,10 @@ static int adxl372_read_raw(struct iio_dev *indio_dev,
|
||||
*val2 = ADXL372_USCALE;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = adxl372_samp_freq_tbl[st->odr];
|
||||
*val = st->chip_info->samp_freq_tbl[st->odr];
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
*val = adxl372_bw_freq_tbl[st->bw];
|
||||
*val = st->chip_info->bw_freq_tbl[st->bw];
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
@@ -796,23 +863,17 @@ static int adxl372_write_raw(struct iio_dev *indio_dev,
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
odr_index = adxl372_find_closest_match(adxl372_samp_freq_tbl,
|
||||
ARRAY_SIZE(adxl372_samp_freq_tbl),
|
||||
val);
|
||||
odr_index = adxl372_find_closest_match(st->chip_info->samp_freq_tbl,
|
||||
st->chip_info->num_freqs,
|
||||
val);
|
||||
ret = adxl372_set_odr(st, odr_index);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/*
|
||||
* The timer period depends on the ODR selected.
|
||||
* At 3200 Hz and below, it is 6.6 ms; at 6400 Hz, it is 3.3 ms
|
||||
*/
|
||||
/* Recalculate activity time as the timer period depends on ODR */
|
||||
ret = adxl372_set_activity_time_ms(st, st->act_time_ms);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/*
|
||||
* The timer period depends on the ODR selected.
|
||||
* At 3200 Hz and below, it is 26 ms; at 6400 Hz, it is 13 ms
|
||||
*/
|
||||
/* Recalculate inactivity time as the timer period depends on ODR */
|
||||
ret = adxl372_set_inactivity_time_ms(st, st->inact_time_ms);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -825,9 +886,9 @@ static int adxl372_write_raw(struct iio_dev *indio_dev,
|
||||
|
||||
return ret;
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
bw_index = adxl372_find_closest_match(adxl372_bw_freq_tbl,
|
||||
ARRAY_SIZE(adxl372_bw_freq_tbl),
|
||||
val);
|
||||
bw_index = adxl372_find_closest_match(st->chip_info->bw_freq_tbl,
|
||||
st->chip_info->num_freqs,
|
||||
val);
|
||||
return adxl372_set_bandwidth(st, bw_index);
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -957,24 +1018,6 @@ static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct ii
|
||||
return adxl372_set_interrupts(st, st->int1_bitmask, 0);
|
||||
}
|
||||
|
||||
static ssize_t adxl372_show_filter_freq_avail(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
int i;
|
||||
size_t len = 0;
|
||||
|
||||
for (i = 0; i <= st->odr; i++)
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len,
|
||||
"%d ", adxl372_bw_freq_tbl[i]);
|
||||
|
||||
buf[len - 1] = '\n';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t adxl372_get_fifo_enabled(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
@@ -1142,25 +1185,38 @@ static const struct iio_trigger_ops adxl372_peak_data_trigger_ops = {
|
||||
.set_trigger_state = adxl372_peak_dready_trig_set_state,
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400");
|
||||
static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available,
|
||||
0444, adxl372_show_filter_freq_avail, NULL, 0);
|
||||
static int adxl372_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length,
|
||||
long mask)
|
||||
{
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
|
||||
static struct attribute *adxl372_attributes[] = {
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group adxl372_attrs_group = {
|
||||
.attrs = adxl372_attributes,
|
||||
};
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*vals = st->chip_info->samp_freq_tbl;
|
||||
*type = IIO_VAL_INT;
|
||||
*length = st->chip_info->num_freqs;
|
||||
return IIO_AVAIL_LIST;
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
*vals = st->chip_info->bw_freq_tbl;
|
||||
*type = IIO_VAL_INT;
|
||||
/*
|
||||
* Bandwidth cannot exceed half the sampling frequency
|
||||
* (Nyquist), so limit available values based on current ODR.
|
||||
*/
|
||||
*length = st->odr + 1;
|
||||
return IIO_AVAIL_LIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info adxl372_info = {
|
||||
.validate_trigger = &adxl372_validate_trigger,
|
||||
.attrs = &adxl372_attrs_group,
|
||||
.read_raw = adxl372_read_raw,
|
||||
.write_raw = adxl372_write_raw,
|
||||
.read_avail = adxl372_read_avail,
|
||||
.read_event_config = adxl372_read_event_config,
|
||||
.write_event_config = adxl372_write_event_config,
|
||||
.read_event_value = adxl372_read_event_value,
|
||||
@@ -1175,8 +1231,57 @@ bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg)
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adxl372_readable_noinc_reg, "IIO_ADXL372");
|
||||
|
||||
static int adxl372_buffer_setup(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct adxl372_state *st = iio_priv(indio_dev);
|
||||
struct device *dev = st->dev;
|
||||
int ret;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup_ext(dev, indio_dev, NULL,
|
||||
adxl372_trigger_handler,
|
||||
IIO_BUFFER_DIRECTION_IN,
|
||||
&adxl372_buffer_ops,
|
||||
adxl372_fifo_attributes);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!st->irq)
|
||||
return 0;
|
||||
|
||||
st->dready_trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
|
||||
indio_dev->name,
|
||||
iio_device_id(indio_dev));
|
||||
if (!st->dready_trig)
|
||||
return -ENOMEM;
|
||||
|
||||
st->peak_datardy_trig = devm_iio_trigger_alloc(dev, "%s-dev%d-peak",
|
||||
indio_dev->name,
|
||||
iio_device_id(indio_dev));
|
||||
if (!st->peak_datardy_trig)
|
||||
return -ENOMEM;
|
||||
|
||||
st->dready_trig->ops = &adxl372_trigger_ops;
|
||||
st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops;
|
||||
iio_trigger_set_drvdata(st->dready_trig, indio_dev);
|
||||
iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev);
|
||||
ret = devm_iio_trigger_register(dev, st->dready_trig);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_trigger_register(dev, st->peak_datardy_trig);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->trig = iio_trigger_get(st->dready_trig);
|
||||
|
||||
return devm_request_irq(dev, st->irq,
|
||||
iio_trigger_generic_data_rdy_poll,
|
||||
IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
|
||||
indio_dev->name, st->dready_trig);
|
||||
}
|
||||
|
||||
int adxl372_probe(struct device *dev, struct regmap *regmap,
|
||||
int irq, const char *name)
|
||||
int irq, const struct adxl372_chip_info *chip_info)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct adxl372_state *st;
|
||||
@@ -1192,15 +1297,21 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
|
||||
st->dev = dev;
|
||||
st->regmap = regmap;
|
||||
st->irq = irq;
|
||||
st->chip_info = chip_info;
|
||||
|
||||
mutex_init(&st->threshold_m);
|
||||
|
||||
indio_dev->channels = adxl372_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adxl372_channels);
|
||||
indio_dev->available_scan_masks = adxl372_channel_masks;
|
||||
indio_dev->name = name;
|
||||
indio_dev->name = chip_info->name;
|
||||
indio_dev->info = &adxl372_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
|
||||
|
||||
if (chip_info->fifo_supported) {
|
||||
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
|
||||
indio_dev->available_scan_masks = adxl372_channel_masks;
|
||||
} else {
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
}
|
||||
|
||||
ret = adxl372_setup(st);
|
||||
if (ret < 0) {
|
||||
@@ -1208,48 +1319,8 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup_ext(dev,
|
||||
indio_dev, NULL,
|
||||
adxl372_trigger_handler,
|
||||
IIO_BUFFER_DIRECTION_IN,
|
||||
&adxl372_buffer_ops,
|
||||
adxl372_fifo_attributes);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (st->irq) {
|
||||
st->dready_trig = devm_iio_trigger_alloc(dev,
|
||||
"%s-dev%d",
|
||||
indio_dev->name,
|
||||
iio_device_id(indio_dev));
|
||||
if (st->dready_trig == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
st->peak_datardy_trig = devm_iio_trigger_alloc(dev,
|
||||
"%s-dev%d-peak",
|
||||
indio_dev->name,
|
||||
iio_device_id(indio_dev));
|
||||
if (!st->peak_datardy_trig)
|
||||
return -ENOMEM;
|
||||
|
||||
st->dready_trig->ops = &adxl372_trigger_ops;
|
||||
st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops;
|
||||
iio_trigger_set_drvdata(st->dready_trig, indio_dev);
|
||||
iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev);
|
||||
ret = devm_iio_trigger_register(dev, st->dready_trig);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_trigger_register(dev, st->peak_datardy_trig);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
indio_dev->trig = iio_trigger_get(st->dready_trig);
|
||||
|
||||
ret = devm_request_irq(dev, st->irq,
|
||||
iio_trigger_generic_data_rdy_poll,
|
||||
IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
|
||||
indio_dev->name, st->dready_trig);
|
||||
if (chip_info->fifo_supported) {
|
||||
ret = adxl372_buffer_setup(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -1259,5 +1330,6 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
|
||||
EXPORT_SYMBOL_NS_GPL(adxl372_probe, "IIO_ADXL372");
|
||||
|
||||
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer driver");
|
||||
MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* ADXL372 3-Axis Digital Accelerometer
|
||||
* ADXL371/ADXL372 3-Axis Digital Accelerometer
|
||||
*
|
||||
* Copyright 2018 Analog Devices Inc.
|
||||
*/
|
||||
@@ -10,8 +10,24 @@
|
||||
|
||||
#define ADXL372_REVID 0x03
|
||||
|
||||
struct adxl372_chip_info {
|
||||
const char *name;
|
||||
const int *samp_freq_tbl;
|
||||
const int *bw_freq_tbl;
|
||||
unsigned int num_freqs;
|
||||
unsigned int act_time_scale_us;
|
||||
unsigned int act_time_scale_low_us;
|
||||
unsigned int inact_time_scale_ms;
|
||||
unsigned int inact_time_scale_low_ms;
|
||||
unsigned int max_odr;
|
||||
bool fifo_supported;
|
||||
};
|
||||
|
||||
extern const struct adxl372_chip_info adxl371_chip_info;
|
||||
extern const struct adxl372_chip_info adxl372_chip_info;
|
||||
|
||||
int adxl372_probe(struct device *dev, struct regmap *regmap,
|
||||
int irq, const char *name);
|
||||
int irq, const struct adxl372_chip_info *chip_info);
|
||||
bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg);
|
||||
|
||||
#endif /* _ADXL372_H_ */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ADXL372 3-Axis Digital Accelerometer I2C driver
|
||||
* ADXL371/ADXL372 3-Axis Digital Accelerometer I2C driver
|
||||
*
|
||||
* Copyright 2018 Analog Devices Inc.
|
||||
*/
|
||||
@@ -20,11 +20,13 @@ static const struct regmap_config adxl372_regmap_config = {
|
||||
|
||||
static int adxl372_i2c_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct i2c_device_id *id = i2c_client_get_device_id(client);
|
||||
const struct adxl372_chip_info *chip_info;
|
||||
struct regmap *regmap;
|
||||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
chip_info = i2c_get_match_data(client);
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &adxl372_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
@@ -38,17 +40,19 @@ static int adxl372_i2c_probe(struct i2c_client *client)
|
||||
dev_warn(&client->dev,
|
||||
"I2C might not work properly with other devices on the bus");
|
||||
|
||||
return adxl372_probe(&client->dev, regmap, client->irq, id->name);
|
||||
return adxl372_probe(&client->dev, regmap, client->irq, chip_info);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adxl372_i2c_id[] = {
|
||||
{ "adxl372" },
|
||||
{ "adxl371", (kernel_ulong_t)&adxl371_chip_info },
|
||||
{ "adxl372", (kernel_ulong_t)&adxl372_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
|
||||
|
||||
static const struct of_device_id adxl372_of_match[] = {
|
||||
{ .compatible = "adi,adxl372" },
|
||||
{ .compatible = "adi,adxl371", .data = &adxl371_chip_info },
|
||||
{ .compatible = "adi,adxl372", .data = &adxl372_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adxl372_of_match);
|
||||
@@ -65,6 +69,7 @@ static struct i2c_driver adxl372_i2c_driver = {
|
||||
module_i2c_driver(adxl372_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer I2C driver");
|
||||
MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer I2C driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS("IIO_ADXL372");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ADXL372 3-Axis Digital Accelerometer SPI driver
|
||||
* ADXL371/ADXL372 3-Axis Digital Accelerometer SPI driver
|
||||
*
|
||||
* Copyright 2018 Analog Devices Inc.
|
||||
*/
|
||||
@@ -22,24 +22,28 @@ static const struct regmap_config adxl372_spi_regmap_config = {
|
||||
|
||||
static int adxl372_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
const struct adxl372_chip_info *chip_info;
|
||||
struct regmap *regmap;
|
||||
|
||||
chip_info = spi_get_device_match_data(spi);
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &adxl372_spi_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
return adxl372_probe(&spi->dev, regmap, spi->irq, id->name);
|
||||
return adxl372_probe(&spi->dev, regmap, spi->irq, chip_info);
|
||||
}
|
||||
|
||||
static const struct spi_device_id adxl372_spi_id[] = {
|
||||
{ "adxl372", 0 },
|
||||
{ "adxl371", (kernel_ulong_t)&adxl371_chip_info },
|
||||
{ "adxl372", (kernel_ulong_t)&adxl372_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
|
||||
|
||||
static const struct of_device_id adxl372_of_match[] = {
|
||||
{ .compatible = "adi,adxl372" },
|
||||
{ .compatible = "adi,adxl371", .data = &adxl371_chip_info },
|
||||
{ .compatible = "adi,adxl372", .data = &adxl372_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adxl372_of_match);
|
||||
@@ -56,6 +60,7 @@ static struct spi_driver adxl372_spi_driver = {
|
||||
module_spi_driver(adxl372_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer SPI driver");
|
||||
MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer SPI driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS("IIO_ADXL372");
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#define ADXL319_ID_VAL 382
|
||||
|
||||
#define ADXL380_DEVID_AD_REG 0x00
|
||||
#define ADLX380_PART_ID_REG 0x02
|
||||
#define ADXL380_PART_ID_REG 0x02
|
||||
|
||||
#define ADXL380_X_DATA_H_REG 0x15
|
||||
#define ADXL380_Y_DATA_H_REG 0x17
|
||||
@@ -1878,7 +1878,7 @@ static int adxl380_setup(struct iio_dev *indio_dev)
|
||||
if (reg_val != ADXL380_DEVID_AD_VAL)
|
||||
dev_warn(st->dev, "Unknown chip id %x\n", reg_val);
|
||||
|
||||
ret = regmap_bulk_read(st->regmap, ADLX380_PART_ID_REG,
|
||||
ret = regmap_bulk_read(st->regmap, ADXL380_PART_ID_REG,
|
||||
&st->transf_buf, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -851,7 +851,7 @@ static ssize_t bmc150_accel_get_fifo_watermark(struct device *dev,
|
||||
wm = data->watermark;
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return sprintf(buf, "%d\n", wm);
|
||||
return sysfs_emit(buf, "%d\n", wm);
|
||||
}
|
||||
|
||||
static ssize_t bmc150_accel_get_fifo_state(struct device *dev,
|
||||
@@ -866,7 +866,7 @@ static ssize_t bmc150_accel_get_fifo_state(struct device *dev,
|
||||
state = data->fifo_mode;
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return sprintf(buf, "%d\n", state);
|
||||
return sysfs_emit(buf, "%d\n", state);
|
||||
}
|
||||
|
||||
static const struct iio_mount_matrix *
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* See industrialio/accels/sca3000.h for comments.
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/device.h>
|
||||
@@ -171,6 +172,7 @@ struct sca3000_state {
|
||||
|
||||
/**
|
||||
* struct sca3000_chip_info - model dependent parameters
|
||||
* @name: name of the chip
|
||||
* @scale: scale * 10^-6
|
||||
* @temp_output: some devices have temperature sensors.
|
||||
* @measurement_mode_freq: normal mode sampling frequency
|
||||
@@ -193,6 +195,7 @@ struct sca3000_state {
|
||||
* sca3000 variant.
|
||||
**/
|
||||
struct sca3000_chip_info {
|
||||
const char *name;
|
||||
unsigned int scale;
|
||||
bool temp_output;
|
||||
int measurement_mode_freq;
|
||||
@@ -207,69 +210,59 @@ struct sca3000_chip_info {
|
||||
int mot_det_mult_y[7];
|
||||
};
|
||||
|
||||
enum sca3000_variant {
|
||||
d01,
|
||||
e02,
|
||||
e04,
|
||||
e05,
|
||||
static const struct sca3000_chip_info sca3000_chip_info_d01 = {
|
||||
.name = "sca3000_d01",
|
||||
.scale = 7357,
|
||||
.temp_output = true,
|
||||
.measurement_mode_freq = 250,
|
||||
.measurement_mode_3db_freq = 45,
|
||||
.option_mode_1 = SCA3000_OP_MODE_BYPASS,
|
||||
.option_mode_1_freq = 250,
|
||||
.option_mode_1_3db_freq = 70,
|
||||
.mot_det_mult_xz = { 50, 100, 200, 350, 650, 1300 },
|
||||
.mot_det_mult_y = { 50, 100, 150, 250, 450, 850, 1750 },
|
||||
};
|
||||
|
||||
/*
|
||||
* Note where option modes are not defined, the chip simply does not
|
||||
* support any.
|
||||
* Other chips in the sca3000 series use i2c and are not included here.
|
||||
*
|
||||
* Some of these devices are only listed in the family data sheet and
|
||||
* do not actually appear to be available.
|
||||
*/
|
||||
static const struct sca3000_chip_info sca3000_spi_chip_info_tbl[] = {
|
||||
[d01] = {
|
||||
.scale = 7357,
|
||||
.temp_output = true,
|
||||
.measurement_mode_freq = 250,
|
||||
.measurement_mode_3db_freq = 45,
|
||||
.option_mode_1 = SCA3000_OP_MODE_BYPASS,
|
||||
.option_mode_1_freq = 250,
|
||||
.option_mode_1_3db_freq = 70,
|
||||
.mot_det_mult_xz = {50, 100, 200, 350, 650, 1300},
|
||||
.mot_det_mult_y = {50, 100, 150, 250, 450, 850, 1750},
|
||||
},
|
||||
[e02] = {
|
||||
.scale = 9810,
|
||||
.measurement_mode_freq = 125,
|
||||
.measurement_mode_3db_freq = 40,
|
||||
.option_mode_1 = SCA3000_OP_MODE_NARROW,
|
||||
.option_mode_1_freq = 63,
|
||||
.option_mode_1_3db_freq = 11,
|
||||
.mot_det_mult_xz = {100, 150, 300, 550, 1050, 2050},
|
||||
.mot_det_mult_y = {50, 100, 200, 350, 700, 1350, 2700},
|
||||
},
|
||||
[e04] = {
|
||||
.scale = 19620,
|
||||
.measurement_mode_freq = 100,
|
||||
.measurement_mode_3db_freq = 38,
|
||||
.option_mode_1 = SCA3000_OP_MODE_NARROW,
|
||||
.option_mode_1_freq = 50,
|
||||
.option_mode_1_3db_freq = 9,
|
||||
.option_mode_2 = SCA3000_OP_MODE_WIDE,
|
||||
.option_mode_2_freq = 400,
|
||||
.option_mode_2_3db_freq = 70,
|
||||
.mot_det_mult_xz = {200, 300, 600, 1100, 2100, 4100},
|
||||
.mot_det_mult_y = {100, 200, 400, 7000, 1400, 2700, 54000},
|
||||
},
|
||||
[e05] = {
|
||||
.scale = 61313,
|
||||
.measurement_mode_freq = 200,
|
||||
.measurement_mode_3db_freq = 60,
|
||||
.option_mode_1 = SCA3000_OP_MODE_NARROW,
|
||||
.option_mode_1_freq = 50,
|
||||
.option_mode_1_3db_freq = 9,
|
||||
.option_mode_2 = SCA3000_OP_MODE_WIDE,
|
||||
.option_mode_2_freq = 400,
|
||||
.option_mode_2_3db_freq = 75,
|
||||
.mot_det_mult_xz = {600, 900, 1700, 3200, 6100, 11900},
|
||||
.mot_det_mult_y = {300, 600, 1200, 2000, 4100, 7800, 15600},
|
||||
},
|
||||
static const struct sca3000_chip_info sca3000_chip_info_e02 = {
|
||||
.name = "sca3000_e02",
|
||||
.scale = 9810,
|
||||
.measurement_mode_freq = 125,
|
||||
.measurement_mode_3db_freq = 40,
|
||||
.option_mode_1 = SCA3000_OP_MODE_NARROW,
|
||||
.option_mode_1_freq = 63,
|
||||
.option_mode_1_3db_freq = 11,
|
||||
.mot_det_mult_xz = { 100, 150, 300, 550, 1050, 2050 },
|
||||
.mot_det_mult_y = { 50, 100, 200, 350, 700, 1350, 2700 },
|
||||
};
|
||||
|
||||
static const struct sca3000_chip_info sca3000_chip_info_e04 = {
|
||||
.name = "sca3000_e04",
|
||||
.scale = 19620,
|
||||
.measurement_mode_freq = 100,
|
||||
.measurement_mode_3db_freq = 38,
|
||||
.option_mode_1 = SCA3000_OP_MODE_NARROW,
|
||||
.option_mode_1_freq = 50,
|
||||
.option_mode_1_3db_freq = 9,
|
||||
.option_mode_2 = SCA3000_OP_MODE_WIDE,
|
||||
.option_mode_2_freq = 400,
|
||||
.option_mode_2_3db_freq = 70,
|
||||
.mot_det_mult_xz = { 200, 300, 600, 1100, 2100, 4100 },
|
||||
.mot_det_mult_y = { 100, 200, 400, 7000, 1400, 2700, 54000 },
|
||||
};
|
||||
|
||||
static const struct sca3000_chip_info sca3000_chip_info_e05 = {
|
||||
.name = "sca3000_e05",
|
||||
.scale = 61313,
|
||||
.measurement_mode_freq = 200,
|
||||
.measurement_mode_3db_freq = 60,
|
||||
.option_mode_1 = SCA3000_OP_MODE_NARROW,
|
||||
.option_mode_1_freq = 50,
|
||||
.option_mode_1_3db_freq = 9,
|
||||
.option_mode_2 = SCA3000_OP_MODE_WIDE,
|
||||
.option_mode_2_freq = 400,
|
||||
.option_mode_2_3db_freq = 75,
|
||||
.mot_det_mult_xz = { 600, 900, 1700, 3200, 6100, 11900 },
|
||||
.mot_det_mult_y = { 300, 600, 1200, 2000, 4100, 7800, 15600 },
|
||||
};
|
||||
|
||||
static int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val)
|
||||
@@ -1435,24 +1428,42 @@ static const struct iio_info sca3000_info = {
|
||||
.write_event_config = &sca3000_write_event_config,
|
||||
};
|
||||
|
||||
static void sca3000_stop_all_interrupts(void *data)
|
||||
{
|
||||
struct iio_dev *indio_dev = data;
|
||||
struct sca3000_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
sca3000_write_reg(st, SCA3000_REG_INT_MASK_ADDR,
|
||||
(st->rx[0] &
|
||||
~(SCA3000_REG_INT_MASK_RING_THREE_QUARTER |
|
||||
SCA3000_REG_INT_MASK_RING_HALF |
|
||||
SCA3000_REG_INT_MASK_ALL_INTS)));
|
||||
}
|
||||
|
||||
static int sca3000_probe(struct spi_device *spi)
|
||||
{
|
||||
int ret;
|
||||
struct device *dev = &spi->dev;
|
||||
struct sca3000_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
st->us = spi;
|
||||
mutex_init(&st->lock);
|
||||
st->info = &sca3000_spi_chip_info_tbl[spi_get_device_id(spi)
|
||||
->driver_data];
|
||||
st->info = spi_get_device_match_data(spi);
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->name = st->info->name;
|
||||
indio_dev->info = &sca3000_info;
|
||||
if (st->info->temp_output) {
|
||||
indio_dev->channels = sca3000_channels_with_temp;
|
||||
@@ -1464,78 +1475,39 @@ static int sca3000_probe(struct spi_device *spi)
|
||||
}
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = devm_iio_kfifo_buffer_setup(&spi->dev, indio_dev,
|
||||
&sca3000_ring_setup_ops);
|
||||
ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &sca3000_ring_setup_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (spi->irq) {
|
||||
ret = request_threaded_irq(spi->irq,
|
||||
NULL,
|
||||
&sca3000_event_handler,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
"sca3000",
|
||||
indio_dev);
|
||||
ret = devm_request_threaded_irq(dev, spi->irq, NULL,
|
||||
&sca3000_event_handler,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
"sca3000",
|
||||
indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = sca3000_clean_setup(st);
|
||||
if (ret)
|
||||
goto error_free_irq;
|
||||
return ret;
|
||||
|
||||
ret = sca3000_print_rev(indio_dev);
|
||||
if (ret)
|
||||
goto error_free_irq;
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
ret = devm_add_action_or_reset(dev, sca3000_stop_all_interrupts, indio_dev);
|
||||
if (ret)
|
||||
goto error_free_irq;
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
error_free_irq:
|
||||
if (spi->irq)
|
||||
free_irq(spi->irq, indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sca3000_stop_all_interrupts(struct sca3000_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
ret = sca3000_write_reg(st, SCA3000_REG_INT_MASK_ADDR,
|
||||
(st->rx[0] &
|
||||
~(SCA3000_REG_INT_MASK_RING_THREE_QUARTER |
|
||||
SCA3000_REG_INT_MASK_RING_HALF |
|
||||
SCA3000_REG_INT_MASK_ALL_INTS)));
|
||||
error_ret:
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sca3000_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct sca3000_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
/* Must ensure no interrupts can be generated after this! */
|
||||
sca3000_stop_all_interrupts(st);
|
||||
if (spi->irq)
|
||||
free_irq(spi->irq, indio_dev);
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id sca3000_id[] = {
|
||||
{"sca3000_d01", d01},
|
||||
{"sca3000_e02", e02},
|
||||
{"sca3000_e04", e04},
|
||||
{"sca3000_e05", e05},
|
||||
{ "sca3000_d01", (kernel_ulong_t)&sca3000_chip_info_d01 },
|
||||
{ "sca3000_e02", (kernel_ulong_t)&sca3000_chip_info_e02 },
|
||||
{ "sca3000_e04", (kernel_ulong_t)&sca3000_chip_info_e04 },
|
||||
{ "sca3000_e05", (kernel_ulong_t)&sca3000_chip_info_e05 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, sca3000_id);
|
||||
@@ -1545,7 +1517,6 @@ static struct spi_driver sca3000_driver = {
|
||||
.name = "sca3000",
|
||||
},
|
||||
.probe = sca3000_probe,
|
||||
.remove = sca3000_remove,
|
||||
.id_table = sca3000_id,
|
||||
};
|
||||
module_spi_driver(sca3000_driver);
|
||||
|
||||
@@ -60,9 +60,14 @@ config AD4030
|
||||
tristate "Analog Devices AD4030 ADC Driver"
|
||||
depends on SPI
|
||||
depends on GPIOLIB
|
||||
depends on PWM
|
||||
select REGMAP
|
||||
select IIO_BUFFER
|
||||
select IIO_BUFFER_DMA
|
||||
select IIO_BUFFER_DMAENGINE
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select SPI_OFFLOAD
|
||||
select SPI_OFFLOAD_TRIGGER_PWM
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD4030 and AD4630 high speed
|
||||
SPI analog to digital converters (ADC).
|
||||
@@ -413,8 +418,10 @@ config AD7768_1
|
||||
select REGMAP_SPI
|
||||
select RATIONAL
|
||||
select IIO_BUFFER
|
||||
select IIO_BUFFER_DMAENGINE
|
||||
select IIO_TRIGGER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select SPI_OFFLOAD
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD7768-1 SPI
|
||||
simultaneously sampling sigma-delta analog to digital converter (ADC).
|
||||
@@ -1366,6 +1373,32 @@ config QCOM_SPMI_ADC5
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called qcom-spmi-adc5.
|
||||
|
||||
config QCOM_SPMI_ADC5_GEN3
|
||||
tristate "Qualcomm Technologies Inc. SPMI PMIC5 GEN3 ADC"
|
||||
depends on SPMI && THERMAL
|
||||
select REGMAP_SPMI
|
||||
select QCOM_VADC_COMMON
|
||||
select AUXILIARY_BUS
|
||||
help
|
||||
IIO Voltage PMIC5 Gen3 ADC driver for Qualcomm Technologies Inc.
|
||||
|
||||
The driver supports reading multiple channels. The ADC is a 16-bit
|
||||
sigma-delta ADC. The hardware supports calibrated results for
|
||||
conversion requests and clients include reading phone power supply
|
||||
voltage, on board system thermistors connected to the PMIC ADC,
|
||||
PMIC die temperature, charger temperature, battery current, USB
|
||||
voltage input and voltage signals connected to supported PMIC GPIO
|
||||
pins. The hardware supports internal pull-up for thermistors and can
|
||||
choose between a 30k, 100k or 400k ohm pull up using the ADC channels.
|
||||
|
||||
In addition, the same driver supports ADC thermal monitoring devices
|
||||
too. They appear as thermal zones with multiple trip points. A thermal
|
||||
client sets threshold temperature for both warm and cool trips and
|
||||
gets updated when a threshold is reached.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called qcom-spmi-adc5-gen3.
|
||||
|
||||
config RCAR_GYRO_ADC
|
||||
tristate "Renesas R-Car GyroADC driver"
|
||||
depends on ARCH_RCAR_GEN2 || COMPILE_TEST
|
||||
|
||||
@@ -116,6 +116,7 @@ obj-$(CONFIG_PAC1934) += pac1934.o
|
||||
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
|
||||
obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
|
||||
obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
|
||||
obj-$(CONFIG_QCOM_SPMI_ADC5_GEN3) += qcom-spmi-adc5-gen3.o
|
||||
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
|
||||
obj-$(CONFIG_QCOM_SPMI_RRADC) += qcom-spmi-rradc.o
|
||||
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
|
||||
|
||||
@@ -14,15 +14,26 @@
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/offload/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/units.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/iio/buffer-dmaengine.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define AD4030_REG_INTERFACE_CONFIG_A 0x00
|
||||
#define AD4030_REG_INTERFACE_CONFIG_A_SW_RESET (BIT(0) | BIT(7))
|
||||
@@ -37,6 +48,8 @@
|
||||
#define AD4030_REG_CHIP_GRADE_AD4630_24_GRADE 0x00
|
||||
#define AD4030_REG_CHIP_GRADE_AD4632_16_GRADE 0x05
|
||||
#define AD4030_REG_CHIP_GRADE_AD4632_24_GRADE 0x02
|
||||
#define AD4030_REG_CHIP_GRADE_ADAQ4216_GRADE 0x1E
|
||||
#define AD4030_REG_CHIP_GRADE_ADAQ4224_GRADE 0x1C
|
||||
#define AD4030_REG_CHIP_GRADE_MASK_CHIP_GRADE GENMASK(7, 3)
|
||||
#define AD4030_REG_SCRATCH_PAD 0x0A
|
||||
#define AD4030_REG_SPI_REVISION 0x0B
|
||||
@@ -111,6 +124,12 @@
|
||||
#define AD4632_TCYC_NS 2000
|
||||
#define AD4632_TCYC_ADJUSTED_NS (AD4632_TCYC_NS - AD4030_TCNVL_NS)
|
||||
#define AD4030_TRESET_COM_DELAY_MS 750
|
||||
/* Datasheet says 9.8ns, so use the closest integer value */
|
||||
#define AD4030_TQUIET_CNV_DELAY_NS 10
|
||||
|
||||
/* HARDWARE_GAIN */
|
||||
#define ADAQ4616_PGA_PINS 2
|
||||
#define ADAQ4616_PGA_GAIN_MAX_NANO (NANO * 2 / 3)
|
||||
|
||||
enum ad4030_out_mode {
|
||||
AD4030_OUT_DATA_MD_DIFF,
|
||||
@@ -132,15 +151,35 @@ enum {
|
||||
AD4030_SCAN_TYPE_AVG,
|
||||
};
|
||||
|
||||
/*
|
||||
* Gains computed as fractions of 1000 so they can be expressed by integers.
|
||||
*/
|
||||
static const int adaq4216_hw_gains_vpv[] = {
|
||||
1 * MILLI / 3, /* 0.333 */
|
||||
5 * MILLI / 9, /* 0.555 */
|
||||
20 * MILLI / 9, /* 0.2222 */
|
||||
20 * MILLI / 3, /* 0.6666 */
|
||||
};
|
||||
|
||||
static const int adaq4216_hw_gains_frac[][2] = {
|
||||
{ 1, 3 }, /* 1/3 V/V gain */
|
||||
{ 5, 9 }, /* 5/9 V/V gain */
|
||||
{ 20, 9 }, /* 20/9 V/V gain */
|
||||
{ 20, 3 }, /* 20/3 V/V gain */
|
||||
};
|
||||
|
||||
struct ad4030_chip_info {
|
||||
const char *name;
|
||||
const unsigned long *available_masks;
|
||||
const struct iio_chan_spec channels[AD4030_MAX_IIO_CHANNEL_NB];
|
||||
const struct iio_chan_spec offload_channels[AD4030_MAX_IIO_CHANNEL_NB];
|
||||
u8 grade;
|
||||
u8 precision_bits;
|
||||
bool has_pga;
|
||||
/* Number of hardware channels */
|
||||
int num_voltage_inputs;
|
||||
unsigned int tcyc_ns;
|
||||
unsigned int max_sample_rate_hz;
|
||||
};
|
||||
|
||||
struct ad4030_state {
|
||||
@@ -153,6 +192,18 @@ struct ad4030_state {
|
||||
int offset_avail[3];
|
||||
unsigned int avg_log2;
|
||||
enum ad4030_out_mode mode;
|
||||
/* Offload sampling */
|
||||
struct spi_transfer offload_xfer;
|
||||
struct spi_message offload_msg;
|
||||
struct spi_offload *offload;
|
||||
struct spi_offload_trigger *offload_trigger;
|
||||
struct spi_offload_trigger_config offload_trigger_config;
|
||||
struct pwm_device *cnv_trigger;
|
||||
size_t scale_avail_size;
|
||||
struct pwm_waveform cnv_wf;
|
||||
unsigned int scale_avail[ARRAY_SIZE(adaq4216_hw_gains_vpv)][2];
|
||||
struct gpio_descs *pga_gpios;
|
||||
unsigned int pga_index;
|
||||
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires the transfer buffers
|
||||
@@ -209,8 +260,9 @@ struct ad4030_state {
|
||||
* - voltage0-voltage1
|
||||
* - voltage2-voltage3
|
||||
*/
|
||||
#define AD4030_CHAN_DIFF(_idx, _scan_type) { \
|
||||
#define __AD4030_CHAN_DIFF(_idx, _scan_type, _offload, _pga) { \
|
||||
.info_mask_shared_by_all = \
|
||||
(_offload ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0) | \
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
|
||||
.info_mask_shared_by_all_available = \
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
|
||||
@@ -219,6 +271,7 @@ struct ad4030_state {
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS) | \
|
||||
BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_separate_available = BIT(IIO_CHAN_INFO_CALIBBIAS) | \
|
||||
(_pga ? BIT(IIO_CHAN_INFO_SCALE) : 0) | \
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE), \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
@@ -232,10 +285,33 @@ struct ad4030_state {
|
||||
.num_ext_scan_type = ARRAY_SIZE(_scan_type), \
|
||||
}
|
||||
|
||||
#define AD4030_CHAN_DIFF(_idx, _scan_type) \
|
||||
__AD4030_CHAN_DIFF(_idx, _scan_type, 0, 0)
|
||||
|
||||
#define AD4030_OFFLOAD_CHAN_DIFF(_idx, _scan_type) \
|
||||
__AD4030_CHAN_DIFF(_idx, _scan_type, 1, 0)
|
||||
|
||||
#define ADAQ4216_CHAN_DIFF(_idx, _scan_type) \
|
||||
__AD4030_CHAN_DIFF(_idx, _scan_type, 0, 1)
|
||||
|
||||
#define ADAQ4216_OFFLOAD_CHAN_DIFF(_idx, _scan_type) \
|
||||
__AD4030_CHAN_DIFF(_idx, _scan_type, 1, 1)
|
||||
|
||||
/*
|
||||
* AD4030 can average over 2^N samples, where N = 1, 2, 3, ..., 16.
|
||||
* We use N = 0 to mean no sample averaging.
|
||||
*/
|
||||
static const int ad4030_average_modes[] = {
|
||||
1, 2, 4, 8, 16, 32, 64, 128,
|
||||
256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
|
||||
65536,
|
||||
BIT(0), /* No sampling average */
|
||||
BIT(1), BIT(2), BIT(3), BIT(4),
|
||||
BIT(5), BIT(6), BIT(7), BIT(8),
|
||||
BIT(9), BIT(10), BIT(11), BIT(12),
|
||||
BIT(13), BIT(14), BIT(15), BIT(16),
|
||||
};
|
||||
|
||||
static const struct spi_offload_config ad4030_offload_config = {
|
||||
.capability_flags = SPI_OFFLOAD_CAP_TRIGGER |
|
||||
SPI_OFFLOAD_CAP_RX_STREAM_DMA,
|
||||
};
|
||||
|
||||
static int ad4030_enter_config_mode(struct ad4030_state *st)
|
||||
@@ -377,6 +453,65 @@ static const struct regmap_config ad4030_regmap_config = {
|
||||
.max_register = AD4030_REG_DIG_ERR,
|
||||
};
|
||||
|
||||
static void ad4030_fill_scale_avail(struct ad4030_state *st)
|
||||
{
|
||||
unsigned int mag_bits, int_part, fract_part;
|
||||
u64 range;
|
||||
|
||||
/*
|
||||
* The maximum precision of differential channels is retrieved from the
|
||||
* chip properties. The output code of differential channels is in two's
|
||||
* complement format (i.e. signed), so the MSB is the sign bit and only
|
||||
* (precision_bits - 1) bits express voltage magnitude.
|
||||
*/
|
||||
mag_bits = st->chip->precision_bits - 1;
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(adaq4216_hw_gains_frac); i++) {
|
||||
range = mult_frac(st->vref_uv, adaq4216_hw_gains_frac[i][1],
|
||||
adaq4216_hw_gains_frac[i][0]);
|
||||
/*
|
||||
* If range were in mV, we would multiply it by NANO below.
|
||||
* Though, range is in µV so multiply it by MICRO only so the
|
||||
* result after right shift and division scales output codes to
|
||||
* millivolts.
|
||||
*/
|
||||
int_part = div_u64_rem((range * MICRO) >> mag_bits, NANO, &fract_part);
|
||||
st->scale_avail[i][0] = int_part;
|
||||
st->scale_avail[i][1] = fract_part;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad4030_set_pga_gain(struct ad4030_state *st)
|
||||
{
|
||||
DECLARE_BITMAP(bitmap, ADAQ4616_PGA_PINS) = { };
|
||||
|
||||
bitmap_write(bitmap, st->pga_index, 0, ADAQ4616_PGA_PINS);
|
||||
|
||||
return gpiod_multi_set_value_cansleep(st->pga_gpios, bitmap);
|
||||
}
|
||||
|
||||
static int ad4030_set_pga(struct iio_dev *indio_dev, int gain_int, int gain_fract)
|
||||
{
|
||||
struct ad4030_state *st = iio_priv(indio_dev);
|
||||
unsigned int mag_bits = st->chip->precision_bits - 1;
|
||||
unsigned int tmp;
|
||||
u64 gain_nano;
|
||||
|
||||
if (!st->pga_gpios)
|
||||
return -EINVAL;
|
||||
|
||||
gain_nano = gain_int * NANO + gain_fract;
|
||||
if (!in_range(gain_nano, 1, ADAQ4616_PGA_GAIN_MAX_NANO))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = DIV_ROUND_CLOSEST_ULL(gain_nano << mag_bits, NANO);
|
||||
gain_nano = DIV_ROUND_CLOSEST(st->vref_uv, tmp);
|
||||
st->pga_index = find_closest(gain_nano, adaq4216_hw_gains_vpv,
|
||||
ARRAY_SIZE(adaq4216_hw_gains_vpv));
|
||||
|
||||
return ad4030_set_pga_gain(st);
|
||||
}
|
||||
|
||||
static int ad4030_get_chan_scale(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
@@ -389,6 +524,13 @@ static int ad4030_get_chan_scale(struct iio_dev *indio_dev,
|
||||
if (IS_ERR(scan_type))
|
||||
return PTR_ERR(scan_type);
|
||||
|
||||
/* The LSB of the 8-bit common-mode data is always vref/256. */
|
||||
if (st->chip->has_pga && scan_type->realbits != 8) {
|
||||
*val = st->scale_avail[st->pga_index][0];
|
||||
*val2 = st->scale_avail[st->pga_index][1];
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
}
|
||||
|
||||
if (chan->differential)
|
||||
*val = (st->vref_uv * 2) / MILLI;
|
||||
else
|
||||
@@ -451,6 +593,102 @@ static int ad4030_get_chan_calibbias(struct iio_dev *indio_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static void ad4030_get_sampling_freq(struct ad4030_state *st, int *freq)
|
||||
{
|
||||
struct spi_offload_trigger_config *config = &st->offload_trigger_config;
|
||||
|
||||
/*
|
||||
* Conversion data is fetched from the device when the offload transfer
|
||||
* is triggered. Thus, provide the SPI offload trigger frequency as the
|
||||
* sampling frequency.
|
||||
*/
|
||||
*freq = config->periodic.frequency_hz;
|
||||
}
|
||||
|
||||
static int ad4030_update_conversion_rate(struct ad4030_state *st,
|
||||
unsigned int freq_hz, unsigned int avg_log2)
|
||||
{
|
||||
struct spi_offload_trigger_config *config = &st->offload_trigger_config;
|
||||
unsigned int offload_period_ns, cnv_rate_hz;
|
||||
struct pwm_waveform cnv_wf = { };
|
||||
u64 target = AD4030_TCNVH_NS;
|
||||
u64 offload_offset_ns;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* When averaging/oversampling over N samples, we fire the offload
|
||||
* trigger once at every N pulses of the CNV signal. Conversely, the CNV
|
||||
* signal needs to be N times faster than the offload trigger. Take that
|
||||
* into account to correctly re-evaluate both the PWM waveform connected
|
||||
* to CNV and the SPI offload trigger.
|
||||
*/
|
||||
cnv_rate_hz = freq_hz << avg_log2;
|
||||
|
||||
cnv_wf.period_length_ns = DIV_ROUND_CLOSEST(NSEC_PER_SEC, cnv_rate_hz);
|
||||
/*
|
||||
* The datasheet lists a minimum time of 9.8 ns, but no maximum. If the
|
||||
* rounded PWM's value is less than 10, increase the target value by 10
|
||||
* and attempt to round the waveform again, until the value is at least
|
||||
* 10 ns. Use a separate variable to represent the target in case the
|
||||
* rounding is severe enough to keep putting the first few results under
|
||||
* the minimum 10ns condition checked by the while loop.
|
||||
*/
|
||||
do {
|
||||
cnv_wf.duty_length_ns = target;
|
||||
ret = pwm_round_waveform_might_sleep(st->cnv_trigger, &cnv_wf);
|
||||
if (ret)
|
||||
return ret;
|
||||
target += AD4030_TCNVH_NS;
|
||||
} while (cnv_wf.duty_length_ns < AD4030_TCNVH_NS);
|
||||
|
||||
/*
|
||||
* The CNV waveform period (period_length_ns) might get rounded down by
|
||||
* pwm_round_waveform_might_sleep(). Check the resultant PWM period
|
||||
* is not smaller than the minimum data conversion cycle time.
|
||||
*/
|
||||
if (!in_range(cnv_wf.period_length_ns, AD4030_TCYC_NS, INT_MAX))
|
||||
return -EINVAL;
|
||||
|
||||
offload_period_ns = DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq_hz);
|
||||
|
||||
config->periodic.frequency_hz = DIV_ROUND_UP(HZ_PER_GHZ, offload_period_ns);
|
||||
|
||||
/*
|
||||
* The hardware does the capture on zone 2 (when SPI trigger PWM
|
||||
* is used). This means that the SPI trigger signal should happen at
|
||||
* tsync + tquiet_con_delay being tsync the conversion signal period
|
||||
* and tquiet_con_delay 9.8ns. Hence set the PWM phase accordingly.
|
||||
*
|
||||
* The PWM waveform API only supports nanosecond resolution right now,
|
||||
* so round this setting to the closest available value.
|
||||
*/
|
||||
offload_offset_ns = AD4030_TQUIET_CNV_DELAY_NS;
|
||||
do {
|
||||
config->periodic.offset_ns = offload_offset_ns;
|
||||
ret = spi_offload_trigger_validate(st->offload_trigger, config);
|
||||
if (ret)
|
||||
return ret;
|
||||
offload_offset_ns += AD4030_TQUIET_CNV_DELAY_NS;
|
||||
} while (config->periodic.offset_ns < AD4030_TQUIET_CNV_DELAY_NS);
|
||||
|
||||
st->cnv_wf = cnv_wf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad4030_set_sampling_freq(struct iio_dev *indio_dev, int freq_hz)
|
||||
{
|
||||
struct ad4030_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (freq_hz == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!in_range(freq_hz, 0, st->chip->max_sample_rate_hz))
|
||||
return -ERANGE;
|
||||
|
||||
return ad4030_update_conversion_rate(st, freq_hz, st->avg_log2);
|
||||
}
|
||||
|
||||
static int ad4030_set_chan_calibscale(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int gain_int,
|
||||
@@ -510,11 +748,30 @@ static int ad4030_set_avg_frame_len(struct iio_dev *dev, int avg_val)
|
||||
struct ad4030_state *st = iio_priv(dev);
|
||||
unsigned int avg_log2 = ilog2(avg_val);
|
||||
unsigned int last_avg_idx = ARRAY_SIZE(ad4030_average_modes) - 1;
|
||||
int freq_hz;
|
||||
int ret;
|
||||
|
||||
if (avg_val < 0 || avg_val > ad4030_average_modes[last_avg_idx])
|
||||
return -EINVAL;
|
||||
|
||||
if (st->offload_trigger) {
|
||||
/*
|
||||
* The sample averaging and sampling frequency configurations
|
||||
* are mutually dependent on each other. That's because the
|
||||
* effective data sample rate is fCNV / 2^N, where N is the
|
||||
* number of samples being averaged.
|
||||
*
|
||||
* When SPI offload is supported and we have control over the
|
||||
* sample rate, the conversion start signal (CNV) and the SPI
|
||||
* offload trigger frequencies must be re-evaluated so data is
|
||||
* fetched only after 'avg_val' conversions.
|
||||
*/
|
||||
ad4030_get_sampling_freq(st, &freq_hz);
|
||||
ret = ad4030_update_conversion_rate(st, freq_hz, avg_log2);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(st->regmap, AD4030_REG_AVG,
|
||||
AD4030_REG_AVG_MASK_AVG_SYNC |
|
||||
FIELD_PREP(AD4030_REG_AVG_MASK_AVG_VAL, avg_log2));
|
||||
@@ -623,7 +880,7 @@ static int ad4030_conversion(struct iio_dev *indio_dev)
|
||||
/* Add one byte if we are using a differential + common byte mode */
|
||||
bytes_to_read += (st->mode == AD4030_OUT_DATA_MD_24_DIFF_8_COM ||
|
||||
st->mode == AD4030_OUT_DATA_MD_16_DIFF_8_COM) ? 1 : 0;
|
||||
/* Mulitiply by the number of hardware channels */
|
||||
/* Multiply by the number of hardware channels */
|
||||
bytes_to_read *= st->chip->num_voltage_inputs;
|
||||
|
||||
for (i = 0; i < cnv_nb; i++) {
|
||||
@@ -742,6 +999,15 @@ static int ad4030_read_avail(struct iio_dev *indio_dev,
|
||||
*length = ARRAY_SIZE(ad4030_average_modes);
|
||||
return IIO_AVAIL_LIST;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (st->scale_avail_size == 1)
|
||||
*vals = (int *)st->scale_avail[st->pga_index];
|
||||
else
|
||||
*vals = (int *)st->scale_avail;
|
||||
*length = st->scale_avail_size * 2; /* print int and nano part */
|
||||
*type = IIO_VAL_INT_PLUS_NANO;
|
||||
return IIO_AVAIL_LIST;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -767,6 +1033,10 @@ static int ad4030_read_raw_dispatch(struct iio_dev *indio_dev,
|
||||
*val = BIT(st->avg_log2);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ad4030_get_sampling_freq(st, val);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -807,6 +1077,12 @@ static int ad4030_write_raw_dispatch(struct iio_dev *indio_dev,
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
return ad4030_set_avg_frame_len(indio_dev, val);
|
||||
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return ad4030_set_sampling_freq(indio_dev, val);
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return ad4030_set_pga(indio_dev, val, val2);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -828,6 +1104,17 @@ static int ad4030_write_raw(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad4030_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, long mask)
|
||||
{
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
default:
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad4030_reg_access(struct iio_dev *indio_dev, unsigned int reg,
|
||||
unsigned int writeval, unsigned int *readval)
|
||||
{
|
||||
@@ -874,6 +1161,7 @@ static const struct iio_info ad4030_iio_info = {
|
||||
.read_avail = ad4030_read_avail,
|
||||
.read_raw = ad4030_read_raw,
|
||||
.write_raw = ad4030_write_raw,
|
||||
.write_raw_get_fmt = &ad4030_write_raw_get_fmt,
|
||||
.debugfs_reg_access = ad4030_reg_access,
|
||||
.read_label = ad4030_read_label,
|
||||
.get_current_scan_type = ad4030_get_current_scan_type,
|
||||
@@ -896,6 +1184,86 @@ static const struct iio_buffer_setup_ops ad4030_buffer_setup_ops = {
|
||||
.validate_scan_mask = ad4030_validate_scan_mask,
|
||||
};
|
||||
|
||||
static void ad4030_prepare_offload_msg(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad4030_state *st = iio_priv(indio_dev);
|
||||
u8 offload_bpw;
|
||||
|
||||
if (st->mode == AD4030_OUT_DATA_MD_30_AVERAGED_DIFF)
|
||||
offload_bpw = 32;
|
||||
else
|
||||
offload_bpw = st->chip->precision_bits;
|
||||
|
||||
st->offload_xfer.bits_per_word = offload_bpw;
|
||||
st->offload_xfer.len = spi_bpw_to_bytes(offload_bpw);
|
||||
st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
|
||||
spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1);
|
||||
}
|
||||
|
||||
static int ad4030_offload_buffer_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad4030_state *st = iio_priv(indio_dev);
|
||||
unsigned int reg_modes;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* When data from 2 analog input channels is output through a single
|
||||
* bus line (interleaved mode (LANE_MD == 0b11)) and gets pushed through
|
||||
* DMA, extra hardware is required to do the de-interleaving. While we
|
||||
* don't support such hardware configurations, disallow interleaved mode
|
||||
* when using SPI offload.
|
||||
*/
|
||||
ret = regmap_read(st->regmap, AD4030_REG_MODES, ®_modes);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (st->chip->num_voltage_inputs > 1 &&
|
||||
FIELD_GET(AD4030_REG_MODES_MASK_LANE_MODE, reg_modes) == AD4030_LANE_MD_INTERLEAVED)
|
||||
return -EINVAL;
|
||||
|
||||
ad4030_prepare_offload_msg(indio_dev);
|
||||
st->offload_msg.offload = st->offload;
|
||||
ret = spi_optimize_message(st->spi, &st->offload_msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pwm_set_waveform_might_sleep(st->cnv_trigger, &st->cnv_wf, false);
|
||||
if (ret)
|
||||
goto out_unoptimize;
|
||||
|
||||
ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
|
||||
&st->offload_trigger_config);
|
||||
if (ret)
|
||||
goto out_pwm_disable;
|
||||
|
||||
return 0;
|
||||
|
||||
out_pwm_disable:
|
||||
pwm_disable(st->cnv_trigger);
|
||||
out_unoptimize:
|
||||
spi_unoptimize_message(&st->offload_msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad4030_offload_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad4030_state *st = iio_priv(indio_dev);
|
||||
|
||||
spi_offload_trigger_disable(st->offload, st->offload_trigger);
|
||||
|
||||
pwm_disable(st->cnv_trigger);
|
||||
|
||||
spi_unoptimize_message(&st->offload_msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops ad4030_offload_buffer_setup_ops = {
|
||||
.postenable = &ad4030_offload_buffer_postenable,
|
||||
.predisable = &ad4030_offload_buffer_predisable,
|
||||
};
|
||||
|
||||
static int ad4030_regulators_get(struct ad4030_state *st)
|
||||
{
|
||||
struct device *dev = &st->spi->dev;
|
||||
@@ -965,6 +1333,24 @@ static int ad4030_detect_chip_info(const struct ad4030_state *st)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad4030_pwm_get(struct ad4030_state *st)
|
||||
{
|
||||
struct device *dev = &st->spi->dev;
|
||||
|
||||
st->cnv_trigger = devm_pwm_get(dev, NULL);
|
||||
if (IS_ERR(st->cnv_trigger))
|
||||
return dev_err_probe(dev, PTR_ERR(st->cnv_trigger),
|
||||
"Failed to get CNV PWM\n");
|
||||
|
||||
/*
|
||||
* Preemptively disable the PWM, since we only want to enable it with
|
||||
* the buffer.
|
||||
*/
|
||||
pwm_disable(st->cnv_trigger);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad4030_config(struct ad4030_state *st)
|
||||
{
|
||||
int ret;
|
||||
@@ -992,6 +1378,51 @@ static int ad4030_config(struct ad4030_state *st)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad4030_spi_offload_setup(struct iio_dev *indio_dev,
|
||||
struct ad4030_state *st)
|
||||
{
|
||||
struct device *dev = &st->spi->dev;
|
||||
struct dma_chan *rx_dma;
|
||||
|
||||
indio_dev->setup_ops = &ad4030_offload_buffer_setup_ops;
|
||||
|
||||
st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload,
|
||||
SPI_OFFLOAD_TRIGGER_PERIODIC);
|
||||
if (IS_ERR(st->offload_trigger))
|
||||
return dev_err_probe(dev, PTR_ERR(st->offload_trigger),
|
||||
"failed to get offload trigger\n");
|
||||
|
||||
st->offload_trigger_config.type = SPI_OFFLOAD_TRIGGER_PERIODIC;
|
||||
|
||||
rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload);
|
||||
if (IS_ERR(rx_dma))
|
||||
return dev_err_probe(dev, PTR_ERR(rx_dma),
|
||||
"failed to get offload RX DMA\n");
|
||||
|
||||
return devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma,
|
||||
IIO_BUFFER_DIRECTION_IN);
|
||||
}
|
||||
|
||||
static int ad4030_setup_pga(struct device *dev, struct iio_dev *indio_dev,
|
||||
struct ad4030_state *st)
|
||||
{
|
||||
/* Setup GPIOs for PGA control */
|
||||
st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->pga_gpios))
|
||||
return dev_err_probe(dev, PTR_ERR(st->pga_gpios),
|
||||
"Failed to get PGA gpios.\n");
|
||||
|
||||
if (st->pga_gpios->ndescs != ADAQ4616_PGA_PINS)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Expected %d GPIOs for PGA control.\n",
|
||||
ADAQ4616_PGA_PINS);
|
||||
|
||||
st->scale_avail_size = ARRAY_SIZE(adaq4216_hw_gains_vpv);
|
||||
st->pga_index = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad4030_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
@@ -1034,6 +1465,14 @@ static int ad4030_probe(struct spi_device *spi)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (st->chip->has_pga) {
|
||||
ret = ad4030_setup_pga(dev, indio_dev, st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ad4030_fill_scale_avail(st);
|
||||
}
|
||||
|
||||
ret = ad4030_config(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1043,24 +1482,58 @@ static int ad4030_probe(struct spi_device *spi)
|
||||
return dev_err_probe(dev, PTR_ERR(st->cnv_gpio),
|
||||
"Failed to get cnv gpio\n");
|
||||
|
||||
/*
|
||||
* One hardware channel is split in two software channels when using
|
||||
* common byte mode. Add one more channel for the timestamp.
|
||||
*/
|
||||
indio_dev->num_channels = 2 * st->chip->num_voltage_inputs + 1;
|
||||
indio_dev->name = st->chip->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &ad4030_iio_info;
|
||||
indio_dev->channels = st->chip->channels;
|
||||
indio_dev->available_scan_masks = st->chip->available_masks;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
ad4030_trigger_handler,
|
||||
&ad4030_buffer_setup_ops);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to setup triggered buffer\n");
|
||||
st->offload = devm_spi_offload_get(dev, spi, &ad4030_offload_config);
|
||||
ret = PTR_ERR_OR_ZERO(st->offload);
|
||||
/* Fall back to low speed usage when no SPI offload is available. */
|
||||
if (ret == -ENODEV) {
|
||||
/*
|
||||
* One hardware channel is split in two software channels when
|
||||
* using common byte mode. Add one more channel for the timestamp.
|
||||
*/
|
||||
indio_dev->num_channels = 2 * st->chip->num_voltage_inputs + 1;
|
||||
indio_dev->channels = st->chip->channels;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
ad4030_trigger_handler,
|
||||
&ad4030_buffer_setup_ops);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to setup triggered buffer\n");
|
||||
} else if (ret) {
|
||||
return dev_err_probe(dev, ret, "failed to get offload\n");
|
||||
} else {
|
||||
/*
|
||||
* Offloaded SPI transfers can't support software timestamp so
|
||||
* no additional timestamp channel is added.
|
||||
*/
|
||||
indio_dev->num_channels = st->chip->num_voltage_inputs;
|
||||
indio_dev->channels = st->chip->offload_channels;
|
||||
ret = ad4030_spi_offload_setup(indio_dev, st);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to setup SPI offload\n");
|
||||
|
||||
ret = ad4030_pwm_get(st);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to get PWM\n");
|
||||
|
||||
/*
|
||||
* Start with a slower sampling rate so there is some room for
|
||||
* adjusting the sample averaging and the sampling frequency
|
||||
* without hitting the maximum conversion rate.
|
||||
*/
|
||||
ret = ad4030_update_conversion_rate(st, st->chip->max_sample_rate_hz >> 4,
|
||||
st->avg_log2);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to set offload samp freq\n");
|
||||
}
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
@@ -1098,11 +1571,28 @@ static const struct iio_scan_type ad4030_24_scan_types[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_scan_type ad4030_24_offload_scan_types[] = {
|
||||
[AD4030_SCAN_TYPE_NORMAL] = {
|
||||
.sign = 's',
|
||||
.realbits = 24,
|
||||
.storagebits = 32,
|
||||
.shift = 0,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
[AD4030_SCAN_TYPE_AVG] = {
|
||||
.sign = 's',
|
||||
.realbits = 30,
|
||||
.storagebits = 32,
|
||||
.shift = 2,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_scan_type ad4030_16_scan_types[] = {
|
||||
[AD4030_SCAN_TYPE_NORMAL] = {
|
||||
.sign = 's',
|
||||
.storagebits = 32,
|
||||
.realbits = 16,
|
||||
.storagebits = 32,
|
||||
.shift = 16,
|
||||
.endianness = IIO_BE,
|
||||
},
|
||||
@@ -1115,6 +1605,23 @@ static const struct iio_scan_type ad4030_16_scan_types[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct iio_scan_type ad4030_16_offload_scan_types[] = {
|
||||
[AD4030_SCAN_TYPE_NORMAL] = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 32,
|
||||
.shift = 0,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
[AD4030_SCAN_TYPE_AVG] = {
|
||||
.sign = 's',
|
||||
.realbits = 30,
|
||||
.storagebits = 32,
|
||||
.shift = 2,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ad4030_chip_info ad4030_24_chip_info = {
|
||||
.name = "ad4030-24",
|
||||
.available_masks = ad4030_channel_masks,
|
||||
@@ -1123,10 +1630,14 @@ static const struct ad4030_chip_info ad4030_24_chip_info = {
|
||||
AD4030_CHAN_CMO(1, 0),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(2),
|
||||
},
|
||||
.offload_channels = {
|
||||
AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types),
|
||||
},
|
||||
.grade = AD4030_REG_CHIP_GRADE_AD4030_24_GRADE,
|
||||
.precision_bits = 24,
|
||||
.num_voltage_inputs = 1,
|
||||
.tcyc_ns = AD4030_TCYC_ADJUSTED_NS,
|
||||
.max_sample_rate_hz = 2 * HZ_PER_MHZ,
|
||||
};
|
||||
|
||||
static const struct ad4030_chip_info ad4630_16_chip_info = {
|
||||
@@ -1139,10 +1650,15 @@ static const struct ad4030_chip_info ad4630_16_chip_info = {
|
||||
AD4030_CHAN_CMO(3, 1),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.offload_channels = {
|
||||
AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_16_offload_scan_types),
|
||||
AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_16_offload_scan_types),
|
||||
},
|
||||
.grade = AD4030_REG_CHIP_GRADE_AD4630_16_GRADE,
|
||||
.precision_bits = 16,
|
||||
.num_voltage_inputs = 2,
|
||||
.tcyc_ns = AD4030_TCYC_ADJUSTED_NS,
|
||||
.max_sample_rate_hz = 2 * HZ_PER_MHZ,
|
||||
};
|
||||
|
||||
static const struct ad4030_chip_info ad4630_24_chip_info = {
|
||||
@@ -1155,10 +1671,15 @@ static const struct ad4030_chip_info ad4630_24_chip_info = {
|
||||
AD4030_CHAN_CMO(3, 1),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.offload_channels = {
|
||||
AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types),
|
||||
AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_24_offload_scan_types),
|
||||
},
|
||||
.grade = AD4030_REG_CHIP_GRADE_AD4630_24_GRADE,
|
||||
.precision_bits = 24,
|
||||
.num_voltage_inputs = 2,
|
||||
.tcyc_ns = AD4030_TCYC_ADJUSTED_NS,
|
||||
.max_sample_rate_hz = 2 * HZ_PER_MHZ,
|
||||
};
|
||||
|
||||
static const struct ad4030_chip_info ad4632_16_chip_info = {
|
||||
@@ -1171,10 +1692,15 @@ static const struct ad4030_chip_info ad4632_16_chip_info = {
|
||||
AD4030_CHAN_CMO(3, 1),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.offload_channels = {
|
||||
AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_16_offload_scan_types),
|
||||
AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_16_offload_scan_types),
|
||||
},
|
||||
.grade = AD4030_REG_CHIP_GRADE_AD4632_16_GRADE,
|
||||
.precision_bits = 16,
|
||||
.num_voltage_inputs = 2,
|
||||
.tcyc_ns = AD4632_TCYC_ADJUSTED_NS,
|
||||
.max_sample_rate_hz = 500 * HZ_PER_KHZ,
|
||||
};
|
||||
|
||||
static const struct ad4030_chip_info ad4632_24_chip_info = {
|
||||
@@ -1187,10 +1713,53 @@ static const struct ad4030_chip_info ad4632_24_chip_info = {
|
||||
AD4030_CHAN_CMO(3, 1),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.offload_channels = {
|
||||
AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types),
|
||||
AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_24_offload_scan_types),
|
||||
},
|
||||
.grade = AD4030_REG_CHIP_GRADE_AD4632_24_GRADE,
|
||||
.precision_bits = 24,
|
||||
.num_voltage_inputs = 2,
|
||||
.tcyc_ns = AD4632_TCYC_ADJUSTED_NS,
|
||||
.max_sample_rate_hz = 500 * HZ_PER_KHZ,
|
||||
};
|
||||
|
||||
static const struct ad4030_chip_info adaq4216_chip_info = {
|
||||
.name = "adaq4216",
|
||||
.available_masks = ad4030_channel_masks,
|
||||
.channels = {
|
||||
ADAQ4216_CHAN_DIFF(0, ad4030_16_scan_types),
|
||||
AD4030_CHAN_CMO(1, 0),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(2),
|
||||
},
|
||||
.offload_channels = {
|
||||
ADAQ4216_OFFLOAD_CHAN_DIFF(0, ad4030_16_offload_scan_types),
|
||||
},
|
||||
.grade = AD4030_REG_CHIP_GRADE_ADAQ4216_GRADE,
|
||||
.precision_bits = 16,
|
||||
.has_pga = true,
|
||||
.num_voltage_inputs = 1,
|
||||
.tcyc_ns = AD4030_TCYC_ADJUSTED_NS,
|
||||
.max_sample_rate_hz = 2 * HZ_PER_MHZ,
|
||||
};
|
||||
|
||||
static const struct ad4030_chip_info adaq4224_chip_info = {
|
||||
.name = "adaq4224",
|
||||
.available_masks = ad4030_channel_masks,
|
||||
.channels = {
|
||||
ADAQ4216_CHAN_DIFF(0, ad4030_24_scan_types),
|
||||
AD4030_CHAN_CMO(1, 0),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(2),
|
||||
},
|
||||
.offload_channels = {
|
||||
ADAQ4216_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types),
|
||||
},
|
||||
.grade = AD4030_REG_CHIP_GRADE_ADAQ4224_GRADE,
|
||||
.precision_bits = 24,
|
||||
.has_pga = true,
|
||||
.num_voltage_inputs = 1,
|
||||
.tcyc_ns = AD4030_TCYC_ADJUSTED_NS,
|
||||
.max_sample_rate_hz = 2 * HZ_PER_MHZ,
|
||||
};
|
||||
|
||||
static const struct spi_device_id ad4030_id_table[] = {
|
||||
@@ -1199,6 +1768,8 @@ static const struct spi_device_id ad4030_id_table[] = {
|
||||
{ "ad4630-24", (kernel_ulong_t)&ad4630_24_chip_info },
|
||||
{ "ad4632-16", (kernel_ulong_t)&ad4632_16_chip_info },
|
||||
{ "ad4632-24", (kernel_ulong_t)&ad4632_24_chip_info },
|
||||
{ "adaq4216", (kernel_ulong_t)&adaq4216_chip_info },
|
||||
{ "adaq4224", (kernel_ulong_t)&adaq4224_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad4030_id_table);
|
||||
@@ -1209,6 +1780,8 @@ static const struct of_device_id ad4030_of_match[] = {
|
||||
{ .compatible = "adi,ad4630-24", .data = &ad4630_24_chip_info },
|
||||
{ .compatible = "adi,ad4632-16", .data = &ad4632_16_chip_info },
|
||||
{ .compatible = "adi,ad4632-24", .data = &ad4632_24_chip_info },
|
||||
{ .compatible = "adi,adaq4216", .data = &adaq4216_chip_info },
|
||||
{ .compatible = "adi,adaq4224", .data = &adaq4224_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad4030_of_match);
|
||||
@@ -1226,3 +1799,4 @@ module_spi_driver(ad4030_driver);
|
||||
MODULE_AUTHOR("Esteban Blanc <eblanc@baylibre.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD4630 ADC family driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
|
||||
|
||||
@@ -1199,11 +1199,14 @@ static int ad4062_write_event_value(struct iio_dev *indio_dev,
|
||||
* The AD4062 in burst averaging mode increases realbits from 16-bits to
|
||||
* 20-bits, increasing the storagebits from 16-bits to 32-bits.
|
||||
*/
|
||||
static inline size_t ad4062_sizeof_storagebits(struct ad4062_state *st)
|
||||
static inline int ad4062_sizeof_storagebits(struct ad4062_state *st)
|
||||
{
|
||||
const struct iio_scan_type *scan_type =
|
||||
iio_get_current_scan_type(st->indio_dev, st->chip->channels);
|
||||
|
||||
if (IS_ERR(scan_type))
|
||||
return PTR_ERR(scan_type);
|
||||
|
||||
return BITS_TO_BYTES(scan_type->storagebits);
|
||||
}
|
||||
|
||||
@@ -1233,7 +1236,12 @@ static int pm_ad4062_triggered_buffer_postenable(struct ad4062_state *st)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->conv_sizeof = ad4062_sizeof_storagebits(st);
|
||||
ret = ad4062_sizeof_storagebits(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st->conv_sizeof = ret;
|
||||
|
||||
st->conv_addr = ad4062_get_conv_addr(st, st->conv_sizeof);
|
||||
/* CONV_READ requires read to trigger first sample. */
|
||||
struct i3c_xfer xfer_sample[2] = {
|
||||
|
||||
@@ -127,10 +127,13 @@
|
||||
#define AD4080_SPI_READ BIT(7)
|
||||
#define AD4080_CHIP_ID 0x0050
|
||||
#define AD4081_CHIP_ID 0x0051
|
||||
#define AD4082_CHIP_ID 0x0052
|
||||
#define AD4083_CHIP_ID 0x0053
|
||||
#define AD4084_CHIP_ID 0x0054
|
||||
#define AD4085_CHIP_ID 0x0055
|
||||
#define AD4086_CHIP_ID 0x0056
|
||||
#define AD4087_CHIP_ID 0x0057
|
||||
#define AD4088_CHIP_ID 0x0058
|
||||
|
||||
#define AD4080_LVDS_CNV_CLK_CNT_MAX 7
|
||||
|
||||
@@ -185,7 +188,6 @@ struct ad4080_state {
|
||||
*/
|
||||
struct mutex lock;
|
||||
unsigned int num_lanes;
|
||||
unsigned int dec_rate;
|
||||
unsigned long clk_rate;
|
||||
enum ad4080_filter_type filter_type;
|
||||
bool lvds_cnv_en;
|
||||
@@ -442,14 +444,20 @@ static const struct iio_chan_spec ad4080_channel = AD4080_CHANNEL_DEFINE(20, 32)
|
||||
|
||||
static const struct iio_chan_spec ad4081_channel = AD4080_CHANNEL_DEFINE(20, 32);
|
||||
|
||||
static const struct iio_chan_spec ad4082_channel = AD4080_CHANNEL_DEFINE(20, 32);
|
||||
|
||||
static const struct iio_chan_spec ad4083_channel = AD4080_CHANNEL_DEFINE(16, 16);
|
||||
|
||||
static const struct iio_chan_spec ad4084_channel = AD4080_CHANNEL_DEFINE(16, 16);
|
||||
|
||||
static const struct iio_chan_spec ad4085_channel = AD4080_CHANNEL_DEFINE(16, 16);
|
||||
|
||||
static const struct iio_chan_spec ad4086_channel = AD4080_CHANNEL_DEFINE(14, 16);
|
||||
|
||||
static const struct iio_chan_spec ad4087_channel = AD4080_CHANNEL_DEFINE(14, 16);
|
||||
|
||||
static const struct iio_chan_spec ad4088_channel = AD4080_CHANNEL_DEFINE(14, 16);
|
||||
|
||||
static const struct ad4080_chip_info ad4080_chip_info = {
|
||||
.name = "ad4080",
|
||||
.product_id = AD4080_CHIP_ID,
|
||||
@@ -470,6 +478,16 @@ static const struct ad4080_chip_info ad4081_chip_info = {
|
||||
.lvds_cnv_clk_cnt_max = 2,
|
||||
};
|
||||
|
||||
static const struct ad4080_chip_info ad4082_chip_info = {
|
||||
.name = "ad4082",
|
||||
.product_id = AD4082_CHIP_ID,
|
||||
.scale_table = ad4080_scale_table,
|
||||
.num_scales = ARRAY_SIZE(ad4080_scale_table),
|
||||
.num_channels = 1,
|
||||
.channels = &ad4082_channel,
|
||||
.lvds_cnv_clk_cnt_max = 8,
|
||||
};
|
||||
|
||||
static const struct ad4080_chip_info ad4083_chip_info = {
|
||||
.name = "ad4083",
|
||||
.product_id = AD4083_CHIP_ID,
|
||||
@@ -490,6 +508,16 @@ static const struct ad4080_chip_info ad4084_chip_info = {
|
||||
.lvds_cnv_clk_cnt_max = 2,
|
||||
};
|
||||
|
||||
static const struct ad4080_chip_info ad4085_chip_info = {
|
||||
.name = "ad4085",
|
||||
.product_id = AD4085_CHIP_ID,
|
||||
.scale_table = ad4080_scale_table,
|
||||
.num_scales = ARRAY_SIZE(ad4080_scale_table),
|
||||
.num_channels = 1,
|
||||
.channels = &ad4085_channel,
|
||||
.lvds_cnv_clk_cnt_max = 8,
|
||||
};
|
||||
|
||||
static const struct ad4080_chip_info ad4086_chip_info = {
|
||||
.name = "ad4086",
|
||||
.product_id = AD4086_CHIP_ID,
|
||||
@@ -510,6 +538,16 @@ static const struct ad4080_chip_info ad4087_chip_info = {
|
||||
.lvds_cnv_clk_cnt_max = 1,
|
||||
};
|
||||
|
||||
static const struct ad4080_chip_info ad4088_chip_info = {
|
||||
.name = "ad4088",
|
||||
.product_id = AD4088_CHIP_ID,
|
||||
.scale_table = ad4080_scale_table,
|
||||
.num_scales = ARRAY_SIZE(ad4080_scale_table),
|
||||
.num_channels = 1,
|
||||
.channels = &ad4088_channel,
|
||||
.lvds_cnv_clk_cnt_max = 8,
|
||||
};
|
||||
|
||||
static int ad4080_setup(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad4080_state *st = iio_priv(indio_dev);
|
||||
@@ -666,10 +704,13 @@ static int ad4080_probe(struct spi_device *spi)
|
||||
static const struct spi_device_id ad4080_id[] = {
|
||||
{ "ad4080", (kernel_ulong_t)&ad4080_chip_info },
|
||||
{ "ad4081", (kernel_ulong_t)&ad4081_chip_info },
|
||||
{ "ad4082", (kernel_ulong_t)&ad4082_chip_info },
|
||||
{ "ad4083", (kernel_ulong_t)&ad4083_chip_info },
|
||||
{ "ad4084", (kernel_ulong_t)&ad4084_chip_info },
|
||||
{ "ad4085", (kernel_ulong_t)&ad4085_chip_info },
|
||||
{ "ad4086", (kernel_ulong_t)&ad4086_chip_info },
|
||||
{ "ad4087", (kernel_ulong_t)&ad4087_chip_info },
|
||||
{ "ad4088", (kernel_ulong_t)&ad4088_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad4080_id);
|
||||
@@ -677,10 +718,13 @@ MODULE_DEVICE_TABLE(spi, ad4080_id);
|
||||
static const struct of_device_id ad4080_of_match[] = {
|
||||
{ .compatible = "adi,ad4080", &ad4080_chip_info },
|
||||
{ .compatible = "adi,ad4081", &ad4081_chip_info },
|
||||
{ .compatible = "adi,ad4082", &ad4082_chip_info },
|
||||
{ .compatible = "adi,ad4083", &ad4083_chip_info },
|
||||
{ .compatible = "adi,ad4084", &ad4084_chip_info },
|
||||
{ .compatible = "adi,ad4085", &ad4085_chip_info },
|
||||
{ .compatible = "adi,ad4086", &ad4086_chip_info },
|
||||
{ .compatible = "adi,ad4087", &ad4087_chip_info },
|
||||
{ .compatible = "adi,ad4088", &ad4088_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad4080_of_match);
|
||||
|
||||
@@ -275,9 +275,9 @@ static const unsigned int ad4170_reg_size[] = {
|
||||
};
|
||||
|
||||
enum ad4170_ref_buf {
|
||||
AD4170_REF_BUF_PRE, /* Pre-charge referrence buffer */
|
||||
AD4170_REF_BUF_FULL, /* Full referrence buffering */
|
||||
AD4170_REF_BUF_BYPASS, /* Bypass referrence buffering */
|
||||
AD4170_REF_BUF_PRE, /* Pre-charge reference buffer */
|
||||
AD4170_REF_BUF_FULL, /* Full reference buffering */
|
||||
AD4170_REF_BUF_BYPASS, /* Bypass reference buffering */
|
||||
};
|
||||
|
||||
/* maps adi,positive/negative-reference-buffer property values to enum */
|
||||
|
||||
@@ -1763,7 +1763,8 @@ static int ad7173_validate_openwire_ain_inputs(struct ad7173_state *st,
|
||||
static unsigned int ad7173_calc_openwire_thrsh_raw(struct ad7173_state *st,
|
||||
struct iio_chan_spec *chan,
|
||||
struct ad7173_channel *chan_st_priv,
|
||||
unsigned int thrsh_mv) {
|
||||
unsigned int thrsh_mv)
|
||||
{
|
||||
unsigned int thrsh_raw;
|
||||
|
||||
thrsh_raw =
|
||||
|
||||
@@ -1402,9 +1402,6 @@ static int ad7192_probe(struct spi_device *spi)
|
||||
st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI;
|
||||
|
||||
st->chip_info = spi_get_device_match_data(spi);
|
||||
if (!st->chip_info)
|
||||
return -ENODEV;
|
||||
|
||||
indio_dev->name = st->chip_info->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = st->chip_info->info;
|
||||
|
||||
@@ -409,10 +409,8 @@ static int ad7266_probe(struct spi_device *spi)
|
||||
st->gpios[i] = devm_gpiod_get(&spi->dev,
|
||||
ad7266_gpio_labels[i],
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->gpios[i])) {
|
||||
ret = PTR_ERR(st->gpios[i]);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(st->gpios[i]))
|
||||
return PTR_ERR(st->gpios[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -77,8 +77,7 @@
|
||||
#define AD7380_CONFIG1_REFSEL BIT(1)
|
||||
#define AD7380_CONFIG1_PMODE BIT(0)
|
||||
|
||||
#define AD7380_CONFIG2_SDO2 GENMASK(9, 8)
|
||||
#define AD7380_CONFIG2_SDO BIT(8)
|
||||
#define AD7380_CONFIG2_SDO GENMASK(9, 8)
|
||||
#define AD7380_CONFIG2_RESET GENMASK(7, 0)
|
||||
|
||||
#define AD7380_CONFIG2_RESET_SOFT 0x3C
|
||||
@@ -92,11 +91,6 @@
|
||||
#define T_CONVERT_X_NS 500 /* xth conversion start time (oversampling) */
|
||||
#define T_POWERUP_US 5000 /* Power up */
|
||||
|
||||
/*
|
||||
* AD738x support several SDO lines to increase throughput, but driver currently
|
||||
* supports only 1 SDO line (standard SPI transaction)
|
||||
*/
|
||||
#define AD7380_NUM_SDO_LINES 1
|
||||
#define AD7380_DEFAULT_GAIN_MILLI 1000
|
||||
|
||||
/*
|
||||
@@ -888,6 +882,8 @@ struct ad7380_state {
|
||||
bool resolution_boost_enabled;
|
||||
unsigned int ch;
|
||||
bool seq;
|
||||
/* How many SDO lines are wired up. */
|
||||
u8 num_sdo_lines;
|
||||
unsigned int vref_mv;
|
||||
unsigned int vcm_mv[MAX_NUM_CHANNELS];
|
||||
unsigned int gain_milli[MAX_NUM_CHANNELS];
|
||||
@@ -1084,7 +1080,7 @@ static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch)
|
||||
if (oversampling_ratio > 1)
|
||||
xfer.delay.value = T_CONVERT_0_NS +
|
||||
T_CONVERT_X_NS * (oversampling_ratio - 1) *
|
||||
st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES;
|
||||
st->chip_info->num_simult_channels / st->num_sdo_lines;
|
||||
|
||||
return spi_sync_transfer(st->spi, &xfer, 1);
|
||||
}
|
||||
@@ -1113,7 +1109,7 @@ static int ad7380_update_xfers(struct ad7380_state *st,
|
||||
if (oversampling_ratio > 1)
|
||||
t_convert = T_CONVERT_0_NS + T_CONVERT_X_NS *
|
||||
(oversampling_ratio - 1) *
|
||||
st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES;
|
||||
st->chip_info->num_simult_channels / st->num_sdo_lines;
|
||||
|
||||
if (st->seq) {
|
||||
xfer[0].delay.value = xfer[1].delay.value = t_convert;
|
||||
@@ -1198,6 +1194,8 @@ static int ad7380_init_offload_msg(struct ad7380_state *st,
|
||||
xfer->bits_per_word = scan_type->realbits;
|
||||
xfer->offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
|
||||
xfer->len = AD7380_SPI_BYTES(scan_type) * st->chip_info->num_simult_channels;
|
||||
if (st->num_sdo_lines > 1)
|
||||
xfer->multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
|
||||
|
||||
spi_message_init_with_transfers(&st->offload_msg, xfer, 1);
|
||||
st->offload_msg.offload = st->offload;
|
||||
@@ -1793,6 +1791,7 @@ static const struct iio_info ad7380_info = {
|
||||
|
||||
static int ad7380_init(struct ad7380_state *st, bool external_ref_en)
|
||||
{
|
||||
u32 sdo;
|
||||
int ret;
|
||||
|
||||
/* perform hard reset */
|
||||
@@ -1815,11 +1814,24 @@ static int ad7380_init(struct ad7380_state *st, bool external_ref_en)
|
||||
st->ch = 0;
|
||||
st->seq = false;
|
||||
|
||||
/* SPI 1-wire mode */
|
||||
/* SDO field has an irregular mapping. */
|
||||
switch (st->num_sdo_lines) {
|
||||
case 1:
|
||||
sdo = 1;
|
||||
break;
|
||||
case 2:
|
||||
sdo = 0;
|
||||
break;
|
||||
case 4:
|
||||
sdo = 2;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
|
||||
AD7380_CONFIG2_SDO,
|
||||
FIELD_PREP(AD7380_CONFIG2_SDO,
|
||||
AD7380_NUM_SDO_LINES));
|
||||
FIELD_PREP(AD7380_CONFIG2_SDO, sdo));
|
||||
}
|
||||
|
||||
static int ad7380_probe_spi_offload(struct iio_dev *indio_dev,
|
||||
@@ -1842,7 +1854,7 @@ static int ad7380_probe_spi_offload(struct iio_dev *indio_dev,
|
||||
"failed to get offload trigger\n");
|
||||
|
||||
sample_rate = st->chip_info->max_conversion_rate_hz *
|
||||
AD7380_NUM_SDO_LINES / st->chip_info->num_simult_channels;
|
||||
st->num_sdo_lines / st->chip_info->num_simult_channels;
|
||||
|
||||
st->sample_freq_range[0] = 1; /* min */
|
||||
st->sample_freq_range[1] = 1; /* step */
|
||||
@@ -1850,7 +1862,7 @@ static int ad7380_probe_spi_offload(struct iio_dev *indio_dev,
|
||||
|
||||
/*
|
||||
* Starting with a quite low frequency, to allow oversampling x32,
|
||||
* user is then reponsible to adjust the frequency for the specific case.
|
||||
* user is then responsible to adjust the frequency for the specific case.
|
||||
*/
|
||||
ret = ad7380_set_sample_freq(st, sample_rate / 32);
|
||||
if (ret)
|
||||
@@ -1887,6 +1899,13 @@ static int ad7380_probe(struct spi_device *spi)
|
||||
if (!st->chip_info)
|
||||
return dev_err_probe(dev, -EINVAL, "missing match data\n");
|
||||
|
||||
st->num_sdo_lines = spi->num_rx_lanes;
|
||||
|
||||
if (st->num_sdo_lines < 1 || st->num_sdo_lines > st->chip_info->num_simult_channels)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"invalid number of SDO lines (%d)\n",
|
||||
st->num_sdo_lines);
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(dev, st->chip_info->num_supplies,
|
||||
st->chip_info->supplies);
|
||||
|
||||
@@ -2010,6 +2029,8 @@ static int ad7380_probe(struct spi_device *spi)
|
||||
st->normal_xfer[0].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
|
||||
st->normal_xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
st->normal_xfer[1].rx_buf = st->scan_data;
|
||||
if (st->num_sdo_lines > 1)
|
||||
st->normal_xfer[1].multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
|
||||
|
||||
spi_message_init_with_transfers(&st->normal_msg, st->normal_xfer,
|
||||
ARRAY_SIZE(st->normal_xfer));
|
||||
@@ -2031,6 +2052,10 @@ static int ad7380_probe(struct spi_device *spi)
|
||||
st->seq_xfer[2].cs_change = 1;
|
||||
st->seq_xfer[2].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
|
||||
st->seq_xfer[2].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
if (st->num_sdo_lines > 1) {
|
||||
st->seq_xfer[2].multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
|
||||
st->seq_xfer[3].multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
|
||||
}
|
||||
|
||||
spi_message_init_with_transfers(&st->seq_msg, st->seq_xfer,
|
||||
ARRAY_SIZE(st->seq_xfer));
|
||||
|
||||
@@ -25,12 +25,15 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/spi/offload/consumer.h>
|
||||
#include <linux/spi/offload/provider.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/units.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/buffer-dmaengine.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
@@ -161,6 +164,8 @@ enum ad7768_filter_regval {
|
||||
enum ad7768_scan_type {
|
||||
AD7768_SCAN_TYPE_NORMAL,
|
||||
AD7768_SCAN_TYPE_HIGH_SPEED,
|
||||
AD7768_SCAN_TYPE_OFFLOAD_NORMAL,
|
||||
AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -266,6 +271,18 @@ static const struct iio_scan_type ad7768_scan_type[] = {
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_BE,
|
||||
},
|
||||
[AD7768_SCAN_TYPE_OFFLOAD_NORMAL] = {
|
||||
.sign = 's',
|
||||
.realbits = 24,
|
||||
.storagebits = 32,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
[AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED] = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 32,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
};
|
||||
|
||||
struct ad7768_chip_info {
|
||||
@@ -283,6 +300,8 @@ struct ad7768_chip_info {
|
||||
|
||||
struct ad7768_state {
|
||||
struct spi_device *spi;
|
||||
struct spi_offload *offload;
|
||||
struct spi_offload_trigger *offload_trigger;
|
||||
struct regmap *regmap;
|
||||
struct regmap *regmap24;
|
||||
int vref_uv;
|
||||
@@ -290,7 +309,6 @@ struct ad7768_state {
|
||||
unsigned int vcm_output_sel;
|
||||
struct clk *mclk;
|
||||
unsigned int mclk_freq;
|
||||
unsigned int mclk_div;
|
||||
unsigned int oversampling_ratio;
|
||||
enum ad7768_filter_type filter_type;
|
||||
unsigned int samp_freq;
|
||||
@@ -306,6 +324,8 @@ struct ad7768_state {
|
||||
struct gpio_desc *gpio_reset;
|
||||
const char *labels[AD7768_MAX_CHANNELS];
|
||||
struct gpio_chip gpiochip;
|
||||
struct spi_transfer offload_xfer;
|
||||
struct spi_message offload_msg;
|
||||
const struct ad7768_chip_info *chip;
|
||||
bool en_spi_sync;
|
||||
struct mutex pga_lock; /* protect device internal state (PGA) */
|
||||
@@ -464,13 +484,11 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
|
||||
int readval, ret;
|
||||
|
||||
reinit_completion(&st->completion);
|
||||
|
||||
ret = ad7768_set_mode(st, AD7768_ONE_SHOT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
enable_irq(st->spi->irq);
|
||||
|
||||
ret = wait_for_completion_timeout(&st->completion,
|
||||
msecs_to_jiffies(1000));
|
||||
disable_irq(st->spi->irq);
|
||||
if (!ret)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
@@ -487,14 +505,6 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
|
||||
if (st->oversampling_ratio == 8)
|
||||
readval >>= 8;
|
||||
|
||||
/*
|
||||
* Any SPI configuration of the AD7768-1 can only be
|
||||
* performed in continuous conversion mode.
|
||||
*/
|
||||
ret = ad7768_set_mode(st, AD7768_CONTINUOUS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return readval;
|
||||
}
|
||||
|
||||
@@ -1138,6 +1148,10 @@ static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev,
|
||||
{
|
||||
struct ad7768_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (st->offload)
|
||||
return st->oversampling_ratio == 8 ?
|
||||
AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED : AD7768_SCAN_TYPE_OFFLOAD_NORMAL;
|
||||
|
||||
return st->oversampling_ratio == 8 ?
|
||||
AD7768_SCAN_TYPE_HIGH_SPEED : AD7768_SCAN_TYPE_NORMAL;
|
||||
}
|
||||
@@ -1252,6 +1266,10 @@ static int ad7768_setup(struct iio_dev *indio_dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad7768_set_mode(st, AD7768_CONTINUOUS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* For backwards compatibility, try the adi,sync-in-gpios property */
|
||||
st->gpio_sync_in = devm_gpiod_get_optional(&st->spi->dev, "adi,sync-in",
|
||||
GPIOD_OUT_LOW);
|
||||
@@ -1356,8 +1374,94 @@ static const struct iio_buffer_setup_ops ad7768_buffer_ops = {
|
||||
.predisable = &ad7768_buffer_predisable,
|
||||
};
|
||||
|
||||
static int ad7768_offload_buffer_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad7768_state *st = iio_priv(indio_dev);
|
||||
struct spi_offload_trigger_config config = {
|
||||
.type = SPI_OFFLOAD_TRIGGER_DATA_READY,
|
||||
};
|
||||
const struct iio_scan_type *scan_type;
|
||||
unsigned int unused;
|
||||
int ret;
|
||||
|
||||
scan_type = iio_get_current_scan_type(indio_dev, &indio_dev->channels[0]);
|
||||
if (IS_ERR(scan_type))
|
||||
return PTR_ERR(scan_type);
|
||||
|
||||
st->offload_xfer.len = spi_bpw_to_bytes(scan_type->realbits);
|
||||
st->offload_xfer.bits_per_word = scan_type->realbits;
|
||||
st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
|
||||
|
||||
spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1);
|
||||
st->offload_msg.offload = st->offload;
|
||||
|
||||
ret = spi_optimize_message(st->spi, &st->offload_msg);
|
||||
if (ret) {
|
||||
dev_err(&st->spi->dev, "failed to prepare offload, err: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a 1 to the LSB of the INTERFACE_FORMAT register to enter
|
||||
* continuous read mode. Subsequent data reads do not require an
|
||||
* initial 8-bit write to query the ADC_DATA register.
|
||||
*/
|
||||
ret = regmap_write(st->regmap, AD7768_REG_INTERFACE_FORMAT, 0x01);
|
||||
if (ret)
|
||||
goto err_unoptimize_message;
|
||||
|
||||
ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
|
||||
&config);
|
||||
if (ret)
|
||||
goto err_exit_continuous_read_mode;
|
||||
|
||||
return 0;
|
||||
|
||||
err_exit_continuous_read_mode:
|
||||
regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused);
|
||||
|
||||
err_unoptimize_message:
|
||||
spi_unoptimize_message(&st->offload_msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7768_offload_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad7768_state *st = iio_priv(indio_dev);
|
||||
unsigned int unused;
|
||||
|
||||
spi_offload_trigger_disable(st->offload, st->offload_trigger);
|
||||
spi_unoptimize_message(&st->offload_msg);
|
||||
|
||||
/*
|
||||
* To exit continuous read mode, perform a single read of the ADC_DATA
|
||||
* reg (0x2C), which allows further configuration of the device.
|
||||
*/
|
||||
return regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops ad7768_offload_buffer_ops = {
|
||||
.postenable = ad7768_offload_buffer_postenable,
|
||||
.predisable = ad7768_offload_buffer_predisable,
|
||||
};
|
||||
|
||||
static int ad7768_set_trigger_state(struct iio_trigger *trig, bool enable)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct ad7768_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (enable)
|
||||
enable_irq(st->spi->irq);
|
||||
else
|
||||
disable_irq(st->spi->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_trigger_ops ad7768_trigger_ops = {
|
||||
.validate_device = iio_trigger_validate_own_device,
|
||||
.set_trigger_state = ad7768_set_trigger_state,
|
||||
};
|
||||
|
||||
static int ad7768_set_channel_label(struct iio_dev *indio_dev,
|
||||
@@ -1590,6 +1694,36 @@ static int ad7768_parse_aaf_gain(struct device *dev, struct ad7768_state *st)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ad7768_offload_trigger_match(struct spi_offload_trigger *trigger,
|
||||
enum spi_offload_trigger_type type,
|
||||
u64 *args, u32 nargs)
|
||||
{
|
||||
if (type != SPI_OFFLOAD_TRIGGER_DATA_READY)
|
||||
return false;
|
||||
|
||||
/* Up to 2 args are allowed, but only 1 is used */
|
||||
if (nargs == 0 || nargs > 2 || args[0] != AD7768_TRIGGER_SOURCE_DRDY)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ad7768_offload_trigger_request(struct spi_offload_trigger *trigger,
|
||||
enum spi_offload_trigger_type type,
|
||||
u64 *args, u32 nargs)
|
||||
{
|
||||
/* Should already be validated by match, but just in case */
|
||||
if (nargs == 0 || nargs > 2)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_offload_trigger_ops ad7768_offload_trigger_ops = {
|
||||
.match = ad7768_offload_trigger_match,
|
||||
.request = ad7768_offload_trigger_request,
|
||||
};
|
||||
|
||||
static const struct ad7768_chip_info ad7768_chip_info = {
|
||||
.name = "ad7768-1",
|
||||
.channel_spec = ad7768_channels,
|
||||
@@ -1627,10 +1761,51 @@ static const struct ad7768_chip_info adaq7769_chip_info = {
|
||||
.has_variable_aaf = true,
|
||||
};
|
||||
|
||||
static const struct spi_offload_config ad7768_spi_offload_config = {
|
||||
.capability_flags = SPI_OFFLOAD_CAP_TRIGGER | SPI_OFFLOAD_CAP_RX_STREAM_DMA,
|
||||
};
|
||||
|
||||
static int ad7768_spi_offload_probe(struct iio_dev *indio_dev,
|
||||
struct ad7768_state *st)
|
||||
{
|
||||
struct device *dev = &st->spi->dev;
|
||||
struct spi_offload_trigger_info trigger_info = {
|
||||
.fwnode = dev_fwnode(dev),
|
||||
.ops = &ad7768_offload_trigger_ops,
|
||||
.priv = st,
|
||||
};
|
||||
struct dma_chan *rx_dma;
|
||||
int ret;
|
||||
|
||||
ret = devm_spi_offload_trigger_register(dev, &trigger_info);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to register offload trigger\n");
|
||||
|
||||
st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload,
|
||||
SPI_OFFLOAD_TRIGGER_DATA_READY);
|
||||
if (IS_ERR(st->offload_trigger))
|
||||
return dev_err_probe(dev, PTR_ERR(st->offload_trigger),
|
||||
"failed to get offload trigger\n");
|
||||
|
||||
rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload);
|
||||
if (IS_ERR(rx_dma))
|
||||
return dev_err_probe(dev, PTR_ERR(rx_dma), "failed to get offload RX DMA\n");
|
||||
|
||||
ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma,
|
||||
IIO_BUFFER_DIRECTION_IN);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to setup offload RX DMA\n");
|
||||
|
||||
indio_dev->setup_ops = &ad7768_offload_buffer_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7768_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad7768_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
struct device *dev = &spi->dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
@@ -1721,14 +1896,25 @@ static int ad7768_probe(struct spi_device *spi)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_irq(&spi->dev, spi->irq, &ad7768_interrupt,
|
||||
IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
|
||||
IRQF_TRIGGER_RISING | IRQF_NO_THREAD | IRQF_NO_AUTOEN,
|
||||
indio_dev->name, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad7768_triggered_buffer_alloc(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
st->offload = devm_spi_offload_get(dev, spi, &ad7768_spi_offload_config);
|
||||
ret = PTR_ERR_OR_ZERO(st->offload);
|
||||
if (ret == -ENODEV) {
|
||||
/* If not using SPI offload, fall back to low speed usage */
|
||||
ret = ad7768_triggered_buffer_alloc(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (ret) {
|
||||
return dev_err_probe(dev, ret, "failed to get SPI offload\n");
|
||||
} else {
|
||||
ret = ad7768_spi_offload_probe(indio_dev, st);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
@@ -1764,3 +1950,4 @@ module_spi_driver(ad7768_driver);
|
||||
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD7768-1 ADC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
|
||||
|
||||
@@ -152,7 +152,6 @@ struct ad7793_chip_info {
|
||||
|
||||
struct ad7793_state {
|
||||
const struct ad7793_chip_info *chip_info;
|
||||
u16 int_vref_mv;
|
||||
u16 mode;
|
||||
u16 conf;
|
||||
u32 scale_avail[8][2];
|
||||
@@ -805,7 +804,7 @@ static int ad7793_probe(struct spi_device *spi)
|
||||
|
||||
vref_mv = ret / 1000;
|
||||
} else {
|
||||
vref_mv = 1170; /* Build-in ref */
|
||||
vref_mv = 1170; /* Built-in ref */
|
||||
}
|
||||
|
||||
st->chip_info =
|
||||
|
||||
@@ -104,7 +104,7 @@ static int ad7887_ring_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad7887_state *st = iio_priv(indio_dev);
|
||||
|
||||
/* dummy read: restore default CH0 settin */
|
||||
/* dummy read: restore default CH0 settings */
|
||||
return spi_sync(st->spi, &st->msg[AD7887_CH0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#define AD7923_PM_MODE_AS (1) /* auto shutdown */
|
||||
#define AD7923_PM_MODE_FS (2) /* full shutdown */
|
||||
#define AD7923_PM_MODE_OPS (3) /* normal operation */
|
||||
#define AD7923_SEQUENCE_OFF (0) /* no sequence fonction */
|
||||
#define AD7923_SEQUENCE_OFF (0) /* no sequence function */
|
||||
#define AD7923_SEQUENCE_PROTECT (2) /* no interrupt write cycle */
|
||||
#define AD7923_SEQUENCE_ON (3) /* continuous sequence */
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#define AD7923_CHANNEL_WRITE(channel) ((channel) << 6) /* write channel */
|
||||
#define AD7923_SEQUENCE_WRITE(sequence) ((((sequence) & 1) << 3) \
|
||||
+ (((sequence) & 2) << 9))
|
||||
/* write sequence fonction */
|
||||
/* write sequence function */
|
||||
/* left shift for CR : bit 11 transmit in first */
|
||||
#define AD7923_SHIFT_REGISTER 4
|
||||
|
||||
|
||||
@@ -176,7 +176,6 @@ struct ad9467_state {
|
||||
struct clk *clk;
|
||||
/* used for debugfs */
|
||||
struct ad9467_chan_test_mode *chan_test;
|
||||
unsigned int output_mode;
|
||||
unsigned int (*scales)[2];
|
||||
/*
|
||||
* Times 2 because we may also invert the signal polarity and run the
|
||||
@@ -925,7 +924,11 @@ static int __ad9467_update_clock(struct ad9467_state *st, long r_clk)
|
||||
return ret;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
return ad9467_calibrate(st);
|
||||
|
||||
if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION))
|
||||
return ad9467_calibrate(st);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad9467_write_raw(struct iio_dev *indio_dev,
|
||||
@@ -1131,12 +1134,15 @@ static ssize_t ad9467_chan_test_mode_read(struct file *file,
|
||||
len = scnprintf(buf, sizeof(buf), "Running \"%s\" Test:\n\t",
|
||||
ad9467_test_modes[chan->mode]);
|
||||
|
||||
ret = iio_backend_debugfs_print_chan_status(st->back, chan->idx,
|
||||
buf + len,
|
||||
sizeof(buf) - len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret;
|
||||
if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) {
|
||||
ret = iio_backend_debugfs_print_chan_status(st->back,
|
||||
chan->idx,
|
||||
buf + len,
|
||||
sizeof(buf) - len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret;
|
||||
}
|
||||
} else if (chan->mode == AN877_ADC_TESTMODE_OFF) {
|
||||
len = scnprintf(buf, sizeof(buf), "No test Running...\n");
|
||||
} else {
|
||||
@@ -1175,11 +1181,13 @@ static ssize_t ad9467_chan_test_mode_write(struct file *file,
|
||||
if (mode == AN877_ADC_TESTMODE_OFF) {
|
||||
unsigned int out_mode;
|
||||
|
||||
if (chan->mode == AN877_ADC_TESTMODE_PN9_SEQ ||
|
||||
chan->mode == AN877_ADC_TESTMODE_PN23_SEQ) {
|
||||
ret = ad9467_backend_testmode_off(st, chan->idx);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) {
|
||||
if (chan->mode == AN877_ADC_TESTMODE_PN9_SEQ ||
|
||||
chan->mode == AN877_ADC_TESTMODE_PN23_SEQ) {
|
||||
ret = ad9467_backend_testmode_off(st, chan->idx);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ad9467_testmode_set(st, chan->idx, mode);
|
||||
@@ -1205,16 +1213,18 @@ static ssize_t ad9467_chan_test_mode_write(struct file *file,
|
||||
return ret;
|
||||
|
||||
/* some patterns have a backend matching monitoring block */
|
||||
if (mode == AN877_ADC_TESTMODE_PN9_SEQ) {
|
||||
ret = ad9467_backend_testmode_on(st, chan->idx,
|
||||
if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) {
|
||||
if (mode == AN877_ADC_TESTMODE_PN9_SEQ) {
|
||||
ret = ad9467_backend_testmode_on(st, chan->idx,
|
||||
IIO_BACKEND_ADI_PRBS_9A);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (mode == AN877_ADC_TESTMODE_PN23_SEQ) {
|
||||
ret = ad9467_backend_testmode_on(st, chan->idx,
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (mode == AN877_ADC_TESTMODE_PN23_SEQ) {
|
||||
ret = ad9467_backend_testmode_on(st, chan->idx,
|
||||
IIO_BACKEND_ADI_PRBS_23A);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1280,8 +1290,9 @@ static void ad9467_debugfs_init(struct iio_dev *indio_dev)
|
||||
if (!st->chan_test)
|
||||
return;
|
||||
|
||||
debugfs_create_file("calibration_table_dump", 0400, d, st,
|
||||
&ad9467_calib_table_fops);
|
||||
if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION))
|
||||
debugfs_create_file("calibration_table_dump", 0400, d, st,
|
||||
&ad9467_calib_table_fops);
|
||||
|
||||
for (chan = 0; chan < st->info->num_channels; chan++) {
|
||||
snprintf(attr_name, sizeof(attr_name), "in_voltage%u_test_mode",
|
||||
@@ -1300,12 +1311,13 @@ static void ad9467_debugfs_init(struct iio_dev *indio_dev)
|
||||
|
||||
static int ad9467_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad9467_state *st;
|
||||
unsigned int id;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1320,16 +1332,15 @@ static int ad9467_probe(struct spi_device *spi)
|
||||
if (AD9467_CAN_INVERT(st))
|
||||
st->calib_map_size *= 2;
|
||||
|
||||
st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk");
|
||||
st->clk = devm_clk_get_enabled(dev, "adc-clk");
|
||||
if (IS_ERR(st->clk))
|
||||
return PTR_ERR(st->clk);
|
||||
|
||||
st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
|
||||
GPIOD_OUT_LOW);
|
||||
st->pwrdown_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->pwrdown_gpio))
|
||||
return PTR_ERR(st->pwrdown_gpio);
|
||||
|
||||
ret = ad9467_reset(&spi->dev);
|
||||
ret = ad9467_reset(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1339,7 +1350,7 @@ static int ad9467_probe(struct spi_device *spi)
|
||||
|
||||
id = ad9467_spi_read(st, AN877_ADC_REG_CHIP_ID);
|
||||
if (id != st->info->id) {
|
||||
dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n",
|
||||
dev_err(dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n",
|
||||
id, st->info->id);
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1356,19 +1367,25 @@ static int ad9467_probe(struct spi_device *spi)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_backend_request_buffer(&spi->dev, st->back, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_BUFFER)) {
|
||||
ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_iio_backend_enable(&spi->dev, st->back);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_ENABLE)) {
|
||||
ret = devm_iio_backend_enable(dev, st->back);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad9467_calibrate(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) {
|
||||
ret = ad9467_calibrate(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_iio_device_register(&spi->dev, indio_dev);
|
||||
ret = devm_iio_device_register(dev, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -51,8 +51,10 @@
|
||||
*/
|
||||
void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, u8 comm)
|
||||
{
|
||||
/* Some variants use the lower two bits of the communications register
|
||||
* to select the channel */
|
||||
/*
|
||||
* Some variants use the lower two bits of the communications register
|
||||
* to select the channel.
|
||||
*/
|
||||
sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ad_sd_set_comm, "IIO_AD_SIGMA_DELTA");
|
||||
|
||||
@@ -218,9 +218,6 @@
|
||||
#define ADE9000_ST1_ERROR1_BIT BIT(29)
|
||||
#define ADE9000_ST1_ERROR2_BIT BIT(30)
|
||||
#define ADE9000_ST1_ERROR3_BIT BIT(31)
|
||||
#define ADE9000_ST_ERROR \
|
||||
(ADE9000_ST1_ERROR0 | ADE9000_ST1_ERROR1 | \
|
||||
ADE9000_ST1_ERROR2 | ADE9000_ST1_ERROR3)
|
||||
#define ADE9000_ST1_CROSSING_FIRST 6
|
||||
#define ADE9000_ST1_CROSSING_DEPTH 25
|
||||
|
||||
@@ -283,7 +280,6 @@ enum ade9000_wfb_cfg {
|
||||
#define ADE9000_PHASE_C_POS_BIT BIT(6)
|
||||
|
||||
#define ADE9000_MAX_PHASE_NR 3
|
||||
#define AD9000_CHANNELS_PER_PHASE 10
|
||||
|
||||
/*
|
||||
* Calculate register address for multi-phase device.
|
||||
@@ -1549,7 +1545,7 @@ static int ade9000_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
|
||||
ret = regmap_clear_bits(st->regmap, ADE9000_REG_MASK0, interrupts);
|
||||
if (ret) {
|
||||
dev_err(dev, "Post-disable update maks0 fail\n");
|
||||
dev_err(dev, "Post-disable update mask0 fail\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1589,10 +1585,9 @@ static int ade9000_reset(struct ade9000_state *st)
|
||||
/* Only wait for completion if IRQ1 is available to signal reset done */
|
||||
if (fwnode_irq_get_byname(dev_fwnode(dev), "irq1") >= 0) {
|
||||
if (!wait_for_completion_timeout(&st->reset_completion,
|
||||
msecs_to_jiffies(1000))) {
|
||||
dev_err(dev, "Reset timeout after 1s\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
msecs_to_jiffies(1000)))
|
||||
return dev_err_probe(dev, -ETIMEDOUT,
|
||||
"Reset timeout after 1s\n");
|
||||
}
|
||||
/* If no IRQ available, reset is already complete after the 50ms delay above */
|
||||
|
||||
|
||||
@@ -621,6 +621,8 @@ static const struct iio_backend_ops adi_axi_adc_ops = {
|
||||
static const struct iio_backend_info adi_axi_adc_generic = {
|
||||
.name = "axi-adc",
|
||||
.ops = &adi_axi_adc_ops,
|
||||
.caps = IIO_BACKEND_CAP_CALIBRATION | IIO_BACKEND_CAP_BUFFER |
|
||||
IIO_BACKEND_CAP_ENABLE,
|
||||
};
|
||||
|
||||
static const struct iio_backend_ops adi_ad485x_ops = {
|
||||
@@ -645,6 +647,8 @@ static const struct iio_backend_ops adi_ad485x_ops = {
|
||||
static const struct iio_backend_info axi_ad485x = {
|
||||
.name = "axi-ad485x",
|
||||
.ops = &adi_ad485x_ops,
|
||||
.caps = IIO_BACKEND_CAP_CALIBRATION | IIO_BACKEND_CAP_BUFFER |
|
||||
IIO_BACKEND_CAP_ENABLE,
|
||||
};
|
||||
|
||||
static const struct iio_backend_ops adi_ad408x_ops = {
|
||||
@@ -665,6 +669,7 @@ static const struct iio_backend_ops adi_ad408x_ops = {
|
||||
static const struct iio_backend_info axi_ad408x = {
|
||||
.name = "axi-ad408x",
|
||||
.ops = &adi_ad408x_ops,
|
||||
.caps = IIO_BACKEND_CAP_BUFFER | IIO_BACKEND_CAP_ENABLE,
|
||||
};
|
||||
|
||||
static int adi_axi_adc_probe(struct platform_device *pdev)
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
|
||||
#define ASPEED_ADC_INIT_POLLING_TIME 500
|
||||
#define ASPEED_ADC_INIT_TIMEOUT 500000
|
||||
/* Battery sensing is typically on the last channel */
|
||||
#define ASPEED_ADC_BATTERY_CHANNEL 7
|
||||
/*
|
||||
* When the sampling rate is too high, the ADC may not have enough charging
|
||||
* time, resulting in a low voltage value. Thus, the default uses a slow
|
||||
@@ -121,6 +123,31 @@ struct aspeed_adc_data {
|
||||
struct adc_gain battery_mode_gain;
|
||||
};
|
||||
|
||||
/*
|
||||
* Enable multiple consecutive channels starting from channel 0.
|
||||
* This creates a bitmask for channels 0 to (num_channels - 1).
|
||||
* For example: num_channels=3 creates mask 0x0007 (channels 0,1,2)
|
||||
*/
|
||||
static inline u32 aspeed_adc_channels_mask(unsigned int num_channels)
|
||||
{
|
||||
if (num_channels > 16)
|
||||
return GENMASK(15, 0);
|
||||
|
||||
return BIT(num_channels) - 1;
|
||||
}
|
||||
|
||||
static inline unsigned int aspeed_adc_get_active_channels(const struct aspeed_adc_data *data)
|
||||
{
|
||||
/*
|
||||
* For controllers with battery sensing capability, the last channel
|
||||
* is reserved for battery sensing and should not be included in
|
||||
* normal channel operations.
|
||||
*/
|
||||
if (data->model_data->bat_sense_sup)
|
||||
return data->model_data->num_channels - 1;
|
||||
return data->model_data->num_channels;
|
||||
}
|
||||
|
||||
#define ASPEED_CHAN(_idx, _data_reg_addr) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
@@ -236,10 +263,10 @@ static int aspeed_adc_compensation(struct iio_dev *indio_dev)
|
||||
ASPEED_ADC_CTRL_CHANNEL_ENABLE(0),
|
||||
data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
/*
|
||||
* After enable compensating sensing mode need to wait some time for ADC stable
|
||||
* Experiment result is 1ms.
|
||||
* After enable compensating sensing mode need to wait some time for the
|
||||
* ADC stablize. Experiment result is 1ms.
|
||||
*/
|
||||
mdelay(1);
|
||||
fsleep(1000);
|
||||
|
||||
for (index = 0; index < 16; index++) {
|
||||
/*
|
||||
@@ -285,31 +312,48 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (data->battery_sensing && chan->channel == 7) {
|
||||
adc_engine_control_reg_val =
|
||||
readl(data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
adc_engine_control_reg_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
/*
|
||||
* For battery sensing capable controllers, we need to enable
|
||||
* the specific channel before reading. This is required because
|
||||
* the battery channel may not be enabled by default.
|
||||
*/
|
||||
if (data->model_data->bat_sense_sup &&
|
||||
chan->channel == ASPEED_ADC_BATTERY_CHANNEL) {
|
||||
u32 ctrl_reg = adc_engine_control_reg_val & ~ASPEED_ADC_CTRL_CHANNEL;
|
||||
|
||||
ctrl_reg |= ASPEED_ADC_CTRL_CHANNEL_ENABLE(chan->channel);
|
||||
writel(ctrl_reg, data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
/*
|
||||
* After enable a new channel need to wait some time for ADC stable
|
||||
* Experiment result is 1ms.
|
||||
*/
|
||||
fsleep(1000);
|
||||
}
|
||||
|
||||
if (data->battery_sensing && chan->channel == ASPEED_ADC_BATTERY_CHANNEL) {
|
||||
writel(adc_engine_control_reg_val |
|
||||
FIELD_PREP(ASPEED_ADC_CH7_MODE,
|
||||
ASPEED_ADC_CH7_BAT) |
|
||||
ASPEED_ADC_BAT_SENSING_ENABLE,
|
||||
data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
/*
|
||||
* After enable battery sensing mode need to wait some time for adc stable
|
||||
* After enable battery sensing mode need to wait some time for ADC stable
|
||||
* Experiment result is 1ms.
|
||||
*/
|
||||
mdelay(1);
|
||||
fsleep(1000);
|
||||
*val = readw(data->base + chan->address);
|
||||
*val = (*val * data->battery_mode_gain.mult) /
|
||||
data->battery_mode_gain.div;
|
||||
/* Restore control register value */
|
||||
writel(adc_engine_control_reg_val,
|
||||
data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
} else
|
||||
*val = readw(data->base + chan->address);
|
||||
/* Restore control register value */
|
||||
writel(adc_engine_control_reg_val,
|
||||
data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
if (data->battery_sensing && chan->channel == 7)
|
||||
if (data->battery_sensing && chan->channel == ASPEED_ADC_BATTERY_CHANNEL)
|
||||
*val = (data->cv * data->battery_mode_gain.mult) /
|
||||
data->battery_mode_gain.div;
|
||||
else
|
||||
@@ -610,7 +654,9 @@ static int aspeed_adc_probe(struct platform_device *pdev)
|
||||
/* Start all channels in normal mode. */
|
||||
adc_engine_control_reg_val =
|
||||
readl(data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
adc_engine_control_reg_val |= ASPEED_ADC_CTRL_CHANNEL;
|
||||
FIELD_MODIFY(ASPEED_ADC_CTRL_CHANNEL, &adc_engine_control_reg_val,
|
||||
aspeed_adc_channels_mask(aspeed_adc_get_active_channels(data)));
|
||||
|
||||
writel(adc_engine_control_reg_val,
|
||||
data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
|
||||
|
||||
@@ -2259,7 +2259,7 @@ static int at91_adc_temp_sensor_init(struct at91_adc_state *st,
|
||||
return 0;
|
||||
|
||||
/* Get the calibration data from NVMEM. */
|
||||
temp_calib = devm_nvmem_cell_get(dev, "temperature_calib");
|
||||
temp_calib = nvmem_cell_get(dev, "temperature_calib");
|
||||
if (IS_ERR(temp_calib)) {
|
||||
ret = PTR_ERR(temp_calib);
|
||||
if (ret != -ENOENT)
|
||||
@@ -2268,6 +2268,7 @@ static int at91_adc_temp_sensor_init(struct at91_adc_state *st,
|
||||
}
|
||||
|
||||
buf = nvmem_cell_read(temp_calib, &len);
|
||||
nvmem_cell_put(temp_calib);
|
||||
if (IS_ERR(buf)) {
|
||||
dev_err(dev, "Failed to read calibration data!\n");
|
||||
return PTR_ERR(buf);
|
||||
@@ -2507,7 +2508,7 @@ static int at91_adc_suspend(struct device *dev)
|
||||
at91_adc_buffer_postdisable(indio_dev);
|
||||
|
||||
/*
|
||||
* Do a sofware reset of the ADC before we go to suspend.
|
||||
* Do a software reset of the ADC before we go to suspend.
|
||||
* this will ensure that all pins are free from being muxed by the ADC
|
||||
* and can be used by for other devices.
|
||||
* Otherwise, ADC will hog them and we can't go to suspend mode.
|
||||
|
||||
@@ -171,7 +171,7 @@ struct at91_adc_trigger {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct at91_adc_reg_desc - Various informations relative to registers
|
||||
* struct at91_adc_reg_desc - Various information relative to registers
|
||||
* @channel_base: Base offset for the channel data registers
|
||||
* @drdy_mask: Mask of the DRDY field in the relevant registers
|
||||
* (Interruptions registers mostly)
|
||||
@@ -231,7 +231,7 @@ struct at91_adc_state {
|
||||
struct iio_trigger **trig;
|
||||
bool use_external;
|
||||
u32 vref_mv;
|
||||
u32 res; /* resolution used for convertions */
|
||||
u32 res; /* resolution used for conversions */
|
||||
wait_queue_head_t wq_data_avail;
|
||||
const struct at91_adc_caps *caps;
|
||||
|
||||
@@ -304,7 +304,7 @@ static void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
|
||||
}
|
||||
}
|
||||
|
||||
static int at91_ts_sample(struct iio_dev *idev)
|
||||
static void at91_ts_sample(struct iio_dev *idev)
|
||||
{
|
||||
struct at91_adc_state *st = iio_priv(idev);
|
||||
unsigned int xscale, yscale, reg, z1, z2;
|
||||
@@ -323,7 +323,7 @@ static int at91_ts_sample(struct iio_dev *idev)
|
||||
xscale = (reg >> 16) & xyz_mask;
|
||||
if (xscale == 0) {
|
||||
dev_err(&idev->dev, "Error: xscale == 0!\n");
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
x /= xscale;
|
||||
|
||||
@@ -334,7 +334,7 @@ static int at91_ts_sample(struct iio_dev *idev)
|
||||
yscale = (reg >> 16) & xyz_mask;
|
||||
if (yscale == 0) {
|
||||
dev_err(&idev->dev, "Error: yscale == 0!\n");
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
y /= yscale;
|
||||
|
||||
@@ -363,8 +363,6 @@ static int at91_ts_sample(struct iio_dev *idev)
|
||||
} else {
|
||||
dev_dbg(&idev->dev, "pressure too low: not reporting\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t at91_adc_rl_interrupt(int irq, void *private)
|
||||
|
||||
@@ -934,6 +934,17 @@ static const struct cpcap_adc_ato mapphone_adc = {
|
||||
.atox_ps_factor_out = 0,
|
||||
};
|
||||
|
||||
static const struct cpcap_adc_ato mot_adc = {
|
||||
.ato_in = 0x0300,
|
||||
.atox_in = 0,
|
||||
.adc_ps_factor_in = 0x0200,
|
||||
.atox_ps_factor_in = 0,
|
||||
.ato_out = 0x0780,
|
||||
.atox_out = 0,
|
||||
.adc_ps_factor_out = 0x0600,
|
||||
.atox_ps_factor_out = 0,
|
||||
};
|
||||
|
||||
static const struct of_device_id cpcap_adc_id_table[] = {
|
||||
{
|
||||
.compatible = "motorola,cpcap-adc",
|
||||
@@ -942,6 +953,10 @@ static const struct of_device_id cpcap_adc_id_table[] = {
|
||||
.compatible = "motorola,mapphone-cpcap-adc",
|
||||
.data = &mapphone_adc,
|
||||
},
|
||||
{
|
||||
.compatible = "motorola,mot-cpcap-adc",
|
||||
.data = &mot_adc,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cpcap_adc_id_table);
|
||||
|
||||
@@ -47,7 +47,7 @@ struct mx25_gcq_priv {
|
||||
* of register writes, then a wait for a completion callback,
|
||||
* and finally a register read, during which userspace could issue
|
||||
* another read request. This lock protects a read access from
|
||||
* ocurring before another one has finished.
|
||||
* occurring before another one has finished.
|
||||
*/
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
@@ -121,7 +121,7 @@ static const struct regmap_config ina2xx_regmap_config = {
|
||||
.volatile_reg = ina2xx_is_volatile_reg,
|
||||
};
|
||||
|
||||
enum ina2xx_ids { ina219, ina226 };
|
||||
enum ina2xx_ids { ina219, ina226, ina236 };
|
||||
|
||||
struct ina2xx_config {
|
||||
const char *name;
|
||||
@@ -175,6 +175,16 @@ static const struct ina2xx_config ina2xx_config[] = {
|
||||
.power_lsb_factor = 25,
|
||||
.chip_id = ina226,
|
||||
},
|
||||
[ina236] = {
|
||||
.name = "ina236",
|
||||
.config_default = INA226_CONFIG_DEFAULT,
|
||||
.calibration_value = 2048,
|
||||
.shunt_voltage_lsb = 2500,
|
||||
.bus_voltage_shift = 0,
|
||||
.bus_voltage_lsb = 1600,
|
||||
.power_lsb_factor = 32,
|
||||
.chip_id = ina236,
|
||||
},
|
||||
};
|
||||
|
||||
static int ina2xx_read_raw(struct iio_dev *indio_dev,
|
||||
@@ -499,20 +509,26 @@ static int ina2xx_write_raw(struct iio_dev *indio_dev,
|
||||
break;
|
||||
|
||||
case IIO_CHAN_INFO_INT_TIME:
|
||||
if (chip->config->chip_id == ina226) {
|
||||
switch (chip->config->chip_id) {
|
||||
case ina226:
|
||||
case ina236:
|
||||
if (chan->address == INA2XX_SHUNT_VOLTAGE)
|
||||
ret = ina226_set_int_time_vshunt(chip, val2,
|
||||
&tmp);
|
||||
else
|
||||
ret = ina226_set_int_time_vbus(chip, val2,
|
||||
&tmp);
|
||||
} else {
|
||||
break;
|
||||
case ina219:
|
||||
if (chan->address == INA2XX_SHUNT_VOLTAGE)
|
||||
ret = ina219_set_int_time_vshunt(chip, val2,
|
||||
&tmp);
|
||||
else
|
||||
ret = ina219_set_int_time_vbus(chip, val2,
|
||||
&tmp);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -727,19 +743,27 @@ static int ina2xx_conversion_ready(struct iio_dev *indio_dev)
|
||||
* For now, we do an extra read of the MASK_ENABLE register (INA226)
|
||||
* resp. the BUS_VOLTAGE register (INA219).
|
||||
*/
|
||||
if (chip->config->chip_id == ina226) {
|
||||
switch (chip->config->chip_id) {
|
||||
case ina226:
|
||||
case ina236:
|
||||
ret = regmap_read(chip->regmap,
|
||||
INA226_MASK_ENABLE, &alert);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
alert &= INA226_CVRF;
|
||||
} else {
|
||||
break;
|
||||
case ina219:
|
||||
ret = regmap_read(chip->regmap,
|
||||
INA2XX_BUS_VOLTAGE, &alert);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
alert &= INA219_CNVR;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !!alert;
|
||||
}
|
||||
|
||||
@@ -998,16 +1022,22 @@ static int ina2xx_probe(struct i2c_client *client)
|
||||
/* Patch the current config register with default. */
|
||||
val = chip->config->config_default;
|
||||
|
||||
if (type == ina226) {
|
||||
switch (type) {
|
||||
case ina226:
|
||||
case ina236:
|
||||
ina226_set_average(chip, INA226_DEFAULT_AVG, &val);
|
||||
ina226_set_int_time_vbus(chip, INA226_DEFAULT_IT, &val);
|
||||
ina226_set_int_time_vshunt(chip, INA226_DEFAULT_IT, &val);
|
||||
} else {
|
||||
break;
|
||||
case ina219:
|
||||
chip->avg = 1;
|
||||
ina219_set_int_time_vbus(chip, INA219_DEFAULT_IT, &val);
|
||||
ina219_set_int_time_vshunt(chip, INA219_DEFAULT_IT, &val);
|
||||
ina219_set_vbus_range_denom(chip, INA219_DEFAULT_BRNG, &val);
|
||||
ina219_set_vshunt_pga_gain(chip, INA219_DEFAULT_PGA, &val);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ina2xx_init(chip, val);
|
||||
@@ -1017,14 +1047,20 @@ static int ina2xx_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
if (type == ina226) {
|
||||
switch (type) {
|
||||
case ina226:
|
||||
case ina236:
|
||||
indio_dev->channels = ina226_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ina226_channels);
|
||||
indio_dev->info = &ina226_info;
|
||||
} else {
|
||||
break;
|
||||
case ina219:
|
||||
indio_dev->channels = ina219_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ina219_channels);
|
||||
indio_dev->info = &ina219_info;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
indio_dev->name = id ? id->name : chip->config->name;
|
||||
|
||||
@@ -1057,6 +1093,7 @@ static const struct i2c_device_id ina2xx_id[] = {
|
||||
{ "ina226", ina226 },
|
||||
{ "ina230", ina226 },
|
||||
{ "ina231", ina226 },
|
||||
{ "ina236", ina236 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ina2xx_id);
|
||||
@@ -1082,6 +1119,10 @@ static const struct of_device_id ina2xx_of_match[] = {
|
||||
.compatible = "ti,ina231",
|
||||
.data = (void *)ina226
|
||||
},
|
||||
{
|
||||
.compatible = "ti,ina236",
|
||||
.data = (void *)ina236
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ina2xx_of_match);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* The LTC2305 is a 2-Channel, 12-Bit SAR ADC with an I2C Interface.
|
||||
* The LTC2309 is an 8-Channel, 12-Bit SAR ADC with an I2C Interface.
|
||||
*
|
||||
* Datasheet:
|
||||
* https://www.analog.com/media/en/technical-documentation/data-sheets/23015fb.pdf
|
||||
* https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf
|
||||
*
|
||||
* Copyright (c) 2023, Liam Beguin <liambeguin@gmail.com>
|
||||
@@ -41,23 +43,30 @@ struct ltc2309 {
|
||||
};
|
||||
|
||||
/* Order matches expected channel address, See datasheet Table 1. */
|
||||
enum ltc2305_channels {
|
||||
LTC2305_CH0_CH1 = 0x0,
|
||||
LTC2305_CH1_CH0 = 0x4,
|
||||
LTC2305_CH0 = 0x8,
|
||||
LTC2305_CH1 = 0xc,
|
||||
};
|
||||
|
||||
enum ltc2309_channels {
|
||||
LTC2309_CH0_CH1 = 0,
|
||||
LTC2309_CH2_CH3,
|
||||
LTC2309_CH4_CH5,
|
||||
LTC2309_CH6_CH7,
|
||||
LTC2309_CH1_CH0,
|
||||
LTC2309_CH3_CH2,
|
||||
LTC2309_CH5_CH4,
|
||||
LTC2309_CH7_CH6,
|
||||
LTC2309_CH0,
|
||||
LTC2309_CH2,
|
||||
LTC2309_CH4,
|
||||
LTC2309_CH6,
|
||||
LTC2309_CH1,
|
||||
LTC2309_CH3,
|
||||
LTC2309_CH5,
|
||||
LTC2309_CH7,
|
||||
LTC2309_CH0_CH1 = 0x0,
|
||||
LTC2309_CH2_CH3 = 0x1,
|
||||
LTC2309_CH4_CH5 = 0x2,
|
||||
LTC2309_CH6_CH7 = 0x3,
|
||||
LTC2309_CH1_CH0 = 0x4,
|
||||
LTC2309_CH3_CH2 = 0x5,
|
||||
LTC2309_CH5_CH4 = 0x6,
|
||||
LTC2309_CH7_CH6 = 0x7,
|
||||
LTC2309_CH0 = 0x8,
|
||||
LTC2309_CH2 = 0x9,
|
||||
LTC2309_CH4 = 0xa,
|
||||
LTC2309_CH6 = 0xb,
|
||||
LTC2309_CH1 = 0xc,
|
||||
LTC2309_CH3 = 0xd,
|
||||
LTC2309_CH5 = 0xe,
|
||||
LTC2309_CH7 = 0xf,
|
||||
};
|
||||
|
||||
#define LTC2309_CHAN(_chan, _addr) { \
|
||||
@@ -80,6 +89,13 @@ enum ltc2309_channels {
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec ltc2305_channels[] = {
|
||||
LTC2309_CHAN(0, LTC2305_CH0),
|
||||
LTC2309_CHAN(1, LTC2305_CH1),
|
||||
LTC2309_DIFF_CHAN(0, 1, LTC2305_CH0_CH1),
|
||||
LTC2309_DIFF_CHAN(1, 0, LTC2305_CH1_CH0),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ltc2309_channels[] = {
|
||||
LTC2309_CHAN(0, LTC2309_CH0),
|
||||
LTC2309_CHAN(1, LTC2309_CH1),
|
||||
@@ -99,6 +115,24 @@ static const struct iio_chan_spec ltc2309_channels[] = {
|
||||
LTC2309_DIFF_CHAN(7, 6, LTC2309_CH7_CH6),
|
||||
};
|
||||
|
||||
struct ltc2309_chip_info {
|
||||
const char *name;
|
||||
const struct iio_chan_spec *channels;
|
||||
int num_channels;
|
||||
};
|
||||
|
||||
static const struct ltc2309_chip_info ltc2305_chip_info = {
|
||||
.name = "ltc2305",
|
||||
.channels = ltc2305_channels,
|
||||
.num_channels = ARRAY_SIZE(ltc2305_channels),
|
||||
};
|
||||
|
||||
static const struct ltc2309_chip_info ltc2309_chip_info = {
|
||||
.name = "ltc2309",
|
||||
.channels = ltc2309_channels,
|
||||
.num_channels = ARRAY_SIZE(ltc2309_channels),
|
||||
};
|
||||
|
||||
static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309,
|
||||
unsigned long address, int *val)
|
||||
{
|
||||
@@ -158,6 +192,7 @@ static const struct iio_info ltc2309_info = {
|
||||
|
||||
static int ltc2309_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct ltc2309_chip_info *chip_info;
|
||||
struct iio_dev *indio_dev;
|
||||
struct ltc2309 *ltc2309;
|
||||
int ret;
|
||||
@@ -167,13 +202,15 @@ static int ltc2309_probe(struct i2c_client *client)
|
||||
return -ENOMEM;
|
||||
|
||||
ltc2309 = iio_priv(indio_dev);
|
||||
chip_info = i2c_get_match_data(client);
|
||||
|
||||
ltc2309->dev = &indio_dev->dev;
|
||||
ltc2309->client = client;
|
||||
|
||||
indio_dev->name = "ltc2309";
|
||||
indio_dev->name = chip_info->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = ltc2309_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels);
|
||||
indio_dev->channels = chip_info->channels;
|
||||
indio_dev->num_channels = chip_info->num_channels;
|
||||
indio_dev->info = <c2309_info;
|
||||
|
||||
ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref");
|
||||
@@ -189,13 +226,15 @@ static int ltc2309_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct of_device_id ltc2309_of_match[] = {
|
||||
{ .compatible = "lltc,ltc2309" },
|
||||
{ .compatible = "lltc,ltc2305", .data = <c2305_chip_info },
|
||||
{ .compatible = "lltc,ltc2309", .data = <c2309_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltc2309_of_match);
|
||||
|
||||
static const struct i2c_device_id ltc2309_id[] = {
|
||||
{ "ltc2309" },
|
||||
{ "ltc2305", (kernel_ulong_t)<c2305_chip_info },
|
||||
{ "ltc2309", (kernel_ulong_t)<c2309_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc2309_id);
|
||||
|
||||
@@ -912,8 +912,8 @@ static int max11410_self_calibrate(struct max11410_state *st)
|
||||
|
||||
static int max11410_probe(struct spi_device *spi)
|
||||
{
|
||||
const char *vrefp_regs[] = { "vref0p", "vref1p", "vref2p" };
|
||||
const char *vrefn_regs[] = { "vref0n", "vref1n", "vref2n" };
|
||||
static const char * const vrefp_regs[] = { "vref0p", "vref1p", "vref2p" };
|
||||
static const char * const vrefn_regs[] = { "vref0n", "vref1n", "vref2n" };
|
||||
struct device *dev = &spi->dev;
|
||||
struct max11410_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
|
||||
@@ -121,7 +121,7 @@ enum max1363_modes {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct max1363_chip_info - chip specifc information
|
||||
* struct max1363_chip_info - chip specific information
|
||||
* @info: iio core function callbacks structure
|
||||
* @channels: channel specification
|
||||
* @num_channels: number of channels
|
||||
@@ -149,7 +149,6 @@ struct max1363_chip_info {
|
||||
* @configbyte: cache of current device config byte
|
||||
* @chip_info: chip model specific constants, available modes, etc.
|
||||
* @current_mode: the scan mode of this chip
|
||||
* @requestedmask: a valid requested set of channels
|
||||
* @lock: lock to ensure state is consistent
|
||||
* @monitor_on: whether monitor mode is enabled
|
||||
* @monitor_speed: parameter corresponding to device monitor speed setting
|
||||
@@ -169,7 +168,6 @@ struct max1363_state {
|
||||
u8 configbyte;
|
||||
const struct max1363_chip_info *chip_info;
|
||||
const struct max1363_mode *current_mode;
|
||||
u32 requestedmask;
|
||||
struct mutex lock;
|
||||
|
||||
/* Using monitor modes and buffer at the same time is
|
||||
@@ -637,48 +635,51 @@ static const enum max1363_modes max11644_mode_list[] = {
|
||||
static const struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10);
|
||||
static const struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12);
|
||||
|
||||
enum { max1361,
|
||||
max1362,
|
||||
max1363,
|
||||
max1364,
|
||||
max1036,
|
||||
max1037,
|
||||
max1038,
|
||||
max1039,
|
||||
max1136,
|
||||
max1137,
|
||||
max1138,
|
||||
max1139,
|
||||
max1236,
|
||||
max1237,
|
||||
max1238,
|
||||
max1239,
|
||||
max11600,
|
||||
max11601,
|
||||
max11602,
|
||||
max11603,
|
||||
max11604,
|
||||
max11605,
|
||||
max11606,
|
||||
max11607,
|
||||
max11608,
|
||||
max11609,
|
||||
max11610,
|
||||
max11611,
|
||||
max11612,
|
||||
max11613,
|
||||
max11614,
|
||||
max11615,
|
||||
max11616,
|
||||
max11617,
|
||||
max11644,
|
||||
max11645,
|
||||
max11646,
|
||||
max11647
|
||||
enum {
|
||||
max1361,
|
||||
max1362,
|
||||
max1363,
|
||||
max1364,
|
||||
max1036,
|
||||
max1037,
|
||||
max1038,
|
||||
max1039,
|
||||
max1136,
|
||||
max1137,
|
||||
max1138,
|
||||
max1139,
|
||||
max1236,
|
||||
max1237,
|
||||
max1238,
|
||||
max1239,
|
||||
max11600,
|
||||
max11601,
|
||||
max11602,
|
||||
max11603,
|
||||
max11604,
|
||||
max11605,
|
||||
max11606,
|
||||
max11607,
|
||||
max11608,
|
||||
max11609,
|
||||
max11610,
|
||||
max11611,
|
||||
max11612,
|
||||
max11613,
|
||||
max11614,
|
||||
max11615,
|
||||
max11616,
|
||||
max11617,
|
||||
max11644,
|
||||
max11645,
|
||||
max11646,
|
||||
max11647,
|
||||
};
|
||||
|
||||
static const int max1363_monitor_speeds[] = { 133000, 665000, 33300, 16600,
|
||||
8300, 4200, 2000, 1000 };
|
||||
static const int max1363_monitor_speeds[] = {
|
||||
133000, 665000, 33300, 16600,
|
||||
8300, 4200, 2000, 1000,
|
||||
};
|
||||
|
||||
static ssize_t max1363_monitor_show_freq(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
|
||||
@@ -349,7 +349,7 @@ struct mcp3564_chip_info {
|
||||
* struct mcp3564_state - working data for a ADC device
|
||||
* @chip_info: chip specific data
|
||||
* @spi: SPI device structure
|
||||
* @vref_mv: voltage reference value in miliVolts
|
||||
* @vref_mv: voltage reference value in millivolts
|
||||
* @lock: synchronize access to driver's state members
|
||||
* @dev_addr: hardware device address
|
||||
* @oversampling: the index inside oversampling list of the ADC
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* MEN 16z188 Analog to Digial Converter
|
||||
* MEN 16z188 Analog to Digital Converter
|
||||
*
|
||||
* Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
|
||||
* Author: Johannes Thumshirn <johannes.thumshirn@men.de>
|
||||
|
||||
@@ -792,7 +792,7 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
|
||||
size_t read_len;
|
||||
int ret;
|
||||
|
||||
temperature_calib = devm_nvmem_cell_get(dev, "temperature_calib");
|
||||
temperature_calib = nvmem_cell_get(dev, "temperature_calib");
|
||||
if (IS_ERR(temperature_calib)) {
|
||||
ret = PTR_ERR(temperature_calib);
|
||||
|
||||
@@ -806,13 +806,9 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
|
||||
return dev_err_probe(dev, ret, "failed to get temperature_calib cell\n");
|
||||
}
|
||||
|
||||
priv->tsc_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "amlogic,hhi-sysctrl");
|
||||
if (IS_ERR(priv->tsc_regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->tsc_regmap),
|
||||
"failed to get amlogic,hhi-sysctrl regmap\n");
|
||||
|
||||
read_len = MESON_SAR_ADC_EFUSE_BYTES;
|
||||
buf = nvmem_cell_read(temperature_calib, &read_len);
|
||||
nvmem_cell_put(temperature_calib);
|
||||
if (IS_ERR(buf))
|
||||
return dev_err_probe(dev, PTR_ERR(buf), "failed to read temperature_calib cell\n");
|
||||
if (read_len != MESON_SAR_ADC_EFUSE_BYTES) {
|
||||
@@ -820,6 +816,11 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
|
||||
return dev_err_probe(dev, -EINVAL, "invalid read size of temperature_calib cell\n");
|
||||
}
|
||||
|
||||
priv->tsc_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "amlogic,hhi-sysctrl");
|
||||
if (IS_ERR(priv->tsc_regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->tsc_regmap),
|
||||
"failed to get amlogic,hhi-sysctrl regmap\n");
|
||||
|
||||
trimming_bits = priv->param->temperature_trimming_bits;
|
||||
trimming_mask = BIT(trimming_bits) - 1;
|
||||
|
||||
@@ -1313,6 +1314,11 @@ static const struct meson_sar_adc_data meson_sar_adc_g12a_data = {
|
||||
.name = "meson-g12a-saradc",
|
||||
};
|
||||
|
||||
static const struct meson_sar_adc_data meson_sar_adc_s4_data = {
|
||||
.param = &meson_sar_adc_g12a_param,
|
||||
.name = "meson-s4-saradc",
|
||||
};
|
||||
|
||||
static const struct of_device_id meson_sar_adc_of_match[] = {
|
||||
{
|
||||
.compatible = "amlogic,meson8-saradc",
|
||||
@@ -1341,6 +1347,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = {
|
||||
}, {
|
||||
.compatible = "amlogic,meson-g12a-saradc",
|
||||
.data = &meson_sar_adc_g12a_data,
|
||||
}, {
|
||||
.compatible = "amlogic,meson-s4-saradc",
|
||||
.data = &meson_sar_adc_s4_data,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -322,7 +322,7 @@ static const struct mtk_pmic_auxadc_chan mt6359_auxadc_ch_desc[] = {
|
||||
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2),
|
||||
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP1, 15, 8, 5, 2),
|
||||
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP1, 15 ,8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, PMIC_AUXADC_IMP1, 15, 8, 3, 2),
|
||||
MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP1, 15, 128, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP1, 15, 256, 1, 1),
|
||||
|
||||
@@ -55,7 +55,6 @@ struct nau7802_state {
|
||||
struct mutex data_lock;
|
||||
u32 vref_mv;
|
||||
u32 conversion_count;
|
||||
u32 min_conversions;
|
||||
u8 sample_rate;
|
||||
u32 scale_avail[8];
|
||||
struct completion value_ok;
|
||||
@@ -257,7 +256,7 @@ static int nau7802_read_poll(struct iio_dev *indio_dev,
|
||||
/*
|
||||
* Because there is actually only one ADC for both channels, we have to
|
||||
* wait for enough conversions to happen before getting a significant
|
||||
* value when changing channels and the values are far appart.
|
||||
* value when changing channels and the values are far apart.
|
||||
*/
|
||||
do {
|
||||
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
|
||||
|
||||
@@ -38,7 +38,7 @@ struct npcm_adc {
|
||||
* read access from userspace. Reading a raw value requires a sequence
|
||||
* of register writes, then a wait for a event and finally a register
|
||||
* read, during which userspace could issue another read request.
|
||||
* This lock protects a read access from ocurring before another one
|
||||
* This lock protects a read access from occurring before another one
|
||||
* has finished.
|
||||
*/
|
||||
struct mutex lock;
|
||||
|
||||
@@ -247,7 +247,8 @@ static inline void nxp_sar_adc_calibration_start(void __iomem *base)
|
||||
|
||||
static inline int nxp_sar_adc_calibration_wait(void __iomem *base)
|
||||
{
|
||||
u32 msr, ret;
|
||||
u32 msr;
|
||||
int ret;
|
||||
|
||||
ret = readl_poll_timeout(NXP_SAR_ADC_MSR(base), msr,
|
||||
!FIELD_GET(NXP_SAR_ADC_MSR_CALBUSY, msr),
|
||||
|
||||
@@ -856,7 +856,7 @@ static ssize_t pac1921_format_scale_avail(const int (*const scales_tbl)[2],
|
||||
/*
|
||||
* Read available scales for a specific channel
|
||||
*
|
||||
* NOTE: using extended info insted of iio.read_avail() because access to
|
||||
* NOTE: using extended info instead of iio.read_avail() because access to
|
||||
* current scales must be locked as they depend on shunt resistor which may
|
||||
* change runtime. Caller of iio.read_avail() would access the table unlocked
|
||||
* instead.
|
||||
|
||||
@@ -1351,7 +1351,7 @@ static int pac1934_prep_iio_channels(struct pac1934_chip_info *info, struct iio_
|
||||
|
||||
dyn_ch_struct = devm_kzalloc(dev, channel_size, GFP_KERNEL);
|
||||
if (!dyn_ch_struct)
|
||||
return -EINVAL;
|
||||
return -ENOMEM;
|
||||
|
||||
tmp_data = dyn_ch_struct;
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ struct palmas_gpadc_thresholds {
|
||||
* of register writes, then a wait for a completion callback,
|
||||
* and finally a register read, during which userspace could issue
|
||||
* another read request. This lock protects a read access from
|
||||
* ocurring before another one has finished.
|
||||
* occurring before another one has finished.
|
||||
*
|
||||
* This is the palmas_gpadc structure to store run-time information
|
||||
* and pointers for this driver instance.
|
||||
@@ -521,16 +521,16 @@ static int palmas_gpadc_get_low_threshold_raw(struct palmas_gpadc *adc,
|
||||
|
||||
val = (val * 1000) / adc->adc_info[adc_chan].gain;
|
||||
|
||||
if (adc->adc_info[adc_chan].is_uncalibrated) {
|
||||
if (adc->adc_info[adc_chan].is_uncalibrated) {
|
||||
/* 2% worse */
|
||||
min_gain_error -= 20;
|
||||
min_offset_error = -36;
|
||||
} else {
|
||||
} else {
|
||||
val = (val * adc->adc_info[adc_chan].gain_error -
|
||||
adc->adc_info[adc_chan].offset) /
|
||||
1000;
|
||||
min_offset_error = -2;
|
||||
}
|
||||
}
|
||||
|
||||
return palmas_gpadc_threshold_with_tolerance(val,
|
||||
min_INL,
|
||||
|
||||
860
drivers/iio/adc/qcom-spmi-adc5-gen3.c
Normal file
860
drivers/iio/adc/qcom-spmi-adc5-gen3.c
Normal file
@@ -0,0 +1,860 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/device/devres.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/iio/adc/qcom-adc5-gen3-common.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#define ADC5_GEN3_VADC_SDAM 0x0
|
||||
|
||||
struct adc5_chip;
|
||||
|
||||
/**
|
||||
* struct adc5_channel_prop - ADC channel structure
|
||||
* @common_props: structure with ADC channel properties (common to TM usage).
|
||||
* @adc_tm: indicates TM type if the channel is used for TM measurements.
|
||||
* @chip: pointer to top-level ADC device structure.
|
||||
*/
|
||||
struct adc5_channel_prop {
|
||||
struct adc5_channel_common_prop common_props;
|
||||
int adc_tm;
|
||||
struct adc5_chip *chip;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct adc5_chip - ADC private structure.
|
||||
* @dev: SPMI ADC5 Gen3 device.
|
||||
* @dev_data: Top-level ADC device data.
|
||||
* @nchannels: number of ADC channels.
|
||||
* @chan_props: array of ADC channel properties.
|
||||
* @iio_chans: array of IIO channels specification.
|
||||
* @complete: ADC result notification after interrupt is received.
|
||||
* @lock: ADC lock for access to the peripheral, to prevent concurrent
|
||||
* requests from multiple clients.
|
||||
* @data: software configuration data.
|
||||
* @n_tm_channels: number of ADC channels used for TM measurements.
|
||||
* @handler: TM callback to be called for threshold violation interrupt
|
||||
* on first SDAM.
|
||||
* @tm_aux: pointer to auxiliary TM device.
|
||||
*/
|
||||
struct adc5_chip {
|
||||
struct device *dev;
|
||||
struct adc5_device_data dev_data;
|
||||
unsigned int nchannels;
|
||||
struct adc5_channel_prop *chan_props;
|
||||
struct iio_chan_spec *iio_chans;
|
||||
struct completion complete;
|
||||
struct mutex lock;
|
||||
const struct adc5_data *data;
|
||||
unsigned int n_tm_channels;
|
||||
void (*handler)(struct auxiliary_device *tm_aux);
|
||||
struct auxiliary_device *tm_aux;
|
||||
};
|
||||
|
||||
int adc5_gen3_read(struct adc5_device_data *adc, unsigned int sdam_index,
|
||||
u16 offset, u8 *data, int len)
|
||||
{
|
||||
return regmap_bulk_read(adc->regmap,
|
||||
adc->base[sdam_index].base_addr + offset,
|
||||
data, len);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adc5_gen3_read, "QCOM_SPMI_ADC5_GEN3");
|
||||
|
||||
int adc5_gen3_write(struct adc5_device_data *adc, unsigned int sdam_index,
|
||||
u16 offset, u8 *data, int len)
|
||||
{
|
||||
return regmap_bulk_write(adc->regmap,
|
||||
adc->base[sdam_index].base_addr + offset,
|
||||
data, len);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adc5_gen3_write, "QCOM_SPMI_ADC5_GEN3");
|
||||
|
||||
static int adc5_gen3_read_voltage_data(struct adc5_chip *adc, u16 *data)
|
||||
{
|
||||
u8 rslt[2];
|
||||
int ret;
|
||||
|
||||
ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
|
||||
ADC5_GEN3_CH_DATA0(0), rslt, sizeof(rslt));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*data = get_unaligned_le16(rslt);
|
||||
|
||||
if (*data == ADC5_USR_DATA_CHECK) {
|
||||
dev_err(adc->dev, "Invalid data:%#x\n", *data);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(adc->dev, "voltage raw code:%#x\n", *data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void adc5_gen3_update_dig_param(struct adc5_channel_common_prop *prop, u8 *data)
|
||||
{
|
||||
/* Update calibration select and decimation ratio select */
|
||||
*data &= ~(ADC5_GEN3_DIG_PARAM_CAL_SEL_MASK | ADC5_GEN3_DIG_PARAM_DEC_RATIO_SEL_MASK);
|
||||
*data |= FIELD_PREP(ADC5_GEN3_DIG_PARAM_CAL_SEL_MASK, prop->cal_method);
|
||||
*data |= FIELD_PREP(ADC5_GEN3_DIG_PARAM_DEC_RATIO_SEL_MASK, prop->decimation);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adc5_gen3_update_dig_param, "QCOM_SPMI_ADC5_GEN3");
|
||||
|
||||
#define ADC5_GEN3_READ_CONFIG_REGS 7
|
||||
|
||||
static int adc5_gen3_configure(struct adc5_chip *adc,
|
||||
struct adc5_channel_common_prop *prop)
|
||||
{
|
||||
u8 buf[ADC5_GEN3_READ_CONFIG_REGS];
|
||||
u8 conv_req = 0;
|
||||
int ret;
|
||||
|
||||
ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM, ADC5_GEN3_SID,
|
||||
buf, sizeof(buf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Write SID */
|
||||
buf[0] = FIELD_PREP(ADC5_GEN3_SID_MASK, prop->sid);
|
||||
|
||||
/*
|
||||
* Use channel 0 by default for immediate conversion and to indicate
|
||||
* there is an actual conversion request
|
||||
*/
|
||||
buf[1] = ADC5_GEN3_CHAN_CONV_REQ | 0;
|
||||
|
||||
buf[2] = ADC5_GEN3_TIME_IMMEDIATE;
|
||||
|
||||
/* Digital param selection */
|
||||
adc5_gen3_update_dig_param(prop, &buf[3]);
|
||||
|
||||
/* Update fast average sample value */
|
||||
buf[4] = FIELD_PREP(ADC5_GEN3_FAST_AVG_CTL_SAMPLES_MASK,
|
||||
prop->avg_samples) | ADC5_GEN3_FAST_AVG_CTL_EN;
|
||||
|
||||
/* Select ADC channel */
|
||||
buf[5] = prop->channel;
|
||||
|
||||
/* Select HW settle delay for channel */
|
||||
buf[6] = FIELD_PREP(ADC5_GEN3_HW_SETTLE_DELAY_MASK,
|
||||
prop->hw_settle_time_us);
|
||||
|
||||
reinit_completion(&adc->complete);
|
||||
|
||||
ret = adc5_gen3_write(&adc->dev_data, ADC5_GEN3_VADC_SDAM, ADC5_GEN3_SID,
|
||||
buf, sizeof(buf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
conv_req = ADC5_GEN3_CONV_REQ_REQ;
|
||||
return adc5_gen3_write(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
|
||||
ADC5_GEN3_CONV_REQ, &conv_req, sizeof(conv_req));
|
||||
}
|
||||
|
||||
/*
|
||||
* Worst case delay from PBS in readying handshake bit can be up to 15ms, when
|
||||
* PBS is busy running other simultaneous transactions, while in the best case,
|
||||
* it is already ready at this point. Assigning polling delay and retry count
|
||||
* accordingly.
|
||||
*/
|
||||
|
||||
#define ADC5_GEN3_HS_DELAY_US 100
|
||||
#define ADC5_GEN3_HS_RETRY_COUNT 150
|
||||
|
||||
int adc5_gen3_poll_wait_hs(struct adc5_device_data *adc,
|
||||
unsigned int sdam_index)
|
||||
{
|
||||
u8 conv_req = ADC5_GEN3_CONV_REQ_REQ;
|
||||
int ret, count;
|
||||
u8 status = 0;
|
||||
|
||||
for (count = 0; count < ADC5_GEN3_HS_RETRY_COUNT; count++) {
|
||||
ret = adc5_gen3_read(adc, sdam_index, ADC5_GEN3_HS, &status, sizeof(status));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (status == ADC5_GEN3_HS_READY) {
|
||||
ret = adc5_gen3_read(adc, sdam_index, ADC5_GEN3_CONV_REQ,
|
||||
&conv_req, sizeof(conv_req));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!conv_req)
|
||||
return 0;
|
||||
}
|
||||
|
||||
fsleep(ADC5_GEN3_HS_DELAY_US);
|
||||
}
|
||||
|
||||
pr_err("Setting HS ready bit timed out, sdam_index:%d, status:%#x\n",
|
||||
sdam_index, status);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adc5_gen3_poll_wait_hs, "QCOM_SPMI_ADC5_GEN3");
|
||||
|
||||
int adc5_gen3_status_clear(struct adc5_device_data *adc,
|
||||
int sdam_index, u16 offset, u8 *val, int len)
|
||||
{
|
||||
u8 value;
|
||||
int ret;
|
||||
|
||||
ret = adc5_gen3_write(adc, sdam_index, offset, val, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* To indicate conversion request is only to clear a status */
|
||||
value = 0;
|
||||
ret = adc5_gen3_write(adc, sdam_index, ADC5_GEN3_PERPH_CH, &value,
|
||||
sizeof(value));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
value = ADC5_GEN3_CONV_REQ_REQ;
|
||||
return adc5_gen3_write(adc, sdam_index, ADC5_GEN3_CONV_REQ, &value,
|
||||
sizeof(value));
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adc5_gen3_status_clear, "QCOM_SPMI_ADC5_GEN3");
|
||||
|
||||
/*
|
||||
* Worst case delay from PBS for conversion time can be up to 500ms, when PBS
|
||||
* has timed out twice, once for the initial attempt and once for a retry of
|
||||
* the same transaction.
|
||||
*/
|
||||
|
||||
#define ADC5_GEN3_CONV_TIMEOUT_MS 501
|
||||
|
||||
static int adc5_gen3_do_conversion(struct adc5_chip *adc,
|
||||
struct adc5_channel_common_prop *prop,
|
||||
u16 *data_volt)
|
||||
{
|
||||
unsigned long rc;
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
guard(mutex)(&adc->lock);
|
||||
ret = adc5_gen3_poll_wait_hs(&adc->dev_data, ADC5_GEN3_VADC_SDAM);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adc5_gen3_configure(adc, prop);
|
||||
if (ret) {
|
||||
dev_err(adc->dev, "ADC configure failed with %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* No support for polling mode at present */
|
||||
rc = wait_for_completion_timeout(&adc->complete,
|
||||
msecs_to_jiffies(ADC5_GEN3_CONV_TIMEOUT_MS));
|
||||
if (!rc) {
|
||||
dev_err(adc->dev, "Reading ADC channel %s timed out\n",
|
||||
prop->label);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
ret = adc5_gen3_read_voltage_data(adc, data_volt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = BIT(0);
|
||||
return adc5_gen3_status_clear(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
|
||||
ADC5_GEN3_EOC_CLR, &val, 1);
|
||||
}
|
||||
|
||||
static irqreturn_t adc5_gen3_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct adc5_chip *adc = dev_id;
|
||||
struct device *dev = adc->dev;
|
||||
struct auxiliary_device *adev;
|
||||
u8 status, eoc_status, val;
|
||||
u8 tm_status[2];
|
||||
int ret;
|
||||
|
||||
ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
|
||||
ADC5_GEN3_STATUS1, &status, sizeof(status));
|
||||
if (ret) {
|
||||
dev_err(dev, "adc read status1 failed with %d\n", ret);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
|
||||
ADC5_GEN3_EOC_STS, &eoc_status, sizeof(eoc_status));
|
||||
if (ret) {
|
||||
dev_err(dev, "adc read eoc status failed with %d\n", ret);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (status & ADC5_GEN3_STATUS1_CONV_FAULT) {
|
||||
dev_err_ratelimited(dev,
|
||||
"Unexpected conversion fault, status:%#x, eoc_status:%#x\n",
|
||||
status, eoc_status);
|
||||
val = ADC5_GEN3_CONV_ERR_CLR_REQ;
|
||||
adc5_gen3_status_clear(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
|
||||
ADC5_GEN3_CONV_ERR_CLR, &val, 1);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* CHAN0 is the preconfigured channel for immediate conversion */
|
||||
if (eoc_status & ADC5_GEN3_EOC_CHAN_0)
|
||||
complete(&adc->complete);
|
||||
|
||||
ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM,
|
||||
ADC5_GEN3_TM_HIGH_STS, tm_status, sizeof(tm_status));
|
||||
if (ret) {
|
||||
dev_err(dev, "adc read TM status failed with %d\n", ret);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Interrupt status:%#x, EOC status:%#x, high:%#x, low:%#x\n",
|
||||
status, eoc_status, tm_status[0], tm_status[1]);
|
||||
|
||||
if (tm_status[0] || tm_status[1]) {
|
||||
adev = adc->tm_aux;
|
||||
if (!adev || !adev->dev.driver) {
|
||||
dev_err(dev, "adc_tm auxiliary device not initialized\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
adc->handler(adev);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int adc5_gen3_fwnode_xlate(struct iio_dev *indio_dev,
|
||||
const struct fwnode_reference_args *iiospec)
|
||||
{
|
||||
struct adc5_chip *adc = iio_priv(indio_dev);
|
||||
int i, v_channel;
|
||||
|
||||
for (i = 0; i < adc->nchannels; i++) {
|
||||
v_channel = ADC5_GEN3_V_CHAN(adc->chan_props[i].common_props);
|
||||
if (v_channel == iiospec->args[0])
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int adc5_gen3_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct adc5_chip *adc = iio_priv(indio_dev);
|
||||
struct adc5_channel_common_prop *prop;
|
||||
u16 adc_code_volt;
|
||||
int ret;
|
||||
|
||||
prop = &adc->chan_props[chan->address].common_props;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
ret = adc5_gen3_do_conversion(adc, prop, &adc_code_volt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = qcom_adc5_hw_scale(prop->scale_fn_type, prop->prescale,
|
||||
adc->data, adc_code_volt, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adc5_gen3_read_label(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, char *label)
|
||||
{
|
||||
struct adc5_chip *adc = iio_priv(indio_dev);
|
||||
struct adc5_channel_prop *prop;
|
||||
|
||||
prop = &adc->chan_props[chan->address];
|
||||
return sprintf(label, "%s\n", prop->common_props.label);
|
||||
}
|
||||
|
||||
static const struct iio_info adc5_gen3_info = {
|
||||
.read_raw = adc5_gen3_read_raw,
|
||||
.read_label = adc5_gen3_read_label,
|
||||
.fwnode_xlate = adc5_gen3_fwnode_xlate,
|
||||
};
|
||||
|
||||
struct adc5_channels {
|
||||
unsigned int prescale_index;
|
||||
enum iio_chan_type type;
|
||||
long info_mask;
|
||||
enum vadc_scale_fn_type scale_fn_type;
|
||||
};
|
||||
|
||||
/* In these definitions, _pre refers to an index into adc5_prescale_ratios. */
|
||||
#define ADC5_CHAN(_type, _mask, _pre, _scale) \
|
||||
{ \
|
||||
.prescale_index = _pre, \
|
||||
.type = _type, \
|
||||
.info_mask = _mask, \
|
||||
.scale_fn_type = _scale, \
|
||||
}, \
|
||||
|
||||
#define ADC5_CHAN_TEMP(_pre, _scale) \
|
||||
ADC5_CHAN(IIO_TEMP, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \
|
||||
|
||||
#define ADC5_CHAN_VOLT(_pre, _scale) \
|
||||
ADC5_CHAN(IIO_VOLTAGE, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \
|
||||
|
||||
#define ADC5_CHAN_CUR(_pre, _scale) \
|
||||
ADC5_CHAN(IIO_CURRENT, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \
|
||||
|
||||
static const struct adc5_channels adc5_gen3_chans_pmic[ADC5_MAX_CHANNEL] = {
|
||||
[ADC5_GEN3_REF_GND] = ADC5_CHAN_VOLT(0, SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_GEN3_1P25VREF] = ADC5_CHAN_VOLT(0, SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_GEN3_VPH_PWR] = ADC5_CHAN_VOLT(1, SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_GEN3_VBAT_SNS_QBG] = ADC5_CHAN_VOLT(1, SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_GEN3_USB_SNS_V_16] = ADC5_CHAN_TEMP(8, SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_GEN3_VIN_DIV16_MUX] = ADC5_CHAN_TEMP(8, SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_GEN3_DIE_TEMP] = ADC5_CHAN_TEMP(0,
|
||||
SCALE_HW_CALIB_PMIC_THERM_PM7)
|
||||
[ADC5_GEN3_AMUX1_THM_100K_PU] = ADC5_CHAN_TEMP(0,
|
||||
SCALE_HW_CALIB_THERM_100K_PU_PM7)
|
||||
[ADC5_GEN3_AMUX2_THM_100K_PU] = ADC5_CHAN_TEMP(0,
|
||||
SCALE_HW_CALIB_THERM_100K_PU_PM7)
|
||||
[ADC5_GEN3_AMUX3_THM_100K_PU] = ADC5_CHAN_TEMP(0,
|
||||
SCALE_HW_CALIB_THERM_100K_PU_PM7)
|
||||
[ADC5_GEN3_AMUX4_THM_100K_PU] = ADC5_CHAN_TEMP(0,
|
||||
SCALE_HW_CALIB_THERM_100K_PU_PM7)
|
||||
[ADC5_GEN3_AMUX5_THM_100K_PU] = ADC5_CHAN_TEMP(0,
|
||||
SCALE_HW_CALIB_THERM_100K_PU_PM7)
|
||||
[ADC5_GEN3_AMUX6_THM_100K_PU] = ADC5_CHAN_TEMP(0,
|
||||
SCALE_HW_CALIB_THERM_100K_PU_PM7)
|
||||
[ADC5_GEN3_AMUX1_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
|
||||
SCALE_HW_CALIB_THERM_100K_PU_PM7)
|
||||
[ADC5_GEN3_AMUX2_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
|
||||
SCALE_HW_CALIB_THERM_100K_PU_PM7)
|
||||
[ADC5_GEN3_AMUX3_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
|
||||
SCALE_HW_CALIB_THERM_100K_PU_PM7)
|
||||
[ADC5_GEN3_AMUX4_GPIO_100K_PU] = ADC5_CHAN_TEMP(0,
|
||||
SCALE_HW_CALIB_THERM_100K_PU_PM7)
|
||||
};
|
||||
|
||||
static int adc5_gen3_get_fw_channel_data(struct adc5_chip *adc,
|
||||
struct adc5_channel_prop *prop,
|
||||
struct fwnode_handle *fwnode)
|
||||
{
|
||||
const char *name = fwnode_get_name(fwnode);
|
||||
const struct adc5_data *data = adc->data;
|
||||
struct device *dev = adc->dev;
|
||||
const char *channel_name;
|
||||
u32 chan, value, sid;
|
||||
u32 varr[2];
|
||||
int ret;
|
||||
|
||||
ret = fwnode_property_read_u32(fwnode, "reg", &chan);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "invalid channel number %s\n",
|
||||
name);
|
||||
|
||||
/*
|
||||
* Value read from "reg" is virtual channel number
|
||||
* virtual channel number = sid << 8 | channel number
|
||||
*/
|
||||
sid = FIELD_GET(ADC5_GEN3_VIRTUAL_SID_MASK, chan);
|
||||
chan = FIELD_GET(ADC5_GEN3_CHANNEL_MASK, chan);
|
||||
|
||||
if (chan > ADC5_MAX_CHANNEL)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"%s invalid channel number %d\n",
|
||||
name, chan);
|
||||
|
||||
prop->common_props.channel = chan;
|
||||
prop->common_props.sid = sid;
|
||||
|
||||
if (!adc->data->adc_chans[chan].info_mask)
|
||||
return dev_err_probe(dev, -EINVAL, "Channel %#x not supported\n", chan);
|
||||
|
||||
channel_name = name;
|
||||
fwnode_property_read_string(fwnode, "label", &channel_name);
|
||||
prop->common_props.label = channel_name;
|
||||
|
||||
value = data->decimation[ADC5_DECIMATION_DEFAULT];
|
||||
fwnode_property_read_u32(fwnode, "qcom,decimation", &value);
|
||||
ret = qcom_adc5_decimation_from_dt(value, data->decimation);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "%#x invalid decimation %d\n",
|
||||
chan, value);
|
||||
prop->common_props.decimation = ret;
|
||||
|
||||
prop->common_props.prescale = adc->data->adc_chans[chan].prescale_index;
|
||||
ret = fwnode_property_read_u32_array(fwnode, "qcom,pre-scaling", varr, 2);
|
||||
if (!ret) {
|
||||
ret = qcom_adc5_prescaling_from_dt(varr[0], varr[1]);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret,
|
||||
"%#x invalid pre-scaling <%d %d>\n",
|
||||
chan, varr[0], varr[1]);
|
||||
prop->common_props.prescale = ret;
|
||||
}
|
||||
|
||||
value = data->hw_settle_1[VADC_DEF_HW_SETTLE_TIME];
|
||||
fwnode_property_read_u32(fwnode, "qcom,hw-settle-time", &value);
|
||||
ret = qcom_adc5_hw_settle_time_from_dt(value, data->hw_settle_1);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret,
|
||||
"%#x invalid hw-settle-time %d us\n",
|
||||
chan, value);
|
||||
prop->common_props.hw_settle_time_us = ret;
|
||||
|
||||
value = BIT(VADC_DEF_AVG_SAMPLES);
|
||||
fwnode_property_read_u32(fwnode, "qcom,avg-samples", &value);
|
||||
ret = qcom_adc5_avg_samples_from_dt(value);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "%#x invalid avg-samples %d\n",
|
||||
chan, value);
|
||||
prop->common_props.avg_samples = ret;
|
||||
|
||||
if (fwnode_property_read_bool(fwnode, "qcom,ratiometric"))
|
||||
prop->common_props.cal_method = ADC5_RATIOMETRIC_CAL;
|
||||
else
|
||||
prop->common_props.cal_method = ADC5_ABSOLUTE_CAL;
|
||||
|
||||
prop->adc_tm = fwnode_property_read_bool(fwnode, "qcom,adc-tm");
|
||||
if (prop->adc_tm) {
|
||||
adc->n_tm_channels++;
|
||||
if (adc->n_tm_channels > (adc->dev_data.num_sdams * 8 - 1))
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Number of TM nodes %u greater than channels supported:%u\n",
|
||||
adc->n_tm_channels,
|
||||
adc->dev_data.num_sdams * 8 - 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct adc5_data adc5_gen3_data_pmic = {
|
||||
.full_scale_code_volt = 0x70e4,
|
||||
.adc_chans = adc5_gen3_chans_pmic,
|
||||
.info = &adc5_gen3_info,
|
||||
.decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX])
|
||||
{ 85, 340, 1360 },
|
||||
.hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
|
||||
{ 15, 100, 200, 300,
|
||||
400, 500, 600, 700,
|
||||
1000, 2000, 4000, 8000,
|
||||
16000, 32000, 64000, 128000 },
|
||||
};
|
||||
|
||||
static const struct of_device_id adc5_match_table[] = {
|
||||
{
|
||||
.compatible = "qcom,spmi-adc5-gen3",
|
||||
.data = &adc5_gen3_data_pmic,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adc5_match_table);
|
||||
|
||||
static int adc5_get_fw_data(struct adc5_chip *adc)
|
||||
{
|
||||
const struct adc5_channels *adc_chan;
|
||||
struct adc5_channel_prop *chan_props;
|
||||
struct iio_chan_spec *iio_chan;
|
||||
struct device *dev = adc->dev;
|
||||
unsigned int index = 0;
|
||||
int ret;
|
||||
|
||||
adc->nchannels = device_get_child_node_count(dev);
|
||||
if (!adc->nchannels)
|
||||
return dev_err_probe(dev, -EINVAL, "No ADC channels found\n");
|
||||
|
||||
adc->iio_chans = devm_kcalloc(dev, adc->nchannels,
|
||||
sizeof(*adc->iio_chans), GFP_KERNEL);
|
||||
if (!adc->iio_chans)
|
||||
return -ENOMEM;
|
||||
|
||||
adc->chan_props = devm_kcalloc(dev, adc->nchannels,
|
||||
sizeof(*adc->chan_props), GFP_KERNEL);
|
||||
if (!adc->chan_props)
|
||||
return -ENOMEM;
|
||||
|
||||
chan_props = adc->chan_props;
|
||||
adc->n_tm_channels = 0;
|
||||
iio_chan = adc->iio_chans;
|
||||
adc->data = device_get_match_data(dev);
|
||||
|
||||
device_for_each_child_node_scoped(dev, child) {
|
||||
ret = adc5_gen3_get_fw_channel_data(adc, chan_props, child);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
chan_props->chip = adc;
|
||||
adc_chan = &adc->data->adc_chans[chan_props->common_props.channel];
|
||||
chan_props->common_props.scale_fn_type = adc_chan->scale_fn_type;
|
||||
|
||||
iio_chan->channel = ADC5_GEN3_V_CHAN(chan_props->common_props);
|
||||
iio_chan->info_mask_separate = adc_chan->info_mask;
|
||||
iio_chan->type = adc_chan->type;
|
||||
iio_chan->address = index;
|
||||
iio_chan->indexed = 1;
|
||||
iio_chan++;
|
||||
chan_props++;
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adc5_gen3_uninit_aux(void *data)
|
||||
{
|
||||
auxiliary_device_uninit(data);
|
||||
}
|
||||
|
||||
static void adc5_gen3_delete_aux(void *data)
|
||||
{
|
||||
auxiliary_device_delete(data);
|
||||
}
|
||||
|
||||
static void adc5_gen3_aux_device_release(struct device *dev) {}
|
||||
|
||||
static int adc5_gen3_add_aux_tm_device(struct adc5_chip *adc)
|
||||
{
|
||||
struct tm5_aux_dev_wrapper *aux_device;
|
||||
int i, ret, i_tm = 0;
|
||||
|
||||
aux_device = devm_kzalloc(adc->dev, sizeof(*aux_device), GFP_KERNEL);
|
||||
if (!aux_device)
|
||||
return -ENOMEM;
|
||||
|
||||
aux_device->aux_dev.name = "adc5_tm_gen3";
|
||||
aux_device->aux_dev.dev.parent = adc->dev;
|
||||
aux_device->aux_dev.dev.release = adc5_gen3_aux_device_release;
|
||||
|
||||
aux_device->tm_props = devm_kcalloc(adc->dev, adc->n_tm_channels,
|
||||
sizeof(*aux_device->tm_props),
|
||||
GFP_KERNEL);
|
||||
if (!aux_device->tm_props)
|
||||
return -ENOMEM;
|
||||
|
||||
aux_device->dev_data = &adc->dev_data;
|
||||
|
||||
for (i = 0; i < adc->nchannels; i++) {
|
||||
if (!adc->chan_props[i].adc_tm)
|
||||
continue;
|
||||
aux_device->tm_props[i_tm] = adc->chan_props[i].common_props;
|
||||
i_tm++;
|
||||
}
|
||||
|
||||
device_set_of_node_from_dev(&aux_device->aux_dev.dev, adc->dev);
|
||||
|
||||
aux_device->n_tm_channels = adc->n_tm_channels;
|
||||
|
||||
ret = auxiliary_device_init(&aux_device->aux_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(adc->dev, adc5_gen3_uninit_aux,
|
||||
&aux_device->aux_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = auxiliary_device_add(&aux_device->aux_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = devm_add_action_or_reset(adc->dev, adc5_gen3_delete_aux,
|
||||
&aux_device->aux_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adc->tm_aux = &aux_device->aux_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void adc5_gen3_mutex_lock(struct device *dev)
|
||||
__acquires(&adc->lock)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
|
||||
struct adc5_chip *adc = iio_priv(indio_dev);
|
||||
|
||||
mutex_lock(&adc->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adc5_gen3_mutex_lock, "QCOM_SPMI_ADC5_GEN3");
|
||||
|
||||
void adc5_gen3_mutex_unlock(struct device *dev)
|
||||
__releases(&adc->lock)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
|
||||
struct adc5_chip *adc = iio_priv(indio_dev);
|
||||
|
||||
mutex_unlock(&adc->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adc5_gen3_mutex_unlock, "QCOM_SPMI_ADC5_GEN3");
|
||||
|
||||
int adc5_gen3_get_scaled_reading(struct device *dev,
|
||||
struct adc5_channel_common_prop *common_props,
|
||||
int *val)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
|
||||
struct adc5_chip *adc = iio_priv(indio_dev);
|
||||
u16 adc_code_volt;
|
||||
int ret;
|
||||
|
||||
ret = adc5_gen3_do_conversion(adc, common_props, &adc_code_volt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return qcom_adc5_hw_scale(common_props->scale_fn_type,
|
||||
common_props->prescale,
|
||||
adc->data, adc_code_volt, val);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adc5_gen3_get_scaled_reading, "QCOM_SPMI_ADC5_GEN3");
|
||||
|
||||
int adc5_gen3_therm_code_to_temp(struct device *dev,
|
||||
struct adc5_channel_common_prop *common_props,
|
||||
u16 code, int *val)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
|
||||
struct adc5_chip *adc = iio_priv(indio_dev);
|
||||
|
||||
return qcom_adc5_hw_scale(common_props->scale_fn_type,
|
||||
common_props->prescale,
|
||||
adc->data, code, val);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adc5_gen3_therm_code_to_temp, "QCOM_SPMI_ADC5_GEN3");
|
||||
|
||||
void adc5_gen3_register_tm_event_notifier(struct device *dev,
|
||||
void (*handler)(struct auxiliary_device *))
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev->parent);
|
||||
struct adc5_chip *adc = iio_priv(indio_dev);
|
||||
|
||||
adc->handler = handler;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adc5_gen3_register_tm_event_notifier, "QCOM_SPMI_ADC5_GEN3");
|
||||
|
||||
static int adc5_gen3_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct adc5_chip *adc;
|
||||
struct regmap *regmap;
|
||||
int ret, i;
|
||||
u32 *reg;
|
||||
|
||||
regmap = dev_get_regmap(dev->parent, NULL);
|
||||
if (!regmap)
|
||||
return -ENODEV;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
adc = iio_priv(indio_dev);
|
||||
adc->dev_data.regmap = regmap;
|
||||
adc->dev = dev;
|
||||
|
||||
ret = device_property_count_u32(dev, "reg");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
adc->dev_data.num_sdams = ret;
|
||||
|
||||
reg = devm_kcalloc(dev, adc->dev_data.num_sdams, sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (!reg)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = device_property_read_u32_array(dev, "reg", reg,
|
||||
adc->dev_data.num_sdams);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to read reg property\n");
|
||||
|
||||
adc->dev_data.base = devm_kcalloc(dev, adc->dev_data.num_sdams,
|
||||
sizeof(*adc->dev_data.base),
|
||||
GFP_KERNEL);
|
||||
if (!adc->dev_data.base)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
init_completion(&adc->complete);
|
||||
ret = devm_mutex_init(dev, &adc->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < adc->dev_data.num_sdams; i++) {
|
||||
adc->dev_data.base[i].base_addr = reg[i];
|
||||
|
||||
ret = platform_get_irq(pdev, i);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Getting IRQ %d failed\n", i);
|
||||
|
||||
adc->dev_data.base[i].irq = ret;
|
||||
|
||||
adc->dev_data.base[i].irq_name = devm_kasprintf(dev, GFP_KERNEL,
|
||||
"sdam%d", i);
|
||||
if (!adc->dev_data.base[i].irq_name)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, adc->dev_data.base[ADC5_GEN3_VADC_SDAM].irq,
|
||||
adc5_gen3_isr, 0,
|
||||
adc->dev_data.base[ADC5_GEN3_VADC_SDAM].irq_name,
|
||||
adc);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to request SDAM%d irq\n",
|
||||
ADC5_GEN3_VADC_SDAM);
|
||||
|
||||
ret = adc5_get_fw_data(adc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adc->n_tm_channels > 0) {
|
||||
ret = adc5_gen3_add_aux_tm_device(adc);
|
||||
if (ret)
|
||||
dev_err_probe(dev, ret,
|
||||
"Failed to add auxiliary TM device\n");
|
||||
}
|
||||
|
||||
indio_dev->name = "spmi-adc5-gen3";
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &adc5_gen3_info;
|
||||
indio_dev->channels = adc->iio_chans;
|
||||
indio_dev->num_channels = adc->nchannels;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static struct platform_driver adc5_gen3_driver = {
|
||||
.driver = {
|
||||
.name = "qcom-spmi-adc5-gen3",
|
||||
.of_match_table = adc5_match_table,
|
||||
},
|
||||
.probe = adc5_gen3_probe,
|
||||
};
|
||||
module_platform_driver(adc5_gen3_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Technologies Inc. PMIC5 Gen3 ADC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS("QCOM_SPMI_ADC5_GEN3");
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
/*
|
||||
* The high limit, low limit and last measurement result are each stored in
|
||||
* 2 consequtive registers. 4 bits are in the high bits of the first register
|
||||
* 2 consecutive registers. 4 bits are in the high bits of the first register
|
||||
* and 8 bits in the next register.
|
||||
*
|
||||
* These macros return the address of the first reg for the given channel.
|
||||
@@ -962,7 +962,7 @@ static int bd79124_hw_init(struct bd79124_data *data)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable writing the measured values to the regsters */
|
||||
/* Enable writing the measured values to the registers */
|
||||
ret = regmap_set_bits(data->map, BD79124_REG_GEN_CFG,
|
||||
BD79124_MSK_STATS_EN);
|
||||
if (ret)
|
||||
|
||||
@@ -77,6 +77,7 @@ static const struct iio_backend_ops sd_backend_ops = {
|
||||
static const struct iio_backend_info sd_backend_info = {
|
||||
.name = "sd-modulator",
|
||||
.ops = &sd_backend_ops,
|
||||
.caps = IIO_BACKEND_CAP_ENABLE,
|
||||
};
|
||||
|
||||
static int iio_sd_mod_register(struct platform_device *pdev)
|
||||
|
||||
@@ -82,7 +82,7 @@ struct spear_adc_state {
|
||||
* of register writes, then a wait for a completion callback,
|
||||
* and finally a register read, during which userspace could issue
|
||||
* another read request. This lock protects a read access from
|
||||
* ocurring before another one has finished.
|
||||
* occurring before another one has finished.
|
||||
*/
|
||||
struct mutex lock;
|
||||
u32 current_clk;
|
||||
|
||||
@@ -227,7 +227,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
|
||||
if (priv->aclk) {
|
||||
/*
|
||||
* Asynchronous clock modes (e.g. ckmode == 0)
|
||||
* From spec: PLL output musn't exceed max rate
|
||||
* From spec: PLL output mustn't exceed max rate
|
||||
*/
|
||||
rate = clk_get_rate(priv->aclk);
|
||||
if (!rate) {
|
||||
|
||||
@@ -1662,7 +1662,7 @@ static irqreturn_t stm32_adc_threaded_isr(int irq, void *data)
|
||||
/*
|
||||
* Clear ovr bit to avoid subsequent calls to IRQ handler.
|
||||
* This requires to stop ADC first. OVR bit state in ISR,
|
||||
* is propaged to CSR register by hardware.
|
||||
* is propagated to CSR register by hardware.
|
||||
*/
|
||||
adc->cfg->stop_conv(indio_dev);
|
||||
stm32_adc_irq_clear(indio_dev, regs->isr_ovr.mask);
|
||||
|
||||
@@ -55,7 +55,7 @@ struct sun20i_gpadc_iio {
|
||||
* of register writes, then a wait for a completion callback,
|
||||
* and finally a register read, during which userspace could issue
|
||||
* another read request. This lock protects a read access from
|
||||
* ocurring before another one has finished.
|
||||
* occurring before another one has finished.
|
||||
*/
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
@@ -231,7 +231,6 @@ static const struct iio_event_spec ads1015_events[] = {
|
||||
}
|
||||
|
||||
struct ads1015_channel_data {
|
||||
bool enabled;
|
||||
unsigned int pga;
|
||||
unsigned int data_rate;
|
||||
};
|
||||
|
||||
@@ -740,8 +740,7 @@ static int ads1119_probe(struct i2c_client *client)
|
||||
NULL, IRQF_ONESHOT,
|
||||
"ads1119", indio_dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to allocate irq\n");
|
||||
return ret;
|
||||
|
||||
st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
|
||||
indio_dev->name,
|
||||
|
||||
@@ -47,8 +47,6 @@
|
||||
#define TI_ADS7950_MAX_CHAN 16
|
||||
#define TI_ADS7950_NUM_GPIOS 4
|
||||
|
||||
#define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16))
|
||||
|
||||
/* val = value, dec = left shift, bits = number of bits of the mask */
|
||||
#define TI_ADS7950_EXTRACT(val, dec, bits) \
|
||||
(((val) >> (dec)) & ((1 << (bits)) - 1))
|
||||
@@ -105,8 +103,7 @@ struct ti_ads7950_state {
|
||||
* DMA (thus cache coherency maintenance) may require the
|
||||
* transfer buffers to live in their own cache lines.
|
||||
*/
|
||||
u16 rx_buf[TI_ADS7950_MAX_CHAN + 2 + TI_ADS7950_TIMESTAMP_SIZE]
|
||||
__aligned(IIO_DMA_MINALIGN);
|
||||
u16 rx_buf[TI_ADS7950_MAX_CHAN + 2] __aligned(IIO_DMA_MINALIGN);
|
||||
u16 tx_buf[TI_ADS7950_MAX_CHAN + 2];
|
||||
u16 single_tx;
|
||||
u16 single_rx;
|
||||
@@ -118,21 +115,6 @@ struct ti_ads7950_chip_info {
|
||||
unsigned int num_channels;
|
||||
};
|
||||
|
||||
enum ti_ads7950_id {
|
||||
TI_ADS7950,
|
||||
TI_ADS7951,
|
||||
TI_ADS7952,
|
||||
TI_ADS7953,
|
||||
TI_ADS7954,
|
||||
TI_ADS7955,
|
||||
TI_ADS7956,
|
||||
TI_ADS7957,
|
||||
TI_ADS7958,
|
||||
TI_ADS7959,
|
||||
TI_ADS7960,
|
||||
TI_ADS7961,
|
||||
};
|
||||
|
||||
#define TI_ADS7950_V_CHAN(index, bits) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
@@ -225,55 +207,64 @@ static DECLARE_TI_ADS7950_8_CHANNELS(ti_ads7959, 8);
|
||||
static DECLARE_TI_ADS7950_12_CHANNELS(ti_ads7960, 8);
|
||||
static DECLARE_TI_ADS7950_16_CHANNELS(ti_ads7961, 8);
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7950_chip_info[] = {
|
||||
[TI_ADS7950] = {
|
||||
.channels = ti_ads7950_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7950_channels),
|
||||
},
|
||||
[TI_ADS7951] = {
|
||||
.channels = ti_ads7951_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7951_channels),
|
||||
},
|
||||
[TI_ADS7952] = {
|
||||
.channels = ti_ads7952_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7952_channels),
|
||||
},
|
||||
[TI_ADS7953] = {
|
||||
.channels = ti_ads7953_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7953_channels),
|
||||
},
|
||||
[TI_ADS7954] = {
|
||||
.channels = ti_ads7954_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7954_channels),
|
||||
},
|
||||
[TI_ADS7955] = {
|
||||
.channels = ti_ads7955_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7955_channels),
|
||||
},
|
||||
[TI_ADS7956] = {
|
||||
.channels = ti_ads7956_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7956_channels),
|
||||
},
|
||||
[TI_ADS7957] = {
|
||||
.channels = ti_ads7957_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7957_channels),
|
||||
},
|
||||
[TI_ADS7958] = {
|
||||
.channels = ti_ads7958_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7958_channels),
|
||||
},
|
||||
[TI_ADS7959] = {
|
||||
.channels = ti_ads7959_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7959_channels),
|
||||
},
|
||||
[TI_ADS7960] = {
|
||||
.channels = ti_ads7960_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7960_channels),
|
||||
},
|
||||
[TI_ADS7961] = {
|
||||
.channels = ti_ads7961_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7961_channels),
|
||||
},
|
||||
static const struct ti_ads7950_chip_info ti_ads7950_chip_info = {
|
||||
.channels = ti_ads7950_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7950_channels),
|
||||
};
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7951_chip_info = {
|
||||
.channels = ti_ads7951_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7951_channels),
|
||||
};
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7952_chip_info = {
|
||||
.channels = ti_ads7952_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7952_channels),
|
||||
};
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7953_chip_info = {
|
||||
.channels = ti_ads7953_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7953_channels),
|
||||
};
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7954_chip_info = {
|
||||
.channels = ti_ads7954_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7954_channels),
|
||||
};
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7955_chip_info = {
|
||||
.channels = ti_ads7955_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7955_channels),
|
||||
};
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7956_chip_info = {
|
||||
.channels = ti_ads7956_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7956_channels),
|
||||
};
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7957_chip_info = {
|
||||
.channels = ti_ads7957_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7957_channels),
|
||||
};
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7958_chip_info = {
|
||||
.channels = ti_ads7958_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7958_channels),
|
||||
};
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7959_chip_info = {
|
||||
.channels = ti_ads7959_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7959_channels),
|
||||
};
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7960_chip_info = {
|
||||
.channels = ti_ads7960_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7960_channels),
|
||||
};
|
||||
|
||||
static const struct ti_ads7950_chip_info ti_ads7961_chip_info = {
|
||||
.channels = ti_ads7961_channels,
|
||||
.num_channels = ARRAY_SIZE(ti_ads7961_channels),
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -313,8 +304,10 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &st->rx_buf[2],
|
||||
iio_get_time_ns(indio_dev));
|
||||
iio_push_to_buffers_with_ts_unaligned(indio_dev, &st->rx_buf[2],
|
||||
sizeof(*st->rx_buf) *
|
||||
TI_ADS7950_MAX_CHAN,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
out:
|
||||
mutex_unlock(&st->slock);
|
||||
@@ -561,7 +554,7 @@ static int ti_ads7950_probe(struct spi_device *spi)
|
||||
|
||||
st->spi = spi;
|
||||
|
||||
info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data];
|
||||
info = spi_get_device_match_data(spi);
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
@@ -683,35 +676,35 @@ static void ti_ads7950_remove(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id ti_ads7950_id[] = {
|
||||
{ "ads7950", TI_ADS7950 },
|
||||
{ "ads7951", TI_ADS7951 },
|
||||
{ "ads7952", TI_ADS7952 },
|
||||
{ "ads7953", TI_ADS7953 },
|
||||
{ "ads7954", TI_ADS7954 },
|
||||
{ "ads7955", TI_ADS7955 },
|
||||
{ "ads7956", TI_ADS7956 },
|
||||
{ "ads7957", TI_ADS7957 },
|
||||
{ "ads7958", TI_ADS7958 },
|
||||
{ "ads7959", TI_ADS7959 },
|
||||
{ "ads7960", TI_ADS7960 },
|
||||
{ "ads7961", TI_ADS7961 },
|
||||
{ "ads7950", (kernel_ulong_t)&ti_ads7950_chip_info },
|
||||
{ "ads7951", (kernel_ulong_t)&ti_ads7951_chip_info },
|
||||
{ "ads7952", (kernel_ulong_t)&ti_ads7952_chip_info },
|
||||
{ "ads7953", (kernel_ulong_t)&ti_ads7953_chip_info },
|
||||
{ "ads7954", (kernel_ulong_t)&ti_ads7954_chip_info },
|
||||
{ "ads7955", (kernel_ulong_t)&ti_ads7955_chip_info },
|
||||
{ "ads7956", (kernel_ulong_t)&ti_ads7956_chip_info },
|
||||
{ "ads7957", (kernel_ulong_t)&ti_ads7957_chip_info },
|
||||
{ "ads7958", (kernel_ulong_t)&ti_ads7958_chip_info },
|
||||
{ "ads7959", (kernel_ulong_t)&ti_ads7959_chip_info },
|
||||
{ "ads7960", (kernel_ulong_t)&ti_ads7960_chip_info },
|
||||
{ "ads7961", (kernel_ulong_t)&ti_ads7961_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ti_ads7950_id);
|
||||
|
||||
static const struct of_device_id ads7950_of_table[] = {
|
||||
{ .compatible = "ti,ads7950", .data = &ti_ads7950_chip_info[TI_ADS7950] },
|
||||
{ .compatible = "ti,ads7951", .data = &ti_ads7950_chip_info[TI_ADS7951] },
|
||||
{ .compatible = "ti,ads7952", .data = &ti_ads7950_chip_info[TI_ADS7952] },
|
||||
{ .compatible = "ti,ads7953", .data = &ti_ads7950_chip_info[TI_ADS7953] },
|
||||
{ .compatible = "ti,ads7954", .data = &ti_ads7950_chip_info[TI_ADS7954] },
|
||||
{ .compatible = "ti,ads7955", .data = &ti_ads7950_chip_info[TI_ADS7955] },
|
||||
{ .compatible = "ti,ads7956", .data = &ti_ads7950_chip_info[TI_ADS7956] },
|
||||
{ .compatible = "ti,ads7957", .data = &ti_ads7950_chip_info[TI_ADS7957] },
|
||||
{ .compatible = "ti,ads7958", .data = &ti_ads7950_chip_info[TI_ADS7958] },
|
||||
{ .compatible = "ti,ads7959", .data = &ti_ads7950_chip_info[TI_ADS7959] },
|
||||
{ .compatible = "ti,ads7960", .data = &ti_ads7950_chip_info[TI_ADS7960] },
|
||||
{ .compatible = "ti,ads7961", .data = &ti_ads7950_chip_info[TI_ADS7961] },
|
||||
{ .compatible = "ti,ads7950", .data = &ti_ads7950_chip_info },
|
||||
{ .compatible = "ti,ads7951", .data = &ti_ads7951_chip_info },
|
||||
{ .compatible = "ti,ads7952", .data = &ti_ads7952_chip_info },
|
||||
{ .compatible = "ti,ads7953", .data = &ti_ads7953_chip_info },
|
||||
{ .compatible = "ti,ads7954", .data = &ti_ads7954_chip_info },
|
||||
{ .compatible = "ti,ads7955", .data = &ti_ads7955_chip_info },
|
||||
{ .compatible = "ti,ads7956", .data = &ti_ads7956_chip_info },
|
||||
{ .compatible = "ti,ads7957", .data = &ti_ads7957_chip_info },
|
||||
{ .compatible = "ti,ads7958", .data = &ti_ads7958_chip_info },
|
||||
{ .compatible = "ti,ads7959", .data = &ti_ads7959_chip_info },
|
||||
{ .compatible = "ti,ads7960", .data = &ti_ads7960_chip_info },
|
||||
{ .compatible = "ti,ads7961", .data = &ti_ads7961_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ads7950_of_table);
|
||||
|
||||
@@ -113,10 +113,10 @@ static void tiadc_step_config(struct iio_dev *indio_dev)
|
||||
* There are 16 configurable steps and 8 analog input
|
||||
* lines available which are shared between Touchscreen and ADC.
|
||||
*
|
||||
* Steps forwards i.e. from 0 towards 16 are used by ADC
|
||||
* depending on number of input lines needed.
|
||||
* Steps forward, i.e. from 0 towards 16, are used by ADC
|
||||
* depending on the number of input lines needed.
|
||||
* Channel would represent which analog input
|
||||
* needs to be given to ADC to digitalize data.
|
||||
* needs to be given to ADC to digitize data.
|
||||
*/
|
||||
for (i = 0; i < adc_dev->channels; i++) {
|
||||
int chan;
|
||||
|
||||
@@ -252,7 +252,7 @@ static const struct s16_fract twl4030_divider_ratios[16] = {
|
||||
{5, 11}, /* CHANNEL 15 */
|
||||
};
|
||||
|
||||
/* Conversion table from -3 to 55 degrees Celcius */
|
||||
/* Conversion table from -3 to 55 degrees Celsius */
|
||||
static int twl4030_therm_tbl[] = {
|
||||
30800, 29500, 28300, 27100,
|
||||
26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700,
|
||||
|
||||
@@ -416,7 +416,7 @@ static u8 twl6032_channel_to_reg(int channel)
|
||||
{
|
||||
/*
|
||||
* for any prior chosen channel, when the conversion is ready
|
||||
* the result is avalable in GPCH0_LSB, GPCH0_MSB.
|
||||
* the result is available in GPCH0_LSB, GPCH0_MSB.
|
||||
*/
|
||||
|
||||
return TWL6032_GPADC_GPCH0_LSB;
|
||||
|
||||
@@ -839,12 +839,9 @@ static int _ad74413r_get_single_adc_result(struct ad74413r_state *st,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = wait_for_completion_timeout(&st->adc_data_completion,
|
||||
msecs_to_jiffies(1000));
|
||||
if (!ret) {
|
||||
ret = -ETIMEDOUT;
|
||||
return ret;
|
||||
}
|
||||
if (!wait_for_completion_timeout(&st->adc_data_completion,
|
||||
msecs_to_jiffies(1000)))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
ret = regmap_read(st->regmap, AD74413R_REG_ADC_RESULT_X(channel),
|
||||
&uval);
|
||||
|
||||
@@ -18,7 +18,15 @@ config AD8366
|
||||
AD8366 Dual-Digital Variable Gain Amplifier (VGA)
|
||||
ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
|
||||
ADL5240 Digitally controlled variable gain amplifier (VGA)
|
||||
ADRF5702: 0.125 dB LSB, 8-Bit, Silicon Digital Attenuator
|
||||
ADRF5703: 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
|
||||
ADRF5720: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator
|
||||
ADRF5730: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator
|
||||
ADRF5731: 2 dB LSB, 4-Bit, Silicon Digital Attenuator
|
||||
HMC271A: 1dB LSB 5-Bit Digital Attenuator SMT
|
||||
HMC792A 0.25 dB LSB GaAs MMIC 6-Bit Digital Attenuator
|
||||
HMC1018A: 1.0 dB LSB GaAs MMIC 5-BIT Digital Attenuator
|
||||
HMC1019A: 0.5 dB LSB GaAs MMIC 5-BIT Digital Attenuator
|
||||
HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
|
||||
@@ -5,46 +5,52 @@
|
||||
* AD8366 Dual-Digital Variable Gain Amplifier (VGA)
|
||||
* ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
|
||||
* ADL5240 Digitally controlled variable gain amplifier (VGA)
|
||||
* ADRF5702: 0.125 dB LSB, 8-Bit, Silicon Digital Attenuator, 50 MHz to 20 GHz
|
||||
* ADRF5703: 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator, 9 kHz to 20 GHz
|
||||
* ADRF5720: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator, 9 kHz to 40 GHz
|
||||
* ADRF5730: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator, 100 MHz to 40 GHz
|
||||
* ADRF5731: 2 dB LSB, 4-Bit, Silicon Digital Attenuator, 100 MHz to 40 GHz
|
||||
* HMC271A: 1dB LSB 5-Bit Digital Attenuator SMT, 0.7 - 3.7 GHz
|
||||
* HMC792A 0.25 dB LSB GaAs MMIC 6-Bit Digital Attenuator
|
||||
* HMC1018A: 1.0 dB LSB GaAs MMIC 5-BIT DIGITAL ATTENUATOR, 0.1 - 30 GHz
|
||||
* HMC1019A: 0.5 dB LSB GaAs MMIC 5-BIT DIGITAL ATTENUATOR, 0.1 - 30 GHz
|
||||
* HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
|
||||
*
|
||||
* Copyright 2012-2019 Analog Devices Inc.
|
||||
* Copyright 2012-2026 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitrev.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
enum ad8366_type {
|
||||
ID_AD8366,
|
||||
ID_ADA4961,
|
||||
ID_ADL5240,
|
||||
ID_HMC792,
|
||||
ID_HMC1119,
|
||||
};
|
||||
|
||||
struct ad8366_info {
|
||||
const char *name;
|
||||
int gain_min;
|
||||
int gain_max;
|
||||
int gain_step;
|
||||
size_t num_channels;
|
||||
size_t (*pack_code)(const unsigned char *code, size_t num_channels,
|
||||
unsigned char *data);
|
||||
};
|
||||
|
||||
struct ad8366_state {
|
||||
struct spi_device *spi;
|
||||
struct regulator *reg;
|
||||
struct mutex lock; /* protect sensor state */
|
||||
struct gpio_desc *reset_gpio;
|
||||
unsigned char ch[2];
|
||||
enum ad8366_type type;
|
||||
const struct ad8366_info *info;
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) may require the
|
||||
@@ -53,60 +59,148 @@ struct ad8366_state {
|
||||
unsigned char data[2] __aligned(IIO_DMA_MINALIGN);
|
||||
};
|
||||
|
||||
static const struct ad8366_info ad8366_infos[] = {
|
||||
[ID_AD8366] = {
|
||||
.gain_min = 4500,
|
||||
.gain_max = 20500,
|
||||
},
|
||||
[ID_ADA4961] = {
|
||||
.gain_min = -6000,
|
||||
.gain_max = 15000,
|
||||
},
|
||||
[ID_ADL5240] = {
|
||||
.gain_min = -11500,
|
||||
.gain_max = 20000,
|
||||
},
|
||||
[ID_HMC792] = {
|
||||
.gain_min = -15750,
|
||||
.gain_max = 0,
|
||||
},
|
||||
[ID_HMC1119] = {
|
||||
.gain_min = -31750,
|
||||
.gain_max = 0,
|
||||
},
|
||||
static size_t ad8366_pack_code(const unsigned char *code, size_t num_channels,
|
||||
unsigned char *data)
|
||||
{
|
||||
u8 ch_a = bitrev8(code[0]) >> 2;
|
||||
u8 ch_b = bitrev8(code[1]) >> 2;
|
||||
|
||||
put_unaligned_be16((ch_b << 6) | ch_a, &data[0]);
|
||||
return sizeof(__be16);
|
||||
}
|
||||
|
||||
static size_t adrf5731_pack_code(const unsigned char *code, size_t num_channels,
|
||||
unsigned char *data)
|
||||
{
|
||||
data[0] = code[0] << 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t hmc271_pack_code(const unsigned char *code, size_t num_channels,
|
||||
unsigned char *data)
|
||||
{
|
||||
data[0] = bitrev8(code[0]) >> 3;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct ad8366_info ad8366_chip_info = {
|
||||
.name = "ad8366",
|
||||
.gain_min = 4500,
|
||||
.gain_max = 20500,
|
||||
.gain_step = 253,
|
||||
.num_channels = 2,
|
||||
.pack_code = ad8366_pack_code,
|
||||
};
|
||||
|
||||
static int ad8366_write(struct iio_dev *indio_dev,
|
||||
unsigned char ch_a, unsigned char ch_b)
|
||||
static const struct ad8366_info ada4961_chip_info = {
|
||||
.name = "ada4961",
|
||||
.gain_min = -6000,
|
||||
.gain_max = 15000,
|
||||
.gain_step = -1000,
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
static const struct ad8366_info adl5240_chip_info = {
|
||||
.name = "adl5240",
|
||||
.gain_min = -11500,
|
||||
.gain_max = 20000,
|
||||
.gain_step = 500,
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
static const struct ad8366_info adrf5702_chip_info = {
|
||||
.name = "adrf5702",
|
||||
.gain_min = -31875,
|
||||
.gain_max = 0,
|
||||
.gain_step = -125,
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
static const struct ad8366_info adrf5703_chip_info = {
|
||||
.name = "adrf5703",
|
||||
.gain_min = -31750,
|
||||
.gain_max = 0,
|
||||
.gain_step = -250,
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
static const struct ad8366_info adrf5720_chip_info = {
|
||||
.name = "adrf5720",
|
||||
.gain_min = -31500,
|
||||
.gain_max = 0,
|
||||
.gain_step = -500,
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
static const struct ad8366_info adrf5730_chip_info = {
|
||||
.name = "adrf5730",
|
||||
.gain_min = -31500,
|
||||
.gain_max = 0,
|
||||
.gain_step = -500,
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
static const struct ad8366_info adrf5731_chip_info = {
|
||||
.name = "adrf5731",
|
||||
.gain_min = -30000,
|
||||
.gain_max = 0,
|
||||
.gain_step = -2000,
|
||||
.num_channels = 1,
|
||||
.pack_code = adrf5731_pack_code,
|
||||
};
|
||||
|
||||
static const struct ad8366_info hmc271_chip_info = {
|
||||
.name = "hmc271a",
|
||||
.gain_min = -31000,
|
||||
.gain_max = 0,
|
||||
.gain_step = 1000,
|
||||
.num_channels = 1,
|
||||
.pack_code = hmc271_pack_code,
|
||||
};
|
||||
|
||||
static const struct ad8366_info hmc792_chip_info = {
|
||||
.name = "hmc792a",
|
||||
.gain_min = -15750,
|
||||
.gain_max = 0,
|
||||
.gain_step = 250,
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
static const struct ad8366_info hmc1018_chip_info = {
|
||||
.name = "hmc1018a",
|
||||
.gain_min = -31000,
|
||||
.gain_max = 0,
|
||||
.gain_step = 1000,
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
static const struct ad8366_info hmc1019_chip_info = {
|
||||
.name = "hmc1019a",
|
||||
.gain_min = -15500,
|
||||
.gain_max = 0,
|
||||
.gain_step = 500,
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
static const struct ad8366_info hmc1119_chip_info = {
|
||||
.name = "hmc1119",
|
||||
.gain_min = -31750,
|
||||
.gain_max = 0,
|
||||
.gain_step = -250,
|
||||
.num_channels = 1,
|
||||
};
|
||||
|
||||
static int ad8366_write_code(struct ad8366_state *st)
|
||||
{
|
||||
struct ad8366_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
const struct ad8366_info *inf = st->info;
|
||||
size_t len = 1;
|
||||
|
||||
switch (st->type) {
|
||||
case ID_AD8366:
|
||||
ch_a = bitrev8(ch_a & 0x3F);
|
||||
ch_b = bitrev8(ch_b & 0x3F);
|
||||
if (inf->pack_code)
|
||||
len = inf->pack_code(st->ch, inf->num_channels, st->data);
|
||||
else
|
||||
st->data[0] = st->ch[0];
|
||||
|
||||
st->data[0] = ch_b >> 4;
|
||||
st->data[1] = (ch_b << 4) | (ch_a >> 2);
|
||||
break;
|
||||
case ID_ADA4961:
|
||||
st->data[0] = ch_a & 0x1F;
|
||||
break;
|
||||
case ID_ADL5240:
|
||||
st->data[0] = (ch_a & 0x3F);
|
||||
break;
|
||||
case ID_HMC792:
|
||||
case ID_HMC1119:
|
||||
st->data[0] = ch_a;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = spi_write(st->spi, st->data, indio_dev->num_channels);
|
||||
if (ret < 0)
|
||||
dev_err(&indio_dev->dev, "write failed (%d)", ret);
|
||||
|
||||
return ret;
|
||||
return spi_write(st->spi, st->data, len);
|
||||
}
|
||||
|
||||
static int ad8366_read_raw(struct iio_dev *indio_dev,
|
||||
@@ -116,6 +210,7 @@ static int ad8366_read_raw(struct iio_dev *indio_dev,
|
||||
long m)
|
||||
{
|
||||
struct ad8366_state *st = iio_priv(indio_dev);
|
||||
const struct ad8366_info *inf = st->info;
|
||||
int ret;
|
||||
int code, gain = 0;
|
||||
|
||||
@@ -123,25 +218,8 @@ static int ad8366_read_raw(struct iio_dev *indio_dev,
|
||||
switch (m) {
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
code = st->ch[chan->channel];
|
||||
|
||||
switch (st->type) {
|
||||
case ID_AD8366:
|
||||
gain = code * 253 + 4500;
|
||||
break;
|
||||
case ID_ADA4961:
|
||||
gain = 15000 - code * 1000;
|
||||
break;
|
||||
case ID_ADL5240:
|
||||
gain = 20000 - 31500 + code * 500;
|
||||
break;
|
||||
case ID_HMC792:
|
||||
gain = -1 * code * 500;
|
||||
break;
|
||||
case ID_HMC1119:
|
||||
gain = -1 * code * 250;
|
||||
break;
|
||||
}
|
||||
|
||||
gain = inf->gain_step > 0 ? inf->gain_min : inf->gain_max;
|
||||
gain += inf->gain_step * code;
|
||||
/* Values in dB */
|
||||
*val = gain / 1000;
|
||||
*val2 = (gain % 1000) * 1000;
|
||||
@@ -176,29 +254,14 @@ static int ad8366_write_raw(struct iio_dev *indio_dev,
|
||||
if (gain > inf->gain_max || gain < inf->gain_min)
|
||||
return -EINVAL;
|
||||
|
||||
switch (st->type) {
|
||||
case ID_AD8366:
|
||||
code = (gain - 4500) / 253;
|
||||
break;
|
||||
case ID_ADA4961:
|
||||
code = (15000 - gain) / 1000;
|
||||
break;
|
||||
case ID_ADL5240:
|
||||
code = ((gain - 500 - 20000) / 500) & 0x3F;
|
||||
break;
|
||||
case ID_HMC792:
|
||||
code = (abs(gain) / 500) & 0x3F;
|
||||
break;
|
||||
case ID_HMC1119:
|
||||
code = (abs(gain) / 250) & 0x7F;
|
||||
break;
|
||||
}
|
||||
gain -= inf->gain_step > 0 ? inf->gain_min : inf->gain_max;
|
||||
code = DIV_ROUND_CLOSEST(gain, inf->gain_step);
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
st->ch[chan->channel] = code;
|
||||
ret = ad8366_write(indio_dev, st->ch[0], st->ch[1]);
|
||||
ret = ad8366_write_code(st);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
@@ -239,107 +302,97 @@ static const struct iio_chan_spec ad8366_channels[] = {
|
||||
AD8366_CHAN(1),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ada4961_channels[] = {
|
||||
AD8366_CHAN(0),
|
||||
};
|
||||
|
||||
static int ad8366_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct reset_control *rstc;
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad8366_state *st;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
if (indio_dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
st->reg = devm_regulator_get(&spi->dev, "vcc");
|
||||
if (!IS_ERR(st->reg)) {
|
||||
ret = regulator_enable(st->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = devm_mutex_init(dev, &st->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_regulator_get_enable(dev, "vcc");
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to get regulator\n");
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
mutex_init(&st->lock);
|
||||
st->spi = spi;
|
||||
st->type = spi_get_device_id(spi)->driver_data;
|
||||
st->info = spi_get_device_match_data(spi);
|
||||
|
||||
switch (st->type) {
|
||||
case ID_AD8366:
|
||||
indio_dev->channels = ad8366_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
|
||||
break;
|
||||
case ID_ADA4961:
|
||||
case ID_ADL5240:
|
||||
case ID_HMC792:
|
||||
case ID_HMC1119:
|
||||
st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(st->reset_gpio)) {
|
||||
ret = PTR_ERR(st->reset_gpio);
|
||||
goto error_disable_reg;
|
||||
}
|
||||
indio_dev->channels = ada4961_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ada4961_channels);
|
||||
break;
|
||||
default:
|
||||
dev_err(&spi->dev, "Invalid device ID\n");
|
||||
ret = -EINVAL;
|
||||
goto error_disable_reg;
|
||||
}
|
||||
enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(enable_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(enable_gpio),
|
||||
"Failed to get enable GPIO\n");
|
||||
|
||||
st->info = &ad8366_infos[st->type];
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
rstc = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL);
|
||||
if (IS_ERR(rstc))
|
||||
return dev_err_probe(dev, PTR_ERR(rstc),
|
||||
"Failed to get reset controller\n");
|
||||
|
||||
indio_dev->name = st->info->name;
|
||||
indio_dev->info = &ad8366_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = ad8366_channels;
|
||||
indio_dev->num_channels = st->info->num_channels;
|
||||
|
||||
ret = ad8366_write(indio_dev, 0, 0);
|
||||
ret = ad8366_write_code(st);
|
||||
if (ret < 0)
|
||||
goto error_disable_reg;
|
||||
return dev_err_probe(dev, ret, "failed to write initial gain\n");
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto error_disable_reg;
|
||||
|
||||
return 0;
|
||||
|
||||
error_disable_reg:
|
||||
if (!IS_ERR(st->reg))
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ad8366_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ad8366_state *st = iio_priv(indio_dev);
|
||||
struct regulator *reg = st->reg;
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
if (!IS_ERR(reg))
|
||||
regulator_disable(reg);
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad8366_id[] = {
|
||||
{"ad8366", ID_AD8366},
|
||||
{"ada4961", ID_ADA4961},
|
||||
{"adl5240", ID_ADL5240},
|
||||
{"hmc792a", ID_HMC792},
|
||||
{"hmc1119", ID_HMC1119},
|
||||
{ "ad8366", (kernel_ulong_t)&ad8366_chip_info },
|
||||
{ "ada4961", (kernel_ulong_t)&ada4961_chip_info },
|
||||
{ "adl5240", (kernel_ulong_t)&adl5240_chip_info },
|
||||
{ "adrf5702", (kernel_ulong_t)&adrf5702_chip_info },
|
||||
{ "adrf5703", (kernel_ulong_t)&adrf5703_chip_info },
|
||||
{ "adrf5720", (kernel_ulong_t)&adrf5720_chip_info },
|
||||
{ "adrf5730", (kernel_ulong_t)&adrf5730_chip_info },
|
||||
{ "adrf5731", (kernel_ulong_t)&adrf5731_chip_info },
|
||||
{ "hmc271a", (kernel_ulong_t)&hmc271_chip_info },
|
||||
{ "hmc792a", (kernel_ulong_t)&hmc792_chip_info },
|
||||
{ "hmc1018a", (kernel_ulong_t)&hmc1018_chip_info },
|
||||
{ "hmc1019a", (kernel_ulong_t)&hmc1019_chip_info },
|
||||
{ "hmc1119", (kernel_ulong_t)&hmc1119_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad8366_id);
|
||||
|
||||
static const struct of_device_id ad8366_of_match[] = {
|
||||
{ .compatible = "adi,ad8366", .data = &ad8366_chip_info },
|
||||
{ .compatible = "adi,ada4961", .data = &ada4961_chip_info },
|
||||
{ .compatible = "adi,adl5240", .data = &adl5240_chip_info },
|
||||
{ .compatible = "adi,adrf5702", .data = &adrf5702_chip_info },
|
||||
{ .compatible = "adi,adrf5703", .data = &adrf5703_chip_info },
|
||||
{ .compatible = "adi,adrf5720", .data = &adrf5720_chip_info },
|
||||
{ .compatible = "adi,adrf5730", .data = &adrf5730_chip_info },
|
||||
{ .compatible = "adi,adrf5731", .data = &adrf5731_chip_info },
|
||||
{ .compatible = "adi,hmc271a", .data = &hmc271_chip_info },
|
||||
{ .compatible = "adi,hmc792a", .data = &hmc792_chip_info },
|
||||
{ .compatible = "adi,hmc1018a", .data = &hmc1018_chip_info },
|
||||
{ .compatible = "adi,hmc1019a", .data = &hmc1019_chip_info },
|
||||
{ .compatible = "adi,hmc1119", .data = &hmc1119_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad8366_of_match);
|
||||
|
||||
static struct spi_driver ad8366_driver = {
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = ad8366_of_match,
|
||||
},
|
||||
.probe = ad8366_probe,
|
||||
.remove = ad8366_remove,
|
||||
.id_table = ad8366_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ static int ada4250_set_offset_uv(struct iio_dev *indio_dev,
|
||||
|
||||
/*
|
||||
* Compute Range and Voltage per LSB for the Sensor Offset Calibration
|
||||
* Example of computation for Range 1 and Range 2 (Curren Bias Set = AVDD):
|
||||
* Example of computation for Range 1 and Range 2 (Current Bias Set = AVDD):
|
||||
* Range 1 Range 2
|
||||
* Gain | Max Vos(mV) | LSB(mV) | Max Vos(mV) | LSB(mV) |
|
||||
* 2 | X1*127 | X1=0.126(AVDD-1) | X1*3*127 | X1*3 |
|
||||
|
||||
@@ -28,7 +28,6 @@ struct hw_consumer_buffer {
|
||||
struct list_head head;
|
||||
struct iio_dev *indio_dev;
|
||||
struct iio_buffer buffer;
|
||||
long scan_mask[];
|
||||
};
|
||||
|
||||
static struct hw_consumer_buffer *iio_buffer_to_hw_consumer_buffer(
|
||||
@@ -52,7 +51,6 @@ static const struct iio_buffer_access_funcs iio_hw_buf_access = {
|
||||
static struct hw_consumer_buffer *iio_hw_consumer_get_buffer(
|
||||
struct iio_hw_consumer *hwc, struct iio_dev *indio_dev)
|
||||
{
|
||||
unsigned int mask_longs = BITS_TO_LONGS(iio_get_masklength(indio_dev));
|
||||
struct hw_consumer_buffer *buf;
|
||||
|
||||
list_for_each_entry(buf, &hwc->buffers, head) {
|
||||
@@ -60,13 +58,18 @@ static struct hw_consumer_buffer *iio_hw_consumer_get_buffer(
|
||||
return buf;
|
||||
}
|
||||
|
||||
buf = kzalloc_flex(*buf, scan_mask, mask_longs);
|
||||
buf = kzalloc_obj(*buf);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
buf->buffer.access = &iio_hw_buf_access;
|
||||
buf->indio_dev = indio_dev;
|
||||
buf->buffer.scan_mask = buf->scan_mask;
|
||||
buf->buffer.scan_mask = bitmap_zalloc(iio_get_masklength(indio_dev),
|
||||
GFP_KERNEL);
|
||||
if (!buf->buffer.scan_mask) {
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iio_buffer_init(&buf->buffer);
|
||||
list_add_tail(&buf->head, &hwc->buffers);
|
||||
|
||||
@@ -224,35 +224,9 @@ void iio_kfifo_free(struct iio_buffer *r)
|
||||
}
|
||||
EXPORT_SYMBOL(iio_kfifo_free);
|
||||
|
||||
static void devm_iio_kfifo_release(struct device *dev, void *res)
|
||||
static void devm_iio_kfifo_release(void *buffer)
|
||||
{
|
||||
iio_kfifo_free(*(struct iio_buffer **)res);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_iio_kfifo_allocate - Resource-managed iio_kfifo_allocate()
|
||||
* @dev: Device to allocate kfifo buffer for
|
||||
*
|
||||
* RETURNS:
|
||||
* Pointer to allocated iio_buffer on success, NULL on failure.
|
||||
*/
|
||||
static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
|
||||
{
|
||||
struct iio_buffer **ptr, *r;
|
||||
|
||||
ptr = devres_alloc(devm_iio_kfifo_release, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
r = iio_kfifo_allocate();
|
||||
if (r) {
|
||||
*ptr = r;
|
||||
devres_add(dev, ptr);
|
||||
} else {
|
||||
devres_free(ptr);
|
||||
}
|
||||
|
||||
return r;
|
||||
iio_kfifo_free(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,10 +236,12 @@ static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
|
||||
* @setup_ops: The setup_ops required to configure the HW part of the buffer (optional)
|
||||
* @buffer_attrs: Extra sysfs buffer attributes for this IIO buffer
|
||||
*
|
||||
* This function allocates a kfifo buffer via devm_iio_kfifo_allocate() and
|
||||
* This function allocates a kfifo buffer via iio_kfifo_allocate() and
|
||||
* attaches it to the IIO device via iio_device_attach_buffer().
|
||||
* This is meant to be a bit of a short-hand/helper function as there are a few
|
||||
* drivers that seem to do this.
|
||||
*
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
int devm_iio_kfifo_buffer_setup_ext(struct device *dev,
|
||||
struct iio_dev *indio_dev,
|
||||
@@ -273,11 +249,16 @@ int devm_iio_kfifo_buffer_setup_ext(struct device *dev,
|
||||
const struct iio_dev_attr **buffer_attrs)
|
||||
{
|
||||
struct iio_buffer *buffer;
|
||||
int ret;
|
||||
|
||||
buffer = devm_iio_kfifo_allocate(dev);
|
||||
buffer = iio_kfifo_allocate();
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, devm_iio_kfifo_release, buffer);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
|
||||
indio_dev->setup_ops = setup_ops;
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,
|
||||
dir);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
/* reenable any irq's we disabled whilst changing mode */
|
||||
/* re-enable any IRQs we disabled whilst changing mode */
|
||||
enable_irq(chip->interrupts[0]);
|
||||
enable_irq(chip->interrupts[1]);
|
||||
}
|
||||
|
||||
@@ -606,7 +606,7 @@ static int ad7746_read_channel(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Offset applied internally becaue the _offset userspace interface is
|
||||
* Offset applied internally because the _offset userspace interface is
|
||||
* needed for the CAP DACs which apply a controllable offset.
|
||||
*/
|
||||
*val = get_unaligned_be24(data) - 0x800000;
|
||||
|
||||
@@ -807,7 +807,7 @@ static int bme680_read_gas(struct bme680_data *data, int *comp_gas_res)
|
||||
adc_gas_res = FIELD_GET(BME680_ADC_GAS_RES, gas_regs_val);
|
||||
|
||||
/*
|
||||
* occurs if either the gas heating duration was insuffient
|
||||
* This may occur if either the gas heating duration was insufficient
|
||||
* to reach the target heater temperature or the target
|
||||
* heater temperature was too high for the heater sink to
|
||||
* reach.
|
||||
|
||||
@@ -106,7 +106,7 @@ static int cros_ec_sensors_read(struct iio_dev *indio_dev,
|
||||
switch (st->core.type) {
|
||||
case MOTIONSENSE_TYPE_ACCEL:
|
||||
/*
|
||||
* EC returns data in g, iio exepects m/s^2.
|
||||
* EC returns data in g, IIO expects m/s^2.
|
||||
* Do not use IIO_G_TO_M_S_2 to avoid precision loss.
|
||||
*/
|
||||
*val = div_s64(val64 * 980665, 10);
|
||||
|
||||
@@ -346,7 +346,7 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st,
|
||||
EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_rel_value, "IIO_HID");
|
||||
|
||||
/*
|
||||
* This fuction applies the unit exponent to the scale.
|
||||
* This function applies the unit exponent to the scale.
|
||||
* For example:
|
||||
* 9.806650000 ->exp:2-> val0[980]val1[665000000]
|
||||
* 9.000806000 ->exp:2-> val0[900]val1[80600000]
|
||||
|
||||
@@ -154,7 +154,7 @@ void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts,
|
||||
valid = inv_update_chip_period(ts, period);
|
||||
}
|
||||
|
||||
/* no previous data, compute theoritical value from interrupt */
|
||||
/* no previous data, compute theoretical value from interrupt */
|
||||
if (ts->timestamp == 0) {
|
||||
/* elapsed time: sensor period * sensor samples number */
|
||||
interval = (int64_t)ts->period * (int64_t)sample_nb;
|
||||
@@ -185,7 +185,7 @@ void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts,
|
||||
|
||||
/*
|
||||
* After ODR change the time interval with the previous sample is
|
||||
* undertermined (depends when the change occures). So we compute the
|
||||
* undertermined (depends when the change occurs). So we compute the
|
||||
* timestamp from the current interrupt using the new FIFO period, the
|
||||
* total number of samples and the current sample numero.
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user