mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-06 06:43:13 -04:00
Merge tag 'iio-for-6.13a-take2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes: IIO: 1st set of new device support, features and cleanup for 6.13 Changes in take2: - Additional patch to drop the accidentally added empty file. - Tidy up of a duplicate include. Two merges of other trees. 6.12-rc2: To pull in the move of unaligned.h from include/asm to include/linux This was to resolve issues in linux-next. pwm/duty_offset-for6.13-rc1@ PWM infrastructure that is use di the AD7625 ADC driver. New device support ================== adi,ad7173 - Add support for the AD4113 8 channel ADC. adi,ad7606 - Add support for the AD7606C-16 and AD7606C-18 which have higher precision and support bipolar and differential channels. A lot of driver rework was needed to add the additional flexibility needed to support these parts. adi,ad7625 - New driver supporting AD7625, AD7626, AD7960 and AD7961 LVDS connected ADCs. Interface uses a combination of a PWM control and an IIO backend (currently a custom FPGA IP). adi,ad8460 - New driver for the ad8460 Waveform DAC. This high speed device is driven by a custom IP via a DMAEngine buffer. bosch,bmi270 - New driver for this 6-axis IMU. A later patch adds SPI support. gehc,pmc-adc - New driver for this GE Healthcare ADC 16-channel 16 bit ADC. invensense,mpu6050 - Add support for IAM-20680HT and IAM-20680HP variants of the IAM-20680 IMU that have better specifications in various ways including larger FIFO sizes. vishay,vl6030 - Support the veml7700, a stripped down veml6030 ambient light sensor. - Support the veml6035 ambient light sensor. Features ======== liteon,ltr390 - Allow configuration of sampling frequency - Support suspend and resume - Add interrupt support including threshold events + control over event reporting persistence. st,vl53l0x - Add support for continuous mode via IIO buffer support and a dataready trigger. ti,tmp0006 - Add triggered buffer support using data ready interrupt. vishay,vl6030 - Add regulator control support. vishay,vl6070 - Add regulator control support. vishay,vl6180 - Allow configuration of waiting between continuous samples. - Use the interrupt, if available, for single shot captures - Support continuous mode via the IIO triggered buffer interfaces. Cleanups and minor fixes ======================== tools/event monitor - Free dev_dir_name. treewide - Introduce aligned_s64 type for timestamps to replace s64 __aligned(8). Initial use in a few drivers - many others to follow. - Use dev_get_platform_data() instead of open-coding the access. - InvenSense email address and maintainer updates to reflect move to the tdk domain after acquisition. - Switch platform drivers from remove_new() back to remove() now all rework this was enabling is done. - More use of device_for_each_child_node_scoped() to remove need for manual caling of fwnode_handle_put() in early exits from the loop. - Use IIO_MAP() macro to replace some open-coded versions. - Constify struct iio_map arrays. - Use irq_get_trigger_type(irq) rather than irqd_get_trigger_type(irq_get_irq_data(irq); core - unsigned to unsigned int. adi,ad3552r - Fix to low a limit on max SPI clock speed. No rush to upstream this one as the binding that uses the higher speed will merge via this tree once ready. adi,ad5770r - Use get_unaligned_le16() instead of open-coding. Note this caused a merge issue in linux-next as unaligned.h has moved. adi,ad7606 - Use read_avail() callback to handle the various _available attributes. - Wrap up all data related to channel scaling into a single structure as the use of this gets more complex for the -16 and -18 parts. adi,adf4371 - Use chip_info structures and spi_get_device_match_data() - Drop spi_set_drvdata() as unused. - Reduce scope of struct clock as only touched in probe(). - Use dev_err_probe() where appropriate. adi,axi-dac - Improve register naming to make field and register association clearer. - Fix a wrong register bit. amlogic,meson8-saradc - Allow the meson8-saradc to have the amlogic,hhi-sysctrl property. bosch,bmp280 - Use u8 for the DMA buffer to avoid implication of other types given it can contain be24 data. - Use unsigned types to store raw values to make it clear they cannot be negative. - Drop unnecessary check for errors after IIR filter update. - Support soft reset to get device to know state on driver load. - Use bulk reads to retrieve the humidity calibration data. dynaimage,al3010 - Make sure to powerdown device in error paths. invensense,icm42600 - Add missing i2c_device-id tables. kionix,kmx61 - Drop ACPI IDs that are not associated with valid ACPI vendor IDs and for which there is no evidence they are in use in real devices. liteon,ltrf261a - Document a bad compatible that we are supporting because it is in the wild in the Valve Steam Deck via ACPI PRP0001. maxim,max1363 - Use get_unaligned_be16() instead of open-coding. Note this caused a merge issue in linux-next as unaligned.h has moved. mediatek,mt6360 - Use get_unaligned_be16() instead of open-coding. Note this caused a merge issue in linux-next as unaligned.h has moved. microchip,pac1921 - Drop various unnecessary type casts that were suggested by Wconversion compiler warnings which we do not use in IIO. Remove them because they hurt readability in cases where it is clear not overflow can occur. rohm,rpr0521 - Use iio_poll_func_store_time() rather than open-coding a similar solution. semtech,sx9324 - Make sx_common_get_raw_register() local to the only code that uses it. - Drop unnecessary acpi.h include. st,vl53l0x - Check the part ID register and print an info message if it is not what is expected. vishay,veml6030 - Fix DT binding file name to include vishay - Use regmap_set_bits() for case where all bits are set. - Use dev_err_probe() where appropriate. - Add missing delay after powering up in resume path. - Drop a processed accessor for the white channel as there is no public information to allow a specific scale to be established. - Use read_avail() to replace explicit custom _available attributes. vishay,veml6070 - Use guard() to allow early returns. - Add a devm callback to unregister the i2c device. - Use devm_iio_device_register() to simplify removal code. Various other minor improvements not called out explicitly. * tag 'iio-for-6.13a-take2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (161 commits) iio: imu: bmi270: Remove duplicated include in bmi270_i2c.c iio: adc: ad7606: Drop spurious empty file. iio: light: rpr0521: Use generic iio_pollfunc_store_time() iio: light: vl6180: Add support for Continuous Mode iio: light: vl6180: Added Interrupt support for single shot access iio: light: vl6180: Add configurable inter-measurement period support MAINTAINERS: add entry for VEML6030 ambient light sensor driver iio: light: veml6030: add support for veml7700 dt-bindings: iio: light: veml6030: add veml7700 iio: light: veml6035: fix read_avail in no_irq case for veml6035 iio: dac: adi-axi-dac: update register names iio: dac: adi-axi-dac: fix wrong register bitfield docs: iio: new docs for ad7625 driver iio: adc: ad7625: add driver dt-bindings: iio: adc: add AD762x/AD796x ADCs iio: Convert unsigned to unsigned int iio: pressure: bmp280: Fix uninitialized variable iio: Switch back to struct platform_driver::remove() iio: imu: bmi323: remove redundant register definition iio: frequency: adf4371: make use of dev_err_probe() ...
This commit is contained in:
@@ -37,6 +37,10 @@ properties:
|
||||
to both the positive and negative inputs of a differential ADC.
|
||||
The first value specifies the positive input pin, the second
|
||||
specifies the negative input pin.
|
||||
There are also some ADCs, where the differential channel has dedicated
|
||||
positive and negative inputs which can be used to measure differential
|
||||
voltage levels. For those setups, this property can be configured with
|
||||
the 'reg' property for both inputs (i.e. diff-channels = <reg reg>).
|
||||
|
||||
single-channel:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
@@ -28,6 +28,7 @@ description: |
|
||||
Datasheets for supported chips:
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/AD4111.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/AD4112.pdf
|
||||
<AD4113: not released yet>
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/AD4114.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/AD4115.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/AD4116.pdf
|
||||
@@ -44,6 +45,7 @@ properties:
|
||||
enum:
|
||||
- adi,ad4111
|
||||
- adi,ad4112
|
||||
- adi,ad4113
|
||||
- adi,ad4114
|
||||
- adi,ad4115
|
||||
- adi,ad4116
|
||||
@@ -331,6 +333,7 @@ allOf:
|
||||
enum:
|
||||
- adi,ad4111
|
||||
- adi,ad4112
|
||||
- adi,ad4113
|
||||
- adi,ad4114
|
||||
- adi,ad4115
|
||||
- adi,ad4116
|
||||
|
||||
@@ -14,6 +14,8 @@ description: |
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7605-4.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7606B.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606c-16.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606c-18.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf
|
||||
|
||||
properties:
|
||||
@@ -24,11 +26,19 @@ properties:
|
||||
- adi,ad7606-6
|
||||
- adi,ad7606-8 # Referred to as AD7606 (without -8) in the datasheet
|
||||
- adi,ad7606b
|
||||
- adi,ad7606c-16
|
||||
- adi,ad7606c-18
|
||||
- adi,ad7616
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
spi-cpha: true
|
||||
|
||||
spi-cpol: true
|
||||
@@ -114,6 +124,47 @@ properties:
|
||||
assumed that the pins are hardwired to VDD.
|
||||
type: boolean
|
||||
|
||||
patternProperties:
|
||||
"^channel@[1-8]$":
|
||||
type: object
|
||||
$ref: adc.yaml
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description:
|
||||
The channel number, as specified in the datasheet (from 1 to 8).
|
||||
minimum: 1
|
||||
maximum: 8
|
||||
|
||||
diff-channels:
|
||||
description:
|
||||
Each channel can be configured as a bipolar differential channel.
|
||||
The ADC uses the same positive and negative inputs for this.
|
||||
This property must be specified as 'reg' (or the channel number) for
|
||||
both positive and negative inputs (i.e. diff-channels = <reg reg>).
|
||||
Since the configuration is bipolar differential, the 'bipolar'
|
||||
property is required.
|
||||
items:
|
||||
minimum: 1
|
||||
maximum: 8
|
||||
|
||||
bipolar:
|
||||
description:
|
||||
The ADC channels can be configured as
|
||||
* Bipolar single-ended
|
||||
* Unipolar single-ended
|
||||
* Bipolar differential
|
||||
Therefore in the DT, if no channel node is specified, it is considered
|
||||
'unipolar single-ended'. So for the other configurations the 'bipolar'
|
||||
property must be specified. If 'diff-channels' is specified, it is
|
||||
considered a bipolar differential channel. Otherwise it is bipolar
|
||||
single-ended.
|
||||
|
||||
required:
|
||||
- reg
|
||||
- bipolar
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@@ -170,6 +221,25 @@ allOf:
|
||||
adi,conversion-start-gpios:
|
||||
maxItems: 1
|
||||
|
||||
- if:
|
||||
not:
|
||||
required:
|
||||
- adi,sw-mode
|
||||
then:
|
||||
patternProperties:
|
||||
"^channel@[1-8]$": false
|
||||
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad7606c-16
|
||||
- adi,ad7606c-18
|
||||
then:
|
||||
patternProperties:
|
||||
"^channel@[1-8]$": false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
@@ -202,4 +272,54 @@ examples:
|
||||
standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "adi,ad7606c-18";
|
||||
reg = <0>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
spi-max-frequency = <1000000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
|
||||
avcc-supply = <&adc_vref>;
|
||||
vdrive-supply = <&vdd_supply>;
|
||||
|
||||
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-parent = <&gpio>;
|
||||
|
||||
adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
|
||||
adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
|
||||
standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
|
||||
|
||||
adi,sw-mode;
|
||||
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
diff-channels = <1 1>;
|
||||
bipolar;
|
||||
};
|
||||
|
||||
channel@3 {
|
||||
reg = <3>;
|
||||
bipolar;
|
||||
};
|
||||
|
||||
channel@8 {
|
||||
reg = <8>;
|
||||
diff-channels = <8 8>;
|
||||
bipolar;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
...
|
||||
|
||||
176
Documentation/devicetree/bindings/iio/adc/adi,ad7625.yaml
Normal file
176
Documentation/devicetree/bindings/iio/adc/adi,ad7625.yaml
Normal file
@@ -0,0 +1,176 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/adi,ad7625.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices Fast PulSAR Analog to Digital Converters
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
- Nuno Sá <nuno.sa@analog.com>
|
||||
|
||||
description: |
|
||||
A family of single channel differential analog to digital converters.
|
||||
|
||||
* https://www.analog.com/en/products/ad7625.html
|
||||
* https://www.analog.com/en/products/ad7626.html
|
||||
* https://www.analog.com/en/products/ad7960.html
|
||||
* https://www.analog.com/en/products/ad7961.html
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad7625
|
||||
- adi,ad7626
|
||||
- adi,ad7960
|
||||
- adi,ad7961
|
||||
|
||||
vdd1-supply: true
|
||||
vdd2-supply: true
|
||||
vio-supply: true
|
||||
|
||||
ref-supply:
|
||||
description:
|
||||
Voltage regulator for the external reference voltage (REF).
|
||||
|
||||
refin-supply:
|
||||
description:
|
||||
Voltage regulator for the reference buffer input (REFIN).
|
||||
|
||||
clocks:
|
||||
description:
|
||||
The clock connected to the CLK pins, gated by the clk_gate PWM.
|
||||
maxItems: 1
|
||||
|
||||
pwms:
|
||||
items:
|
||||
- description: PWM connected to the CNV input on the ADC.
|
||||
- description: PWM that gates the clock connected to the ADC's CLK input.
|
||||
|
||||
pwm-names:
|
||||
items:
|
||||
- const: cnv
|
||||
- const: clk_gate
|
||||
|
||||
io-backends:
|
||||
description:
|
||||
The AXI ADC IP block connected to the D+/- and DCO+/- lines of the
|
||||
ADC. An example backend can be found at
|
||||
http://analogdevicesinc.github.io/hdl/projects/pulsar_lvds/index.html.
|
||||
maxItems: 1
|
||||
|
||||
adi,no-dco:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Indicates the wiring of the DCO+/- lines. If true, then they are
|
||||
grounded and the device is in self-clocked mode. If this is not
|
||||
present, then the device is in echoed clock mode.
|
||||
|
||||
adi,en0-always-on:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Indicates if EN0 is hard-wired to the high state. If neither this
|
||||
nor en0-gpios are present, then EN0 is hard-wired low.
|
||||
|
||||
adi,en1-always-on:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Indicates if EN1 is hard-wired to the high state. If neither this
|
||||
nor en1-gpios are present, then EN1 is hard-wired low.
|
||||
|
||||
adi,en2-always-on:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Indicates if EN2 is hard-wired to the high state. If neither this
|
||||
nor en2-gpios are present, then EN2 is hard-wired low.
|
||||
|
||||
adi,en3-always-on:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Indicates if EN3 is hard-wired to the high state. If neither this
|
||||
nor en3-gpios are present, then EN3 is hard-wired low.
|
||||
|
||||
en0-gpios:
|
||||
description:
|
||||
Configurable EN0 pin.
|
||||
|
||||
en1-gpios:
|
||||
description:
|
||||
Configurable EN1 pin.
|
||||
|
||||
en2-gpios:
|
||||
description:
|
||||
Configurable EN2 pin.
|
||||
|
||||
en3-gpios:
|
||||
description:
|
||||
Configurable EN3 pin.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- vdd1-supply
|
||||
- vdd2-supply
|
||||
- vio-supply
|
||||
- clocks
|
||||
- pwms
|
||||
- pwm-names
|
||||
- io-backends
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
required:
|
||||
- ref-supply
|
||||
then:
|
||||
properties:
|
||||
refin-supply: false
|
||||
- if:
|
||||
required:
|
||||
- refin-supply
|
||||
then:
|
||||
properties:
|
||||
ref-supply: false
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad7625
|
||||
- adi,ad7626
|
||||
then:
|
||||
properties:
|
||||
en2-gpios: false
|
||||
en3-gpios: false
|
||||
adi,en2-always-on: false
|
||||
adi,en3-always-on: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad7960
|
||||
- adi,ad7961
|
||||
then:
|
||||
# ad796x parts must have one of the two supplies
|
||||
oneOf:
|
||||
- required: [ref-supply]
|
||||
- required: [refin-supply]
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
adc {
|
||||
compatible = "adi,ad7625";
|
||||
vdd1-supply = <&supply_5V>;
|
||||
vdd2-supply = <&supply_2_5V>;
|
||||
vio-supply = <&supply_2_5V>;
|
||||
io-backends = <&axi_adc>;
|
||||
clocks = <&ref_clk>;
|
||||
pwms = <&axi_pwm_gen 0 0>, <&axi_pwm_gen 1 0>;
|
||||
pwm-names = "cnv", "clk_gate";
|
||||
en0-gpios = <&gpio0 86 GPIO_ACTIVE_HIGH>;
|
||||
en1-gpios = <&gpio0 87 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
@@ -98,6 +98,7 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- amlogic,meson8-saradc
|
||||
- amlogic,meson8b-saradc
|
||||
- amlogic,meson8m2-saradc
|
||||
then:
|
||||
|
||||
86
Documentation/devicetree/bindings/iio/adc/gehc,pmc-adc.yaml
Normal file
86
Documentation/devicetree/bindings/iio/adc/gehc,pmc-adc.yaml
Normal file
@@ -0,0 +1,86 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/gehc,pmc-adc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: GE HealthCare PMC Analog to Digital Converter (ADC)
|
||||
|
||||
maintainers:
|
||||
- Herve Codina <herve.codina@bootlin.com>
|
||||
|
||||
description:
|
||||
The GE HealthCare PMC ADC is a 16-Channel (voltage and current), 16-Bit ADC
|
||||
with an I2C Interface.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: gehc,pmc-adc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply:
|
||||
description:
|
||||
Regulator for the VDD power supply.
|
||||
|
||||
vdda-supply:
|
||||
description:
|
||||
Regulator for the VDD analog (VDDA) power supply.
|
||||
|
||||
vddio-supply:
|
||||
description:
|
||||
Regulator for the VDD IO (VDDIO) power supply.
|
||||
|
||||
vref-supply:
|
||||
description:
|
||||
Regulator for the voltage reference power supply.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
The component uses an external oscillator (osc) if an external oscillator
|
||||
is connected to its clock pins. Otherwise, it uses an internal reference
|
||||
clock.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: osc
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 2
|
||||
description: |
|
||||
The first cell is the channel type (dt-bindings/iio/adc/gehc,pmc-adc.h
|
||||
defines these values):
|
||||
- 0: voltage
|
||||
- 1: current
|
||||
The second cell is the channel number from 0 to 15.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
- vdda-supply
|
||||
- vddio-supply
|
||||
- vref-supply
|
||||
- '#io-channel-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@14 {
|
||||
compatible = "gehc,pmc-adc";
|
||||
reg = <0x14>;
|
||||
vdd-supply = <®_vdd>;
|
||||
vdda-supply = <®_vdda>;
|
||||
vddio-supply = <®_vddio>;
|
||||
vref-supply = <®_vref>;
|
||||
#io-channel-cells = <2>;
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -30,7 +30,7 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 30000000
|
||||
maximum: 66000000
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
164
Documentation/devicetree/bindings/iio/dac/adi,ad8460.yaml
Normal file
164
Documentation/devicetree/bindings/iio/dac/adi,ad8460.yaml
Normal file
@@ -0,0 +1,164 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2024 Analog Devices Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad8460.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD8460 DAC
|
||||
|
||||
maintainers:
|
||||
- Mariel Tinaco <mariel.tinaco@analog.com>
|
||||
|
||||
description: |
|
||||
Analog Devices AD8460 110 V High Voltage, 1 A High Current,
|
||||
Arbitrary Waveform Generator with Integrated 14-Bit High Speed DAC
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad8460.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad8460
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
maxItems: 1
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: tx
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 20000000
|
||||
|
||||
hvcc-supply:
|
||||
description: Positive high voltage power supply line
|
||||
|
||||
hvee-supply:
|
||||
description: Negative high voltage power supply line
|
||||
|
||||
vcc-5v-supply:
|
||||
description: Low voltage power supply
|
||||
|
||||
vref-5v-supply:
|
||||
description: Reference voltage for analog low voltage
|
||||
|
||||
dvdd-3p3v-supply:
|
||||
description: Digital supply bypass
|
||||
|
||||
avdd-3p3v-supply:
|
||||
description: Analog supply bypass
|
||||
|
||||
refio-1p2v-supply:
|
||||
description: Drive voltage in the range of 1.2V maximum to as low as
|
||||
low as 0.12V through the REF_IO pin to adjust full scale output span
|
||||
|
||||
adi,external-resistor-ohms:
|
||||
description: Specify value of external resistor connected to FS_ADJ pin
|
||||
to establish internal HVDAC's reference current I_REF
|
||||
minimum: 2000
|
||||
maximum: 20000
|
||||
default: 2000
|
||||
|
||||
adi,range-microvolt:
|
||||
description: Voltage output range specified as <minimum, maximum>
|
||||
items:
|
||||
- minimum: -55000000
|
||||
maximum: 0
|
||||
default: 0
|
||||
- minimum: 0
|
||||
maximum: 55000000
|
||||
default: 0
|
||||
|
||||
adi,range-microamp:
|
||||
description: Current output range specified as <minimum, maximum>
|
||||
items:
|
||||
- minimum: -1000000
|
||||
maximum: 0
|
||||
default: 0
|
||||
- minimum: 0
|
||||
maximum: 1000000
|
||||
default: 0
|
||||
|
||||
adi,max-millicelsius:
|
||||
description: Overtemperature threshold
|
||||
minimum: 0
|
||||
maximum: 150000
|
||||
default: 0
|
||||
|
||||
shutdown-reset-gpios:
|
||||
description: Corresponds to SDN_RESET pin. To exit shutdown
|
||||
or sleep mode, pulse SDN_RESET HIGH, then leave LOW.
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
description: Manual Power On Reset (POR). Pull this GPIO pin
|
||||
LOW and then HIGH to reset all digital registers to default
|
||||
maxItems: 1
|
||||
|
||||
shutdown-gpios:
|
||||
description: Corresponds to SDN_IO pin. Shutdown may be
|
||||
initiated by the user, by pulsing SDN_IO high. To exit shutdown,
|
||||
pulse SDN_IO low, then float.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- hvcc-supply
|
||||
- hvee-supply
|
||||
- vcc-5v-supply
|
||||
- vref-5v-supply
|
||||
- dvdd-3p3v-supply
|
||||
- avdd-3p3v-supply
|
||||
- refio-1p2v-supply
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
compatible = "adi,ad8460";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <8000000>;
|
||||
|
||||
dmas = <&tx_dma 0>;
|
||||
dma-names = "tx";
|
||||
|
||||
shutdown-reset-gpios = <&gpio 86 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio 91 GPIO_ACTIVE_LOW>;
|
||||
shutdown-gpios = <&gpio 88 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
clocks = <&sync_ext_clk>;
|
||||
|
||||
hvcc-supply = <&hvcc>;
|
||||
hvee-supply = <&hvee>;
|
||||
vcc-5v-supply = <&vcc_5>;
|
||||
vref-5v-supply = <&vref_5>;
|
||||
dvdd-3p3v-supply = <&dvdd_3_3>;
|
||||
avdd-3p3v-supply = <&avdd_3_3>;
|
||||
refio-1p2v-supply = <&refio_1_2>;
|
||||
|
||||
adi,external-resistor-ohms = <2000>;
|
||||
adi,range-microvolt = <(-40000000) 40000000>;
|
||||
adi,range-microamp = <0 50000>;
|
||||
adi,max-millicelsius = <50000>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
77
Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml
Normal file
77
Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml
Normal file
@@ -0,0 +1,77 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/imu/bosch,bmi270.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Bosch BMI270 6-Axis IMU
|
||||
|
||||
maintainers:
|
||||
- Alex Lanzano <lanzano.alex@gmail.com>
|
||||
|
||||
description: |
|
||||
BMI270 is a 6-axis inertial measurement unit that can measure acceleration and
|
||||
angular velocity. The sensor also supports configurable interrupt events such
|
||||
as motion, step counter, and wrist motion gestures. The sensor can communicate
|
||||
I2C or SPI.
|
||||
https://www.bosch-sensortec.com/products/motion-sensors/imus/bmi270/
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: bosch,bmi270
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
vddio-supply: true
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
interrupt-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
enum:
|
||||
- INT1
|
||||
- INT2
|
||||
|
||||
drive-open-drain:
|
||||
description:
|
||||
set if the specified interrupt pins should be configured as
|
||||
open drain. If not set, defaults to push-pull.
|
||||
|
||||
mount-matrix:
|
||||
description:
|
||||
an optional 3x3 mounting rotation matrix.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
- vddio-supply
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
imu@68 {
|
||||
compatible = "bosch,bmi270";
|
||||
reg = <0x68>;
|
||||
vdd-supply = <&vdd>;
|
||||
vddio-supply = <&vddio>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <16 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "INT1";
|
||||
};
|
||||
};
|
||||
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: InvenSense ICM-426xx Inertial Measurement Unit
|
||||
|
||||
maintainers:
|
||||
- Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
|
||||
- Jean-Baptiste Maneyrol <jean-baptiste.maneyrol@tdk.com>
|
||||
|
||||
description: |
|
||||
6-axis MotionTracking device that combines a 3-axis gyroscope and a 3-axis
|
||||
|
||||
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: InvenSense MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device
|
||||
|
||||
maintainers:
|
||||
- Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
|
||||
- Jean-Baptiste Maneyrol <jean-baptiste.maneyrol@tdk.com>
|
||||
|
||||
description: |
|
||||
These devices support both I2C and SPI bus interfaces.
|
||||
@@ -36,6 +36,11 @@ properties:
|
||||
- items:
|
||||
- const: invensense,icm20608d
|
||||
- const: invensense,icm20608
|
||||
- items:
|
||||
- enum:
|
||||
- invensense,iam20680hp
|
||||
- invensense,iam20680ht
|
||||
- const: invensense,iam20680
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/light/veml6030.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: VEML6030 Ambient Light Sensor (ALS)
|
||||
|
||||
maintainers:
|
||||
- Rishi Gupta <gupt21@gmail.com>
|
||||
|
||||
description: |
|
||||
Bindings for the ambient light sensor veml6030 from Vishay
|
||||
Semiconductors over an i2c interface.
|
||||
|
||||
Irrespective of whether interrupt is used or not, application
|
||||
can get the ALS and White channel reading from IIO raw interface.
|
||||
|
||||
If the interrupts are used, application will receive an IIO event
|
||||
whenever configured threshold is crossed.
|
||||
|
||||
Specifications about the sensor can be found at:
|
||||
https://www.vishay.com/docs/84366/veml6030.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- vishay,veml6030
|
||||
|
||||
reg:
|
||||
description:
|
||||
I2C address of the device.
|
||||
enum:
|
||||
- 0x10 # ADDR pin pulled down
|
||||
- 0x48 # ADDR pin pulled up
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
interrupt mapping for IRQ. Configure with IRQ_TYPE_LEVEL_LOW.
|
||||
Refer to interrupt-controller/interrupts.txt for generic
|
||||
interrupt client node bindings.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
light-sensor@10 {
|
||||
compatible = "vishay,veml6030";
|
||||
reg = <0x10>;
|
||||
interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
||||
};
|
||||
...
|
||||
104
Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml
Normal file
104
Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml
Normal file
@@ -0,0 +1,104 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/light/vishay,veml6030.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: VEML6030, VEML6035 and VEML7700 Ambient Light Sensors (ALS)
|
||||
|
||||
maintainers:
|
||||
- Rishi Gupta <gupt21@gmail.com>
|
||||
|
||||
description: |
|
||||
Bindings for the ambient light sensors veml6030 and veml6035 from
|
||||
Vishay Semiconductors over an i2c interface.
|
||||
|
||||
Irrespective of whether interrupt is used or not, application
|
||||
can get the ALS and White channel reading from IIO raw interface.
|
||||
|
||||
If the interrupts are used, application will receive an IIO event
|
||||
whenever configured threshold is crossed.
|
||||
|
||||
Specifications about the sensors can be found at:
|
||||
https://www.vishay.com/docs/84366/veml6030.pdf
|
||||
https://www.vishay.com/docs/84889/veml6035.pdf
|
||||
https://www.vishay.com/docs/84286/veml7700.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- vishay,veml6030
|
||||
- vishay,veml6035
|
||||
- vishay,veml7700
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
interrupt mapping for IRQ. Configure with IRQ_TYPE_LEVEL_LOW.
|
||||
Refer to interrupt-controller/interrupts.txt for generic
|
||||
interrupt client node bindings.
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- vishay,veml6030
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
enum:
|
||||
- 0x10 # ADDR pin pulled down
|
||||
- 0x48 # ADDR pin pulled up
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- vishay,veml6035
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
enum:
|
||||
- 0x29
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- vishay,veml7700
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
enum:
|
||||
- 0x10
|
||||
interrupts: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
light-sensor@10 {
|
||||
compatible = "vishay,veml6030";
|
||||
reg = <0x10>;
|
||||
interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
|
||||
vdd-supply = <&vdd>;
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -4,7 +4,7 @@
|
||||
$id: http://devicetree.org/schemas/iio/light/vishay,veml6075.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Vishay VEML6075 UVA/B and VEML6040 RGBW sensors
|
||||
title: Vishay VEML6070 UVA, VEML6075 UVA/B and VEML6040 RGBW sensors
|
||||
|
||||
maintainers:
|
||||
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
|
||||
@@ -16,6 +16,7 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- vishay,veml6040
|
||||
- vishay,veml6070
|
||||
- vishay,veml6075
|
||||
|
||||
reg:
|
||||
|
||||
@@ -23,6 +23,9 @@ properties:
|
||||
vdd-supply:
|
||||
description: provide VDD power to the sensor.
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@@ -31,6 +34,7 @@ additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
@@ -38,5 +42,7 @@ examples:
|
||||
compatible = "ti,tmp006";
|
||||
reg = <0x40>;
|
||||
vdd-supply = <&ldo4_reg>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -561,6 +561,8 @@ patternProperties:
|
||||
description: GE Fanuc Intelligent Platforms Embedded Systems, Inc.
|
||||
"^GEFanuc,.*":
|
||||
description: GE Fanuc Intelligent Platforms Embedded Systems, Inc.
|
||||
"^gehc,.*":
|
||||
description: GE HealthCare
|
||||
"^gemei,.*":
|
||||
description: Gemei Digital Technology Co., Ltd.
|
||||
"^gemtek,.*":
|
||||
|
||||
91
Documentation/iio/ad7625.rst
Normal file
91
Documentation/iio/ad7625.rst
Normal file
@@ -0,0 +1,91 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
====================
|
||||
AD7625 driver
|
||||
====================
|
||||
|
||||
ADC driver for Analog Devices Inc. AD7625, AD7626, AD7960, and AD7961
|
||||
devices. The module name is ``ad7625``.
|
||||
|
||||
Supported devices
|
||||
=================
|
||||
|
||||
The following chips are supported by this driver:
|
||||
|
||||
* `AD7625 <https://www.analog.com/AD7625>`_
|
||||
* `AD7626 <https://www.analog.com/AD7626>`_
|
||||
* `AD7960 <https://www.analog.com/AD7960>`_
|
||||
* `AD7961 <https://www.analog.com/AD7961>`_
|
||||
|
||||
The driver requires use of the Pulsar LVDS HDL project:
|
||||
|
||||
* `Pulsar LVDS HDL <http://analogdevicesinc.github.io/hdl/projects/pulsar_lvds/index.html>`_
|
||||
|
||||
To trigger conversions and enable subsequent data transfer, the devices
|
||||
require coupled PWM signals with a phase offset.
|
||||
|
||||
Supported features
|
||||
==================
|
||||
|
||||
Conversion control modes
|
||||
------------------------
|
||||
|
||||
The driver currently supports one of two possible LVDS conversion control methods.
|
||||
|
||||
Echoed-Clock interface mode
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block::
|
||||
|
||||
+----------------+
|
||||
+xxxxxxxxxxxxxxxxxxxxxxxxxx| CNV |
|
||||
X | |
|
||||
v | HOST |
|
||||
+----------------------------+ | |
|
||||
| CNV+/CNV- DCO+/DCO- |xxxxxxx>| CLK_IN |
|
||||
| | | |
|
||||
| | | |
|
||||
| AD7625 D+/D- |xxxxxxx>| DATA_IN |
|
||||
| | | |
|
||||
| | | |
|
||||
| CLK+/CLK- |<xxxxxxx| CLK & CLK_GATE |
|
||||
+----------------------------+ | |
|
||||
+----------------+
|
||||
|
||||
Reference voltage
|
||||
-----------------
|
||||
|
||||
Three possible reference voltage sources are supported:
|
||||
|
||||
- Internal reference (only available on AD7625 and AD7626)
|
||||
- External reference and internal buffer
|
||||
- External reference
|
||||
|
||||
The source is determined by the device tree. If ``ref-supply`` is present, then
|
||||
the external reference is used. If ``refin-supply`` is present, then the internal
|
||||
buffer is used. If neither is present, then the internal reference is used.
|
||||
|
||||
Unimplemented features
|
||||
----------------------
|
||||
|
||||
- Self-clocked mode
|
||||
|
||||
|
||||
Device attributes
|
||||
=================
|
||||
|
||||
The AD762x is a fully-differential ADC and has the following attributes:
|
||||
|
||||
+---------------------------------------+--------------------------------------------------------------+
|
||||
| Attribute | Description |
|
||||
+=======================================+==============================================================+
|
||||
| ``scale`` | Scale factor to convert raw value from buffered reads to mV. |
|
||||
+---------------------------------------+--------------------------------------------------------------+
|
||||
|
||||
|
||||
Device buffers
|
||||
==============
|
||||
|
||||
This driver supports IIO triggered buffers.
|
||||
|
||||
See :doc:`iio_devbuf` for more information.
|
||||
@@ -22,7 +22,7 @@ This driver supports also IIO buffers.
|
||||
|
||||
The IMU continuously performs an autocalibration procedure if (and only if)
|
||||
operating in fusion mode. The magnetometer autocalibration can however be
|
||||
disabled writing 0 in the sysfs in_magn_calibration_fast_enable attribute.
|
||||
disabled by writing 0 in the sysfs in_magn_calibration_fast_enable attribute.
|
||||
|
||||
The driver provides access to autocalibration flags (i.e. you can known if
|
||||
the IMU has successfully autocalibrated) and to the calibration data blob.
|
||||
|
||||
@@ -21,6 +21,7 @@ Industrial I/O Kernel Drivers
|
||||
ad4000
|
||||
ad4695
|
||||
ad7380
|
||||
ad7625
|
||||
ad7944
|
||||
adis16475
|
||||
adis16480
|
||||
|
||||
50
MAINTAINERS
50
MAINTAINERS
@@ -1327,6 +1327,17 @@ F: Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml
|
||||
F: drivers/iio/addac/ad74413r.c
|
||||
F: include/dt-bindings/iio/addac/adi,ad74413r.h
|
||||
|
||||
ANALOG DEVICES INC AD7625 DRIVER
|
||||
M: Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
R: Trevor Gamblin <tgamblin@baylibre.com>
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
W: http://analogdevicesinc.github.io/hdl/projects/pulsar_lvds/index.html
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad7625.yaml
|
||||
F: Documentation/iio/ad7625.rst
|
||||
F: drivers/iio/adc/ad7625.c
|
||||
|
||||
ANALOG DEVICES INC AD7768-1 DRIVER
|
||||
M: Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
@@ -1354,6 +1365,14 @@ F: Documentation/ABI/testing/debugfs-iio-ad9467
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml
|
||||
F: drivers/iio/adc/ad9467.c
|
||||
|
||||
ANALOG DEVICES INC AD8460 DRIVER
|
||||
M: Mariel Tinaco <Mariel.Tinaco@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/dac/adi,ad8460.yaml
|
||||
F: drivers/iio/dac/ad8460.c
|
||||
|
||||
ANALOG DEVICES INC AD9739a DRIVER
|
||||
M: Nuno Sa <nuno.sa@analog.com>
|
||||
M: Dragos Bogdan <dragos.bogdan@analog.com>
|
||||
@@ -4035,6 +4054,13 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
|
||||
F: drivers/iio/accel/bma400*
|
||||
|
||||
BOSCH SENSORTEC BMI270 IMU IIO DRIVER
|
||||
M: Alex Lanzano <lanzano.alex@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml
|
||||
F: drivers/iio/imu/bmi270/
|
||||
|
||||
BOSCH SENSORTEC BMI323 IMU IIO DRIVER
|
||||
M: Jagath Jog J <jagathjog1996@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
@@ -9457,6 +9483,14 @@ M: Kieran Bingham <kbingham@kernel.org>
|
||||
S: Supported
|
||||
F: scripts/gdb/
|
||||
|
||||
GE HEALTHCARE PMC ADC DRIVER
|
||||
M: Herve Codina <herve.codina@bootlin.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/adc/gehc,pmc-adc.yaml
|
||||
F: drivers/iio/adc/gehc-pmc-adc.c
|
||||
F: include/dt-bindings/iio/adc/gehc,pmc-adc.h
|
||||
|
||||
GEMINI CRYPTO DRIVER
|
||||
M: Corentin Labbe <clabbe@baylibre.com>
|
||||
L: linux-crypto@vger.kernel.org
|
||||
@@ -11886,7 +11920,7 @@ F: Documentation/devicetree/bindings/media/i2c/isil,isl79987.yaml
|
||||
F: drivers/media/i2c/isl7998x.c
|
||||
|
||||
INVENSENSE ICM-426xx IMU DRIVER
|
||||
M: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
|
||||
M: Jean-Baptiste Maneyrol <jean-baptiste.maneyrol@tdk.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://invensense.tdk.com/
|
||||
@@ -11901,6 +11935,14 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/gyroscope/invensense,mpu3050.yaml
|
||||
F: drivers/iio/gyro/mpu3050*
|
||||
|
||||
INVENSENSE MPU-6050 IMU DRIVER
|
||||
M: Jean-Baptiste Maneyrol <jean-baptiste.maneyrol@tdk.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://invensense.tdk.com/
|
||||
F: Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml
|
||||
F: drivers/iio/imu/inv_mpu6050/
|
||||
|
||||
IOC3 ETHERNET DRIVER
|
||||
M: Ralf Baechle <ralf@linux-mips.org>
|
||||
L: linux-mips@vger.kernel.org
|
||||
@@ -24693,6 +24735,12 @@ S: Maintained
|
||||
F: drivers/input/serio/userio.c
|
||||
F: include/uapi/linux/userio.h
|
||||
|
||||
VISHAY VEML6030 AMBIENT LIGHT SENSOR DRIVER
|
||||
M: Javier Carrasco <javier.carrasco.cruz@gmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml
|
||||
F: drivers/iio/light/veml6030.c
|
||||
|
||||
VISHAY VEML6075 UVA AND UVB LIGHT SENSOR DRIVER
|
||||
M: Javier Carrasco <javier.carrasco.cruz@gmail.com>
|
||||
S: Maintained
|
||||
|
||||
@@ -1719,7 +1719,6 @@ static int adxl380_config_irq(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct adxl380_state *st = iio_priv(indio_dev);
|
||||
unsigned long irq_flag;
|
||||
struct irq_data *desc;
|
||||
u32 irq_type;
|
||||
u8 polarity;
|
||||
int ret;
|
||||
@@ -1737,11 +1736,7 @@ static int adxl380_config_irq(struct iio_dev *indio_dev)
|
||||
st->int_map[1] = ADXL380_INT1_MAP1_REG;
|
||||
}
|
||||
|
||||
desc = irq_get_irq_data(st->irq);
|
||||
if (!desc)
|
||||
return dev_err_probe(st->dev, -EINVAL, "Could not find IRQ %d\n", st->irq);
|
||||
|
||||
irq_type = irqd_get_trigger_type(desc);
|
||||
irq_type = irq_get_trigger_type(st->irq);
|
||||
if (irq_type == IRQ_TYPE_LEVEL_HIGH) {
|
||||
polarity = 0;
|
||||
irq_flag = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
|
||||
|
||||
@@ -1103,8 +1103,7 @@ static int fxls8962af_irq_setup(struct iio_dev *indio_dev, int irq)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
irq_type = irqd_get_trigger_type(irq_get_irq_data(irq));
|
||||
|
||||
irq_type = irq_get_trigger_type(irq);
|
||||
switch (irq_type) {
|
||||
case IRQF_TRIGGER_HIGH:
|
||||
case IRQF_TRIGGER_RISING:
|
||||
|
||||
@@ -28,7 +28,7 @@ struct accel_3d_state {
|
||||
/* Ensure timestamp is naturally aligned */
|
||||
struct {
|
||||
u32 accel_val[3];
|
||||
s64 timestamp __aligned(8);
|
||||
aligned_s64 timestamp;
|
||||
} scan;
|
||||
int scale_pre_decml;
|
||||
int scale_post_decml;
|
||||
@@ -328,6 +328,7 @@ static int accel_3d_parse_report(struct platform_device *pdev,
|
||||
/* Function to initialize the processing for usage id */
|
||||
static int hid_accel_3d_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
|
||||
int ret = 0;
|
||||
const char *name;
|
||||
struct iio_dev *indio_dev;
|
||||
@@ -335,8 +336,6 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
|
||||
const struct iio_chan_spec *channel_spec;
|
||||
int channel_size;
|
||||
|
||||
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev,
|
||||
sizeof(struct accel_3d_state));
|
||||
if (indio_dev == NULL)
|
||||
@@ -424,7 +423,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
|
||||
/* Function to deinitialize the processing for usage id */
|
||||
static void hid_accel_3d_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
|
||||
struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct accel_3d_state *accel_state = iio_priv(indio_dev);
|
||||
|
||||
@@ -452,7 +451,7 @@ static struct platform_driver hid_accel_3d_platform_driver = {
|
||||
.pm = &hid_sensor_pm_ops,
|
||||
},
|
||||
.probe = hid_accel_3d_probe,
|
||||
.remove_new = hid_accel_3d_remove,
|
||||
.remove = hid_accel_3d_remove,
|
||||
};
|
||||
module_platform_driver(hid_accel_3d_platform_driver);
|
||||
|
||||
|
||||
@@ -229,7 +229,7 @@ config AD7606_IFACE_PARALLEL
|
||||
ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7606_parallel.
|
||||
module will be called ad7606_par.
|
||||
|
||||
config AD7606_IFACE_SPI
|
||||
tristate "Analog Devices AD7606 ADC driver with spi interface support"
|
||||
@@ -242,6 +242,22 @@ config AD7606_IFACE_SPI
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7606_spi.
|
||||
|
||||
config AD7625
|
||||
tristate "Analog Devices AD7625/AD7626 High Speed ADC driver"
|
||||
depends on PWM
|
||||
select IIO_BACKEND
|
||||
help
|
||||
Say yes here to build support for Analog Devices:
|
||||
* AD7625 16-Bit, 6 MSPS PulSAR Analog-to-Digital Converter
|
||||
* AD7626 16-Bit, 10 MSPS PulSAR Analog-to-Digital Converter
|
||||
* AD7960 18-Bit, 5 MSPS PulSAR Analog-to-Digital Converter
|
||||
* AD7961 16-Bit, 5 MSPS PulSAR Analog-to-Digital Converter
|
||||
|
||||
The driver requires the assistance of the AXI ADC IP core to operate.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad7625.
|
||||
|
||||
config AD7766
|
||||
tristate "Analog Devices AD7766/AD7767 ADC driver"
|
||||
depends on SPI_MASTER
|
||||
@@ -571,6 +587,16 @@ config FSL_MX25_ADC
|
||||
Generic Conversion Queue driver used for general purpose ADC in the
|
||||
MX25. This driver supports single measurements using the MX25 ADC.
|
||||
|
||||
config GEHC_PMC_ADC
|
||||
tristate "GE HealthCare PMC ADC driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for the GE HealthCare PMC 16-bit
|
||||
16-Channel ADC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called gehc-pmc-adc.
|
||||
|
||||
config HI8435
|
||||
tristate "Holt Integrated Circuits HI-8435 threshold detector"
|
||||
select IIO_TRIGGERED_EVENT
|
||||
|
||||
@@ -25,6 +25,7 @@ obj-$(CONFIG_AD7476) += ad7476.o
|
||||
obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
|
||||
obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
|
||||
obj-$(CONFIG_AD7606) += ad7606.o
|
||||
obj-$(CONFIG_AD7625) += ad7625.o
|
||||
obj-$(CONFIG_AD7766) += ad7766.o
|
||||
obj-$(CONFIG_AD7768_1) += ad7768-1.o
|
||||
obj-$(CONFIG_AD7780) += ad7780.o
|
||||
@@ -52,6 +53,7 @@ obj-$(CONFIG_ENVELOPE_DETECTOR) += envelope-detector.o
|
||||
obj-$(CONFIG_EP93XX_ADC) += ep93xx_adc.o
|
||||
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
|
||||
obj-$(CONFIG_FSL_MX25_ADC) += fsl-imx25-gcq.o
|
||||
obj-$(CONFIG_GEHC_PMC_ADC) += gehc-pmc-adc.o
|
||||
obj-$(CONFIG_HI8435) += hi8435.o
|
||||
obj-$(CONFIG_HX711) += hx711.o
|
||||
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
|
||||
|
||||
@@ -1194,7 +1194,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops,
|
||||
|
||||
static struct platform_driver ab8500_gpadc_driver = {
|
||||
.probe = ab8500_gpadc_probe,
|
||||
.remove_new = ab8500_gpadc_remove,
|
||||
.remove = ab8500_gpadc_remove,
|
||||
.driver = {
|
||||
.name = "ab8500-gpadc",
|
||||
.pm = pm_ptr(&ab8500_gpadc_pm_ops),
|
||||
|
||||
@@ -65,7 +65,7 @@ struct ad7091r_state {
|
||||
struct regulator *vref;
|
||||
const struct ad7091r_chip_info *chip_info;
|
||||
enum ad7091r_mode mode;
|
||||
struct mutex lock; /*lock to prevent concurent reads */
|
||||
struct mutex lock; /*lock to prevent concurrent reads */
|
||||
__be16 tx_buf __aligned(IIO_DMA_MINALIGN);
|
||||
__be16 rx_buf;
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* AD717x and AD411x family SPI ADC driver
|
||||
*
|
||||
* Supported devices:
|
||||
* AD4111/AD4112/AD4114/AD4115/AD4116
|
||||
* AD4111/AD4112/AD4113/AD4114/AD4115/AD4116
|
||||
* AD7172-2/AD7172-4/AD7173-8/AD7175-2
|
||||
* AD7175-8/AD7176-2/AD7177-2
|
||||
*
|
||||
@@ -76,14 +76,15 @@
|
||||
(x) == AD7173_AIN_REF_NEG)
|
||||
|
||||
#define AD7172_2_ID 0x00d0
|
||||
#define AD7175_ID 0x0cd0
|
||||
#define AD7176_ID 0x0c90
|
||||
#define AD7175_ID 0x0cd0
|
||||
#define AD7175_2_ID 0x0cd0
|
||||
#define AD7172_4_ID 0x2050
|
||||
#define AD7173_ID 0x30d0
|
||||
#define AD4111_ID AD7173_ID
|
||||
#define AD4112_ID AD7173_ID
|
||||
#define AD4114_ID AD7173_ID
|
||||
#define AD4113_ID 0x31d0
|
||||
#define AD4116_ID 0x34d0
|
||||
#define AD4115_ID 0x38d0
|
||||
#define AD7175_8_ID 0x3cd0
|
||||
@@ -170,6 +171,7 @@ struct ad7173_device_info {
|
||||
bool has_temp;
|
||||
/* ((AVDD1 − AVSS)/5) */
|
||||
bool has_pow_supply_monitoring;
|
||||
bool data_reg_only_16bit;
|
||||
bool has_input_buf;
|
||||
bool has_int_ref;
|
||||
bool has_ref2;
|
||||
@@ -294,6 +296,24 @@ static const struct ad7173_device_info ad4112_device_info = {
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
|
||||
};
|
||||
|
||||
static const struct ad7173_device_info ad4113_device_info = {
|
||||
.name = "ad4113",
|
||||
.id = AD4113_ID,
|
||||
.num_voltage_in_div = 8,
|
||||
.num_channels = 16,
|
||||
.num_configs = 8,
|
||||
.num_voltage_in = 8,
|
||||
.num_gpios = 2,
|
||||
.data_reg_only_16bit = true,
|
||||
.higher_gpio_bits = true,
|
||||
.has_vincom_input = true,
|
||||
.has_input_buf = true,
|
||||
.has_int_ref = true,
|
||||
.clock = 2 * HZ_PER_MHZ,
|
||||
.sinc5_data_rates = ad7173_sinc5_data_rates,
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
|
||||
};
|
||||
|
||||
static const struct ad7173_device_info ad4114_device_info = {
|
||||
.name = "ad4114",
|
||||
.id = AD4114_ID,
|
||||
@@ -985,6 +1005,13 @@ static const struct iio_info ad7173_info = {
|
||||
.update_scan_mode = ad7173_update_scan_mode,
|
||||
};
|
||||
|
||||
static const struct iio_scan_type ad4113_scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_BE,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7173_channel_template = {
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
@@ -1226,6 +1253,8 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
|
||||
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
|
||||
chan_st_priv->cfg.ref_sel = AD7173_SETUP_REF_SEL_INT_REF;
|
||||
st->adc_mode |= AD7173_ADC_MODE_REF_EN;
|
||||
if (st->info->data_reg_only_16bit)
|
||||
chan_arr[chan_index].scan_type = ad4113_scan_type;
|
||||
|
||||
chan_index++;
|
||||
}
|
||||
@@ -1306,6 +1335,9 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
|
||||
chan_st_priv->ain = AD7173_CH_ADDRESS(ain[0], ain[1]);
|
||||
}
|
||||
|
||||
if (st->info->data_reg_only_16bit)
|
||||
chan_arr[chan_index].scan_type = ad4113_scan_type;
|
||||
|
||||
chan_index++;
|
||||
}
|
||||
return 0;
|
||||
@@ -1434,6 +1466,7 @@ static int ad7173_probe(struct spi_device *spi)
|
||||
static const struct of_device_id ad7173_of_match[] = {
|
||||
{ .compatible = "adi,ad4111", .data = &ad4111_device_info },
|
||||
{ .compatible = "adi,ad4112", .data = &ad4112_device_info },
|
||||
{ .compatible = "adi,ad4113", .data = &ad4113_device_info },
|
||||
{ .compatible = "adi,ad4114", .data = &ad4114_device_info },
|
||||
{ .compatible = "adi,ad4115", .data = &ad4115_device_info },
|
||||
{ .compatible = "adi,ad4116", .data = &ad4116_device_info },
|
||||
@@ -1451,6 +1484,7 @@ MODULE_DEVICE_TABLE(of, ad7173_of_match);
|
||||
static const struct spi_device_id ad7173_id_table[] = {
|
||||
{ "ad4111", (kernel_ulong_t)&ad4111_device_info },
|
||||
{ "ad4112", (kernel_ulong_t)&ad4112_device_info },
|
||||
{ "ad4113", (kernel_ulong_t)&ad4113_device_info },
|
||||
{ "ad4114", (kernel_ulong_t)&ad4114_device_info },
|
||||
{ "ad4115", (kernel_ulong_t)&ad4115_device_info },
|
||||
{ "ad4116", (kernel_ulong_t)&ad4116_device_info },
|
||||
|
||||
@@ -383,7 +383,7 @@ static const char * const ad7266_gpio_labels[] = {
|
||||
|
||||
static int ad7266_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad7266_platform_data *pdata = spi->dev.platform_data;
|
||||
const struct ad7266_platform_data *pdata = dev_get_platdata(&spi->dev);
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad7266_state *st;
|
||||
unsigned int i;
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
@@ -32,12 +32,39 @@
|
||||
* Scales are computed as 5000/32768 and 10000/32768 respectively,
|
||||
* so that when applied to the raw values they provide mV values
|
||||
*/
|
||||
static const unsigned int ad7606_scale_avail[2] = {
|
||||
static const unsigned int ad7606_16bit_hw_scale_avail[2] = {
|
||||
152588, 305176
|
||||
};
|
||||
|
||||
static const unsigned int ad7606_18bit_hw_scale_avail[2] = {
|
||||
38147, 76294
|
||||
};
|
||||
|
||||
static const unsigned int ad7616_sw_scale_avail[3] = {
|
||||
static const unsigned int ad7606c_16bit_single_ended_unipolar_scale_avail[3] = {
|
||||
76294, 152588, 190735,
|
||||
};
|
||||
|
||||
static const unsigned int ad7606c_16bit_single_ended_bipolar_scale_avail[5] = {
|
||||
76294, 152588, 190735, 305176, 381470
|
||||
};
|
||||
|
||||
static const unsigned int ad7606c_16bit_differential_bipolar_scale_avail[4] = {
|
||||
152588, 305176, 381470, 610352
|
||||
};
|
||||
|
||||
static const unsigned int ad7606c_18bit_single_ended_unipolar_scale_avail[3] = {
|
||||
19073, 38147, 47684
|
||||
};
|
||||
|
||||
static const unsigned int ad7606c_18bit_single_ended_bipolar_scale_avail[5] = {
|
||||
19073, 38147, 47684, 76294, 95367
|
||||
};
|
||||
|
||||
static const unsigned int ad7606c_18bit_differential_bipolar_scale_avail[4] = {
|
||||
38147, 76294, 95367, 152588
|
||||
};
|
||||
|
||||
static const unsigned int ad7606_16bit_sw_scale_avail[3] = {
|
||||
76293, 152588, 305176
|
||||
};
|
||||
|
||||
@@ -62,6 +89,195 @@ int ad7606_reset(struct ad7606_state *st)
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ad7606_reset, IIO_AD7606);
|
||||
|
||||
static int ad7606_16bit_chan_scale_setup(struct ad7606_state *st,
|
||||
struct iio_chan_spec *chan, int ch)
|
||||
{
|
||||
struct ad7606_chan_scale *cs = &st->chan_scales[ch];
|
||||
|
||||
if (!st->sw_mode_en) {
|
||||
/* tied to logic low, analog input range is +/- 5V */
|
||||
cs->range = 0;
|
||||
cs->scale_avail = ad7606_16bit_hw_scale_avail;
|
||||
cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Scale of 0.076293 is only available in sw mode */
|
||||
/* After reset, in software mode, ±10 V is set by default */
|
||||
cs->range = 2;
|
||||
cs->scale_avail = ad7606_16bit_sw_scale_avail;
|
||||
cs->num_scales = ARRAY_SIZE(ad7606_16bit_sw_scale_avail);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7606_get_chan_config(struct ad7606_state *st, int ch,
|
||||
bool *bipolar, bool *differential)
|
||||
{
|
||||
unsigned int num_channels = st->chip_info->num_channels - 1;
|
||||
struct device *dev = st->dev;
|
||||
int ret;
|
||||
|
||||
*bipolar = false;
|
||||
*differential = false;
|
||||
|
||||
device_for_each_child_node_scoped(dev, child) {
|
||||
u32 pins[2];
|
||||
int reg;
|
||||
|
||||
ret = fwnode_property_read_u32(child, "reg", ®);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
/* channel number (here) is from 1 to num_channels */
|
||||
if (reg == 0 || reg > num_channels) {
|
||||
dev_warn(dev,
|
||||
"Invalid channel number (ignoring): %d\n", reg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (reg != (ch + 1))
|
||||
continue;
|
||||
|
||||
*bipolar = fwnode_property_read_bool(child, "bipolar");
|
||||
|
||||
ret = fwnode_property_read_u32_array(child, "diff-channels",
|
||||
pins, ARRAY_SIZE(pins));
|
||||
/* Channel is differential, if pins are the same as 'reg' */
|
||||
if (ret == 0 && (pins[0] != reg || pins[1] != reg)) {
|
||||
dev_err(dev,
|
||||
"Differential pins must be the same as 'reg'");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*differential = (ret == 0);
|
||||
|
||||
if (*differential && !*bipolar) {
|
||||
dev_err(dev,
|
||||
"'bipolar' must be added for diff channel %d\n",
|
||||
reg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7606c_18bit_chan_scale_setup(struct ad7606_state *st,
|
||||
struct iio_chan_spec *chan, int ch)
|
||||
{
|
||||
struct ad7606_chan_scale *cs = &st->chan_scales[ch];
|
||||
bool bipolar, differential;
|
||||
int ret;
|
||||
|
||||
if (!st->sw_mode_en) {
|
||||
cs->range = 0;
|
||||
cs->scale_avail = ad7606_18bit_hw_scale_avail;
|
||||
cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ad7606_get_chan_config(st, ch, &bipolar, &differential);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (differential) {
|
||||
cs->scale_avail = ad7606c_18bit_differential_bipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ARRAY_SIZE(ad7606c_18bit_differential_bipolar_scale_avail);
|
||||
/* Bipolar differential ranges start at 8 (b1000) */
|
||||
cs->reg_offset = 8;
|
||||
cs->range = 1;
|
||||
chan->differential = 1;
|
||||
chan->channel2 = chan->channel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
chan->differential = 0;
|
||||
|
||||
if (bipolar) {
|
||||
cs->scale_avail = ad7606c_18bit_single_ended_bipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ARRAY_SIZE(ad7606c_18bit_single_ended_bipolar_scale_avail);
|
||||
/* Bipolar single-ended ranges start at 0 (b0000) */
|
||||
cs->reg_offset = 0;
|
||||
cs->range = 3;
|
||||
chan->scan_type.sign = 's';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cs->scale_avail = ad7606c_18bit_single_ended_unipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ARRAY_SIZE(ad7606c_18bit_single_ended_unipolar_scale_avail);
|
||||
/* Unipolar single-ended ranges start at 5 (b0101) */
|
||||
cs->reg_offset = 5;
|
||||
cs->range = 1;
|
||||
chan->scan_type.sign = 'u';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7606c_16bit_chan_scale_setup(struct ad7606_state *st,
|
||||
struct iio_chan_spec *chan, int ch)
|
||||
{
|
||||
struct ad7606_chan_scale *cs = &st->chan_scales[ch];
|
||||
bool bipolar, differential;
|
||||
int ret;
|
||||
|
||||
if (!st->sw_mode_en) {
|
||||
cs->range = 0;
|
||||
cs->scale_avail = ad7606_16bit_hw_scale_avail;
|
||||
cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ad7606_get_chan_config(st, ch, &bipolar, &differential);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (differential) {
|
||||
cs->scale_avail = ad7606c_16bit_differential_bipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ARRAY_SIZE(ad7606c_16bit_differential_bipolar_scale_avail);
|
||||
/* Bipolar differential ranges start at 8 (b1000) */
|
||||
cs->reg_offset = 8;
|
||||
cs->range = 1;
|
||||
chan->differential = 1;
|
||||
chan->channel2 = chan->channel;
|
||||
chan->scan_type.sign = 's';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
chan->differential = 0;
|
||||
|
||||
if (bipolar) {
|
||||
cs->scale_avail = ad7606c_16bit_single_ended_bipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ARRAY_SIZE(ad7606c_16bit_single_ended_bipolar_scale_avail);
|
||||
/* Bipolar single-ended ranges start at 0 (b0000) */
|
||||
cs->reg_offset = 0;
|
||||
cs->range = 3;
|
||||
chan->scan_type.sign = 's';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cs->scale_avail = ad7606c_16bit_single_ended_unipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ARRAY_SIZE(ad7606c_16bit_single_ended_unipolar_scale_avail);
|
||||
/* Unipolar single-ended ranges start at 5 (b0101) */
|
||||
cs->reg_offset = 5;
|
||||
cs->range = 1;
|
||||
chan->scan_type.sign = 'u';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7606_reg_access(struct iio_dev *indio_dev,
|
||||
unsigned int reg,
|
||||
unsigned int writeval,
|
||||
@@ -86,9 +302,8 @@ static int ad7606_reg_access(struct iio_dev *indio_dev,
|
||||
static int ad7606_read_samples(struct ad7606_state *st)
|
||||
{
|
||||
unsigned int num = st->chip_info->num_channels - 1;
|
||||
u16 *data = st->data;
|
||||
|
||||
return st->bops->read_block(st->dev, num, data);
|
||||
return st->bops->read_block(st->dev, num, &st->data);
|
||||
}
|
||||
|
||||
static irqreturn_t ad7606_trigger_handler(int irq, void *p)
|
||||
@@ -104,7 +319,7 @@ static irqreturn_t ad7606_trigger_handler(int irq, void *p)
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->data,
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &st->data,
|
||||
iio_get_time_ns(indio_dev));
|
||||
error_ret:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
@@ -114,9 +329,12 @@ static irqreturn_t ad7606_trigger_handler(int irq, void *p)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
|
||||
static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
|
||||
int *val)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
unsigned int storagebits = st->chip_info->channels[1].scan_type.storagebits;
|
||||
const struct iio_chan_spec *chan;
|
||||
int ret;
|
||||
|
||||
gpiod_set_value(st->gpio_convst, 1);
|
||||
@@ -128,8 +346,21 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
|
||||
}
|
||||
|
||||
ret = ad7606_read_samples(st);
|
||||
if (ret == 0)
|
||||
ret = st->data[ch];
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
|
||||
chan = &indio_dev->channels[ch + 1];
|
||||
if (chan->scan_type.sign == 'u') {
|
||||
if (storagebits > 16)
|
||||
*val = st->data.buf32[ch];
|
||||
else
|
||||
*val = st->data.buf16[ch];
|
||||
} else {
|
||||
if (storagebits > 16)
|
||||
*val = sign_extend32(st->data.buf32[ch], 17);
|
||||
else
|
||||
*val = sign_extend32(st->data.buf16[ch], 15);
|
||||
}
|
||||
|
||||
error_ret:
|
||||
gpiod_set_value(st->gpio_convst, 0);
|
||||
@@ -145,22 +376,23 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
|
||||
{
|
||||
int ret, ch = 0;
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs;
|
||||
|
||||
switch (m) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
|
||||
ret = ad7606_scan_direct(indio_dev, chan->address);
|
||||
ret = ad7606_scan_direct(indio_dev, chan->address, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = (short) ret;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
unreachable();
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (st->sw_mode_en)
|
||||
ch = chan->address;
|
||||
cs = &st->chan_scales[ch];
|
||||
*val = 0;
|
||||
*val2 = st->scale_avail[st->range[ch]];
|
||||
*val2 = cs->scale_avail[cs->range];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
*val = st->oversampling;
|
||||
@@ -190,8 +422,9 @@ static ssize_t in_voltage_scale_available_show(struct device *dev,
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs = &st->chan_scales[0];
|
||||
|
||||
return ad7606_show_avail(buf, st->scale_avail, st->num_scales, true);
|
||||
return ad7606_show_avail(buf, cs->scale_avail, cs->num_scales, true);
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0);
|
||||
@@ -229,19 +462,21 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
|
||||
long mask)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs;
|
||||
int i, ret, ch = 0;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
i = find_closest(val2, st->scale_avail, st->num_scales);
|
||||
if (st->sw_mode_en)
|
||||
ch = chan->address;
|
||||
ret = st->write_scale(indio_dev, ch, i);
|
||||
cs = &st->chan_scales[ch];
|
||||
i = find_closest(val2, cs->scale_avail, cs->num_scales);
|
||||
ret = st->write_scale(indio_dev, ch, i + cs->reg_offset);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
st->range[ch] = i;
|
||||
cs->range = i;
|
||||
|
||||
return 0;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
@@ -309,16 +544,28 @@ static const struct iio_chan_spec ad7605_channels[] = {
|
||||
AD7605_CHANNEL(3),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7606_channels[] = {
|
||||
static const struct iio_chan_spec ad7606_channels_16bit[] = {
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
AD7606_CHANNEL(0),
|
||||
AD7606_CHANNEL(1),
|
||||
AD7606_CHANNEL(2),
|
||||
AD7606_CHANNEL(3),
|
||||
AD7606_CHANNEL(4),
|
||||
AD7606_CHANNEL(5),
|
||||
AD7606_CHANNEL(6),
|
||||
AD7606_CHANNEL(7),
|
||||
AD7606_CHANNEL(0, 16),
|
||||
AD7606_CHANNEL(1, 16),
|
||||
AD7606_CHANNEL(2, 16),
|
||||
AD7606_CHANNEL(3, 16),
|
||||
AD7606_CHANNEL(4, 16),
|
||||
AD7606_CHANNEL(5, 16),
|
||||
AD7606_CHANNEL(6, 16),
|
||||
AD7606_CHANNEL(7, 16),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7606_channels_18bit[] = {
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
AD7606_CHANNEL(0, 18),
|
||||
AD7606_CHANNEL(1, 18),
|
||||
AD7606_CHANNEL(2, 18),
|
||||
AD7606_CHANNEL(3, 18),
|
||||
AD7606_CHANNEL(4, 18),
|
||||
AD7606_CHANNEL(5, 18),
|
||||
AD7606_CHANNEL(6, 18),
|
||||
AD7606_CHANNEL(7, 18),
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -333,22 +580,22 @@ static const struct iio_chan_spec ad7606_channels[] = {
|
||||
*/
|
||||
static const struct iio_chan_spec ad7616_channels[] = {
|
||||
IIO_CHAN_SOFT_TIMESTAMP(16),
|
||||
AD7606_CHANNEL(0),
|
||||
AD7606_CHANNEL(1),
|
||||
AD7606_CHANNEL(2),
|
||||
AD7606_CHANNEL(3),
|
||||
AD7606_CHANNEL(4),
|
||||
AD7606_CHANNEL(5),
|
||||
AD7606_CHANNEL(6),
|
||||
AD7606_CHANNEL(7),
|
||||
AD7606_CHANNEL(8),
|
||||
AD7606_CHANNEL(9),
|
||||
AD7606_CHANNEL(10),
|
||||
AD7606_CHANNEL(11),
|
||||
AD7606_CHANNEL(12),
|
||||
AD7606_CHANNEL(13),
|
||||
AD7606_CHANNEL(14),
|
||||
AD7606_CHANNEL(15),
|
||||
AD7606_CHANNEL(0, 16),
|
||||
AD7606_CHANNEL(1, 16),
|
||||
AD7606_CHANNEL(2, 16),
|
||||
AD7606_CHANNEL(3, 16),
|
||||
AD7606_CHANNEL(4, 16),
|
||||
AD7606_CHANNEL(5, 16),
|
||||
AD7606_CHANNEL(6, 16),
|
||||
AD7606_CHANNEL(7, 16),
|
||||
AD7606_CHANNEL(8, 16),
|
||||
AD7606_CHANNEL(9, 16),
|
||||
AD7606_CHANNEL(10, 16),
|
||||
AD7606_CHANNEL(11, 16),
|
||||
AD7606_CHANNEL(12, 16),
|
||||
AD7606_CHANNEL(13, 16),
|
||||
AD7606_CHANNEL(14, 16),
|
||||
AD7606_CHANNEL(15, 16),
|
||||
};
|
||||
|
||||
static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
|
||||
@@ -356,34 +603,54 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
|
||||
[ID_AD7605_4] = {
|
||||
.channels = ad7605_channels,
|
||||
.num_channels = 5,
|
||||
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
|
||||
},
|
||||
[ID_AD7606_8] = {
|
||||
.channels = ad7606_channels,
|
||||
.channels = ad7606_channels_16bit,
|
||||
.num_channels = 9,
|
||||
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
|
||||
.oversampling_avail = ad7606_oversampling_avail,
|
||||
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
|
||||
},
|
||||
[ID_AD7606_6] = {
|
||||
.channels = ad7606_channels,
|
||||
.channels = ad7606_channels_16bit,
|
||||
.num_channels = 7,
|
||||
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
|
||||
.oversampling_avail = ad7606_oversampling_avail,
|
||||
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
|
||||
},
|
||||
[ID_AD7606_4] = {
|
||||
.channels = ad7606_channels,
|
||||
.channels = ad7606_channels_16bit,
|
||||
.num_channels = 5,
|
||||
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
|
||||
.oversampling_avail = ad7606_oversampling_avail,
|
||||
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
|
||||
},
|
||||
[ID_AD7606B] = {
|
||||
.channels = ad7606_channels,
|
||||
.channels = ad7606_channels_16bit,
|
||||
.num_channels = 9,
|
||||
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
|
||||
.oversampling_avail = ad7606_oversampling_avail,
|
||||
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
|
||||
},
|
||||
[ID_AD7606C_16] = {
|
||||
.channels = ad7606_channels_16bit,
|
||||
.num_channels = 9,
|
||||
.scale_setup_cb = ad7606c_16bit_chan_scale_setup,
|
||||
.oversampling_avail = ad7606_oversampling_avail,
|
||||
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
|
||||
},
|
||||
[ID_AD7606C_18] = {
|
||||
.channels = ad7606_channels_18bit,
|
||||
.num_channels = 9,
|
||||
.scale_setup_cb = ad7606c_18bit_chan_scale_setup,
|
||||
.oversampling_avail = ad7606_oversampling_avail,
|
||||
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
|
||||
},
|
||||
[ID_AD7616] = {
|
||||
.channels = ad7616_channels,
|
||||
.num_channels = 17,
|
||||
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
|
||||
.oversampling_avail = ad7616_oversampling_avail,
|
||||
.oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
|
||||
.os_req_reset = true,
|
||||
@@ -478,6 +745,37 @@ static int ad7606_buffer_predisable(struct iio_dev *indio_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7606_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length,
|
||||
long info)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs;
|
||||
unsigned int ch = 0;
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
*vals = st->oversampling_avail;
|
||||
*length = st->num_os_ratios;
|
||||
*type = IIO_VAL_INT;
|
||||
|
||||
return IIO_AVAIL_LIST;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (st->sw_mode_en)
|
||||
ch = chan->address;
|
||||
|
||||
cs = &st->chan_scales[ch];
|
||||
*vals = cs->scale_avail_show;
|
||||
*length = cs->num_scales * 2;
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
|
||||
return IIO_AVAIL_LIST;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops ad7606_buffer_ops = {
|
||||
.postenable = &ad7606_buffer_postenable,
|
||||
.predisable = &ad7606_buffer_predisable,
|
||||
@@ -495,11 +793,11 @@ static const struct iio_info ad7606_info_os_and_range = {
|
||||
.validate_trigger = &ad7606_validate_trigger,
|
||||
};
|
||||
|
||||
static const struct iio_info ad7606_info_os_range_and_debug = {
|
||||
static const struct iio_info ad7606_info_sw_mode = {
|
||||
.read_raw = &ad7606_read_raw,
|
||||
.write_raw = &ad7606_write_raw,
|
||||
.read_avail = &ad7606_read_avail,
|
||||
.debugfs_reg_access = &ad7606_reg_access,
|
||||
.attrs = &ad7606_attribute_group_os_and_range,
|
||||
.validate_trigger = &ad7606_validate_trigger,
|
||||
};
|
||||
|
||||
@@ -521,6 +819,61 @@ static const struct iio_trigger_ops ad7606_trigger_ops = {
|
||||
.validate_device = iio_trigger_validate_own_device,
|
||||
};
|
||||
|
||||
static int ad7606_sw_mode_setup(struct iio_dev *indio_dev, unsigned int id)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
|
||||
st->sw_mode_en = st->bops->sw_mode_config &&
|
||||
device_property_present(st->dev, "adi,sw-mode");
|
||||
if (!st->sw_mode_en)
|
||||
return 0;
|
||||
|
||||
indio_dev->info = &ad7606_info_sw_mode;
|
||||
|
||||
return st->bops->sw_mode_config(indio_dev);
|
||||
}
|
||||
|
||||
static int ad7606_chan_scales_setup(struct iio_dev *indio_dev)
|
||||
{
|
||||
unsigned int num_channels = indio_dev->num_channels - 1;
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct iio_chan_spec *chans;
|
||||
size_t size;
|
||||
int ch, ret;
|
||||
|
||||
/* Clone IIO channels, since some may be differential */
|
||||
size = indio_dev->num_channels * sizeof(*indio_dev->channels);
|
||||
chans = devm_kzalloc(st->dev, size, GFP_KERNEL);
|
||||
if (!chans)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(chans, indio_dev->channels, size);
|
||||
indio_dev->channels = chans;
|
||||
|
||||
for (ch = 0; ch < num_channels; ch++) {
|
||||
struct ad7606_chan_scale *cs;
|
||||
int i;
|
||||
|
||||
ret = st->chip_info->scale_setup_cb(st, &chans[ch + 1], ch);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cs = &st->chan_scales[ch];
|
||||
|
||||
if (cs->num_scales * 2 > AD760X_MAX_SCALE_SHOW)
|
||||
return dev_err_probe(st->dev, -ERANGE,
|
||||
"Driver error: scale range too big");
|
||||
|
||||
/* Generate a scale_avail list for showing to userspace */
|
||||
for (i = 0; i < cs->num_scales; i++) {
|
||||
cs->scale_avail_show[i * 2] = 0;
|
||||
cs->scale_avail_show[i * 2 + 1] = cs->scale_avail[i];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
|
||||
const char *name, unsigned int id,
|
||||
const struct ad7606_bus_ops *bops)
|
||||
@@ -540,11 +893,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
|
||||
mutex_init(&st->lock);
|
||||
st->bops = bops;
|
||||
st->base_address = base_address;
|
||||
/* tied to logic low, analog input range is +/- 5V */
|
||||
st->range[0] = 0;
|
||||
st->oversampling = 1;
|
||||
st->scale_avail = ad7606_scale_avail;
|
||||
st->num_scales = ARRAY_SIZE(ad7606_scale_avail);
|
||||
|
||||
ret = devm_regulator_get_enable(dev, "avcc");
|
||||
if (ret)
|
||||
@@ -593,23 +942,13 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
|
||||
st->write_scale = ad7606_write_scale_hw;
|
||||
st->write_os = ad7606_write_os_hw;
|
||||
|
||||
if (st->bops->sw_mode_config)
|
||||
st->sw_mode_en = device_property_present(st->dev,
|
||||
"adi,sw-mode");
|
||||
ret = ad7606_sw_mode_setup(indio_dev, id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (st->sw_mode_en) {
|
||||
/* Scale of 0.076293 is only available in sw mode */
|
||||
st->scale_avail = ad7616_sw_scale_avail;
|
||||
st->num_scales = ARRAY_SIZE(ad7616_sw_scale_avail);
|
||||
|
||||
/* After reset, in software mode, ±10 V is set by default */
|
||||
memset32(st->range, 2, ARRAY_SIZE(st->range));
|
||||
indio_dev->info = &ad7606_info_os_range_and_debug;
|
||||
|
||||
ret = st->bops->sw_mode_config(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
ret = ad7606_chan_scales_setup(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
|
||||
indio_dev->name,
|
||||
@@ -665,7 +1004,7 @@ static int ad7606_resume(struct device *dev)
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (st->gpio_standby) {
|
||||
gpiod_set_value(st->gpio_range, st->range[0]);
|
||||
gpiod_set_value(st->gpio_range, st->chan_scales[0].range);
|
||||
gpiod_set_value(st->gpio_standby, 1);
|
||||
ad7606_reset(st);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#ifndef IIO_ADC_AD7606_H_
|
||||
#define IIO_ADC_AD7606_H_
|
||||
|
||||
#define AD760X_CHANNEL(num, mask_sep, mask_type, mask_all) { \
|
||||
#define AD760X_MAX_CHANNELS 16
|
||||
|
||||
#define AD760X_CHANNEL(num, mask_sep, mask_type, mask_all, bits) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = num, \
|
||||
@@ -19,56 +21,102 @@
|
||||
.scan_index = num, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 16, \
|
||||
.storagebits = 16, \
|
||||
.realbits = (bits), \
|
||||
.storagebits = (bits) > 16 ? 32 : 16, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define AD7606_SW_CHANNEL(num, bits) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = num, \
|
||||
.address = num, \
|
||||
.info_mask_separate = \
|
||||
BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_separate_available = \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = \
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
|
||||
.info_mask_shared_by_all_available = \
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
|
||||
.scan_index = num, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = (bits), \
|
||||
.storagebits = (bits) > 16 ? 32 : 16, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define AD7605_CHANNEL(num) \
|
||||
AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \
|
||||
BIT(IIO_CHAN_INFO_SCALE), 0)
|
||||
BIT(IIO_CHAN_INFO_SCALE), 0, 16)
|
||||
|
||||
#define AD7606_CHANNEL(num) \
|
||||
#define AD7606_CHANNEL(num, bits) \
|
||||
AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO))
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), bits)
|
||||
|
||||
#define AD7616_CHANNEL(num) \
|
||||
AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),\
|
||||
0, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO))
|
||||
#define AD7616_CHANNEL(num) AD7606_SW_CHANNEL(num, 16)
|
||||
|
||||
struct ad7606_state;
|
||||
|
||||
typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st,
|
||||
struct iio_chan_spec *chan, int ch);
|
||||
|
||||
/**
|
||||
* struct ad7606_chip_info - chip specific information
|
||||
* @channels: channel specification
|
||||
* @num_channels: number of channels
|
||||
* @scale_setup_cb: callback to setup the scales for each channel
|
||||
* @oversampling_avail pointer to the array which stores the available
|
||||
* oversampling ratios.
|
||||
* @oversampling_num number of elements stored in oversampling_avail array
|
||||
* @os_req_reset some devices require a reset to update oversampling
|
||||
* @init_delay_ms required delay in miliseconds for initialization
|
||||
* @init_delay_ms required delay in milliseconds for initialization
|
||||
* after a restart
|
||||
*/
|
||||
struct ad7606_chip_info {
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned int num_channels;
|
||||
ad7606_scale_setup_cb_t scale_setup_cb;
|
||||
const unsigned int *oversampling_avail;
|
||||
unsigned int oversampling_num;
|
||||
bool os_req_reset;
|
||||
unsigned long init_delay_ms;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ad7606_chan_scale - channel scale configuration
|
||||
* @scale_avail pointer to the array which stores the available scales
|
||||
* @scale_avail_show a duplicate of 'scale_avail' which is readily formatted
|
||||
* such that it can be read via the 'read_avail' hook
|
||||
* @num_scales number of elements stored in the scale_avail array
|
||||
* @range voltage range selection, selects which scale to apply
|
||||
* @reg_offset offset for the register value, to be applied when
|
||||
* writing the value of 'range' to the register value
|
||||
*/
|
||||
struct ad7606_chan_scale {
|
||||
#define AD760X_MAX_SCALES 16
|
||||
#define AD760X_MAX_SCALE_SHOW (AD760X_MAX_SCALES * 2)
|
||||
const unsigned int *scale_avail;
|
||||
int scale_avail_show[AD760X_MAX_SCALE_SHOW];
|
||||
unsigned int num_scales;
|
||||
unsigned int range;
|
||||
unsigned int reg_offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ad7606_state - driver instance specific data
|
||||
* @dev pointer to kernel device
|
||||
* @chip_info entry in the table of chips that describes this device
|
||||
* @bops bus operations (SPI or parallel)
|
||||
* @range voltage range selection, selects which scale to apply
|
||||
* @chan_scales scale configuration for channels
|
||||
* @oversampling oversampling selection
|
||||
* @base_address address from where to read data in parallel operation
|
||||
* @sw_mode_en software mode enabled
|
||||
* @scale_avail pointer to the array which stores the available scales
|
||||
* @num_scales number of elements stored in the scale_avail array
|
||||
* @oversampling_avail pointer to the array which stores the available
|
||||
* oversampling ratios.
|
||||
* @num_os_ratios number of elements stored in oversampling_avail array
|
||||
@@ -92,12 +140,10 @@ struct ad7606_state {
|
||||
struct device *dev;
|
||||
const struct ad7606_chip_info *chip_info;
|
||||
const struct ad7606_bus_ops *bops;
|
||||
unsigned int range[16];
|
||||
struct ad7606_chan_scale chan_scales[AD760X_MAX_CHANNELS];
|
||||
unsigned int oversampling;
|
||||
void __iomem *base_address;
|
||||
bool sw_mode_en;
|
||||
const unsigned int *scale_avail;
|
||||
unsigned int num_scales;
|
||||
const unsigned int *oversampling_avail;
|
||||
unsigned int num_os_ratios;
|
||||
int (*write_scale)(struct iio_dev *indio_dev, int ch, int val);
|
||||
@@ -116,9 +162,13 @@ struct ad7606_state {
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) may require the
|
||||
* transfer buffers to live in their own cache lines.
|
||||
* 16 * 16-bit samples + 64-bit timestamp
|
||||
* 16 * 16-bit samples + 64-bit timestamp - for AD7616
|
||||
* 8 * 32-bit samples + 64-bit timestamp - for AD7616C-18 (and similar)
|
||||
*/
|
||||
unsigned short data[20] __aligned(IIO_DMA_MINALIGN);
|
||||
union {
|
||||
u16 buf16[20];
|
||||
u32 buf32[10];
|
||||
} data __aligned(IIO_DMA_MINALIGN);
|
||||
__be16 d16[2];
|
||||
};
|
||||
|
||||
@@ -159,6 +209,8 @@ enum ad7606_supported_device_ids {
|
||||
ID_AD7606_6,
|
||||
ID_AD7606_4,
|
||||
ID_AD7606B,
|
||||
ID_AD7606C_16,
|
||||
ID_AD7606C_18,
|
||||
ID_AD7616,
|
||||
};
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include "ad7606.h"
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include "ad7606.h"
|
||||
@@ -67,14 +67,26 @@ static const struct iio_chan_spec ad7616_sw_channels[] = {
|
||||
|
||||
static const struct iio_chan_spec ad7606b_sw_channels[] = {
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
AD7616_CHANNEL(0),
|
||||
AD7616_CHANNEL(1),
|
||||
AD7616_CHANNEL(2),
|
||||
AD7616_CHANNEL(3),
|
||||
AD7616_CHANNEL(4),
|
||||
AD7616_CHANNEL(5),
|
||||
AD7616_CHANNEL(6),
|
||||
AD7616_CHANNEL(7),
|
||||
AD7606_SW_CHANNEL(0, 16),
|
||||
AD7606_SW_CHANNEL(1, 16),
|
||||
AD7606_SW_CHANNEL(2, 16),
|
||||
AD7606_SW_CHANNEL(3, 16),
|
||||
AD7606_SW_CHANNEL(4, 16),
|
||||
AD7606_SW_CHANNEL(5, 16),
|
||||
AD7606_SW_CHANNEL(6, 16),
|
||||
AD7606_SW_CHANNEL(7, 16),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7606c_18_sw_channels[] = {
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
AD7606_SW_CHANNEL(0, 18),
|
||||
AD7606_SW_CHANNEL(1, 18),
|
||||
AD7606_SW_CHANNEL(2, 18),
|
||||
AD7606_SW_CHANNEL(3, 18),
|
||||
AD7606_SW_CHANNEL(4, 18),
|
||||
AD7606_SW_CHANNEL(5, 18),
|
||||
AD7606_SW_CHANNEL(6, 18),
|
||||
AD7606_SW_CHANNEL(7, 18),
|
||||
};
|
||||
|
||||
static const unsigned int ad7606B_oversampling_avail[9] = {
|
||||
@@ -120,6 +132,19 @@ static int ad7606_spi_read_block(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7606_spi_read_block18to32(struct device *dev,
|
||||
int count, void *buf)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
struct spi_transfer xfer = {
|
||||
.bits_per_word = 18,
|
||||
.len = count * sizeof(u32),
|
||||
.rx_buf = buf,
|
||||
};
|
||||
|
||||
return spi_sync_transfer(spi, &xfer, 1);
|
||||
}
|
||||
|
||||
static int ad7606_spi_reg_read(struct ad7606_state *st, unsigned int addr)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(st->dev);
|
||||
@@ -283,6 +308,19 @@ static int ad7606B_sw_mode_config(struct iio_dev *indio_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7606c_18_sw_mode_config(struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ad7606B_sw_mode_config(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->channels = ad7606c_18_sw_channels;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ad7606_bus_ops ad7606_spi_bops = {
|
||||
.read_block = ad7606_spi_read_block,
|
||||
};
|
||||
@@ -305,6 +343,15 @@ static const struct ad7606_bus_ops ad7606B_spi_bops = {
|
||||
.sw_mode_config = ad7606B_sw_mode_config,
|
||||
};
|
||||
|
||||
static const struct ad7606_bus_ops ad7606c_18_spi_bops = {
|
||||
.read_block = ad7606_spi_read_block18to32,
|
||||
.reg_read = ad7606_spi_reg_read,
|
||||
.reg_write = ad7606_spi_reg_write,
|
||||
.write_mask = ad7606_spi_write_mask,
|
||||
.rd_wr_cmd = ad7606B_spi_rd_wr_cmd,
|
||||
.sw_mode_config = ad7606c_18_sw_mode_config,
|
||||
};
|
||||
|
||||
static int ad7606_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
@@ -315,8 +362,12 @@ static int ad7606_spi_probe(struct spi_device *spi)
|
||||
bops = &ad7616_spi_bops;
|
||||
break;
|
||||
case ID_AD7606B:
|
||||
case ID_AD7606C_16:
|
||||
bops = &ad7606B_spi_bops;
|
||||
break;
|
||||
case ID_AD7606C_18:
|
||||
bops = &ad7606c_18_spi_bops;
|
||||
break;
|
||||
default:
|
||||
bops = &ad7606_spi_bops;
|
||||
break;
|
||||
@@ -333,6 +384,8 @@ static const struct spi_device_id ad7606_id_table[] = {
|
||||
{ "ad7606-6", ID_AD7606_6 },
|
||||
{ "ad7606-8", ID_AD7606_8 },
|
||||
{ "ad7606b", ID_AD7606B },
|
||||
{ "ad7606c-16", ID_AD7606C_16 },
|
||||
{ "ad7606c-18", ID_AD7606C_18 },
|
||||
{ "ad7616", ID_AD7616 },
|
||||
{ }
|
||||
};
|
||||
@@ -344,6 +397,8 @@ static const struct of_device_id ad7606_of_match[] = {
|
||||
{ .compatible = "adi,ad7606-6" },
|
||||
{ .compatible = "adi,ad7606-8" },
|
||||
{ .compatible = "adi,ad7606b" },
|
||||
{ .compatible = "adi,ad7606c-16" },
|
||||
{ .compatible = "adi,ad7606c-18" },
|
||||
{ .compatible = "adi,ad7616" },
|
||||
{ }
|
||||
};
|
||||
|
||||
684
drivers/iio/adc/ad7625.c
Normal file
684
drivers/iio/adc/ad7625.c
Normal file
@@ -0,0 +1,684 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
/*
|
||||
* Analog Devices Inc. AD7625 ADC driver
|
||||
*
|
||||
* Copyright 2024 Analog Devices Inc.
|
||||
* Copyright 2024 BayLibre, SAS
|
||||
*
|
||||
* Note that this driver requires the AXI ADC IP block configured for
|
||||
* LVDS to function. See Documentation/iio/ad7625.rst for more
|
||||
* information.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/iio/backend.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#define AD7625_INTERNAL_REF_MV 4096
|
||||
#define AD7960_MAX_NBW_FREQ (2 * MEGA)
|
||||
|
||||
struct ad7625_timing_spec {
|
||||
/* Max conversion high time (t_{CNVH}). */
|
||||
unsigned int conv_high_ns;
|
||||
/* Max conversion to MSB delay (t_{MSB}). */
|
||||
unsigned int conv_msb_ns;
|
||||
};
|
||||
|
||||
struct ad7625_chip_info {
|
||||
const char *name;
|
||||
const unsigned int max_sample_freq_hz;
|
||||
const struct ad7625_timing_spec *timing_spec;
|
||||
const struct iio_chan_spec chan_spec;
|
||||
const bool has_power_down_state;
|
||||
const bool has_bandwidth_control;
|
||||
const bool has_internal_vref;
|
||||
};
|
||||
|
||||
/* AD7625_CHAN_SPEC - Define a chan spec structure for a specific chip */
|
||||
#define AD7625_CHAN_SPEC(_bits) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.differential = 1, \
|
||||
.channel = 0, \
|
||||
.channel2 = 1, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.scan_index = 0, \
|
||||
.scan_type.sign = 's', \
|
||||
.scan_type.storagebits = (_bits) > 16 ? 32 : 16, \
|
||||
.scan_type.realbits = (_bits), \
|
||||
}
|
||||
|
||||
struct ad7625_state {
|
||||
const struct ad7625_chip_info *info;
|
||||
struct iio_backend *back;
|
||||
/* rate of the clock gated by the "clk_gate" PWM */
|
||||
u32 ref_clk_rate_hz;
|
||||
/* PWM burst signal for transferring acquired data to the host */
|
||||
struct pwm_device *clk_gate_pwm;
|
||||
/*
|
||||
* PWM control signal for initiating data conversion. Analog
|
||||
* inputs are sampled beginning on this signal's rising edge.
|
||||
*/
|
||||
struct pwm_device *cnv_pwm;
|
||||
/*
|
||||
* Waveforms containing the last-requested and rounded
|
||||
* properties for the clk_gate and cnv PWMs
|
||||
*/
|
||||
struct pwm_waveform clk_gate_wf;
|
||||
struct pwm_waveform cnv_wf;
|
||||
unsigned int vref_mv;
|
||||
u32 sampling_freq_hz;
|
||||
/*
|
||||
* Optional GPIOs for controlling device state. EN0 and EN1
|
||||
* determine voltage reference configuration and on/off state.
|
||||
* EN2 controls the device -3dB bandwidth (and by extension, max
|
||||
* sample rate). EN3 controls the VCM reference output. EN2 and
|
||||
* EN3 are only present for the AD796x devices.
|
||||
*/
|
||||
struct gpio_desc *en_gpios[4];
|
||||
bool can_power_down;
|
||||
bool can_refin;
|
||||
bool can_ref_4v096;
|
||||
/*
|
||||
* Indicate whether the bandwidth can be narrow (9MHz).
|
||||
* When true, device sample rate must also be < 2MSPS.
|
||||
*/
|
||||
bool can_narrow_bandwidth;
|
||||
/* Indicate whether the bandwidth can be wide (28MHz). */
|
||||
bool can_wide_bandwidth;
|
||||
bool can_ref_5v;
|
||||
bool can_snooze;
|
||||
bool can_test_pattern;
|
||||
/* Indicate whether there is a REFIN supply connected */
|
||||
bool have_refin;
|
||||
};
|
||||
|
||||
static const struct ad7625_timing_spec ad7625_timing_spec = {
|
||||
.conv_high_ns = 40,
|
||||
.conv_msb_ns = 145,
|
||||
};
|
||||
|
||||
static const struct ad7625_timing_spec ad7626_timing_spec = {
|
||||
.conv_high_ns = 40,
|
||||
.conv_msb_ns = 80,
|
||||
};
|
||||
|
||||
/*
|
||||
* conv_msb_ns is set to 0 instead of the datasheet maximum of 200ns to
|
||||
* avoid exceeding the minimum conversion time, i.e. it is effectively
|
||||
* modulo 200 and offset by a full period. Values greater than or equal
|
||||
* to the period would be rejected by the PWM API.
|
||||
*/
|
||||
static const struct ad7625_timing_spec ad7960_timing_spec = {
|
||||
.conv_high_ns = 80,
|
||||
.conv_msb_ns = 0,
|
||||
};
|
||||
|
||||
static const struct ad7625_chip_info ad7625_chip_info = {
|
||||
.name = "ad7625",
|
||||
.max_sample_freq_hz = 6 * MEGA,
|
||||
.timing_spec = &ad7625_timing_spec,
|
||||
.chan_spec = AD7625_CHAN_SPEC(16),
|
||||
.has_power_down_state = false,
|
||||
.has_bandwidth_control = false,
|
||||
.has_internal_vref = true,
|
||||
};
|
||||
|
||||
static const struct ad7625_chip_info ad7626_chip_info = {
|
||||
.name = "ad7626",
|
||||
.max_sample_freq_hz = 10 * MEGA,
|
||||
.timing_spec = &ad7626_timing_spec,
|
||||
.chan_spec = AD7625_CHAN_SPEC(16),
|
||||
.has_power_down_state = true,
|
||||
.has_bandwidth_control = false,
|
||||
.has_internal_vref = true,
|
||||
};
|
||||
|
||||
static const struct ad7625_chip_info ad7960_chip_info = {
|
||||
.name = "ad7960",
|
||||
.max_sample_freq_hz = 5 * MEGA,
|
||||
.timing_spec = &ad7960_timing_spec,
|
||||
.chan_spec = AD7625_CHAN_SPEC(18),
|
||||
.has_power_down_state = true,
|
||||
.has_bandwidth_control = true,
|
||||
.has_internal_vref = false,
|
||||
};
|
||||
|
||||
static const struct ad7625_chip_info ad7961_chip_info = {
|
||||
.name = "ad7961",
|
||||
.max_sample_freq_hz = 5 * MEGA,
|
||||
.timing_spec = &ad7960_timing_spec,
|
||||
.chan_spec = AD7625_CHAN_SPEC(16),
|
||||
.has_power_down_state = true,
|
||||
.has_bandwidth_control = true,
|
||||
.has_internal_vref = false,
|
||||
};
|
||||
|
||||
enum ad7960_mode {
|
||||
AD7960_MODE_POWER_DOWN,
|
||||
AD7960_MODE_SNOOZE,
|
||||
AD7960_MODE_NARROW_BANDWIDTH,
|
||||
AD7960_MODE_WIDE_BANDWIDTH,
|
||||
AD7960_MODE_TEST_PATTERN,
|
||||
};
|
||||
|
||||
static int ad7625_set_sampling_freq(struct ad7625_state *st, u32 freq)
|
||||
{
|
||||
u32 target;
|
||||
struct pwm_waveform clk_gate_wf = { }, cnv_wf = { };
|
||||
int ret;
|
||||
|
||||
target = DIV_ROUND_UP(NSEC_PER_SEC, freq);
|
||||
cnv_wf.period_length_ns = clamp(target, 100, 10 * KILO);
|
||||
|
||||
/*
|
||||
* Use the maximum conversion time t_CNVH from the datasheet as
|
||||
* the duty_cycle for ref_clk, cnv, and clk_gate
|
||||
*/
|
||||
cnv_wf.duty_length_ns = st->info->timing_spec->conv_high_ns;
|
||||
|
||||
ret = pwm_round_waveform_might_sleep(st->cnv_pwm, &cnv_wf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Set up the burst signal for transferring data. period and
|
||||
* offset should mirror the CNV signal
|
||||
*/
|
||||
clk_gate_wf.period_length_ns = cnv_wf.period_length_ns;
|
||||
|
||||
clk_gate_wf.duty_length_ns = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC *
|
||||
st->info->chan_spec.scan_type.realbits,
|
||||
st->ref_clk_rate_hz);
|
||||
|
||||
/* max t_MSB from datasheet */
|
||||
clk_gate_wf.duty_offset_ns = st->info->timing_spec->conv_msb_ns;
|
||||
|
||||
ret = pwm_round_waveform_might_sleep(st->clk_gate_pwm, &clk_gate_wf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->cnv_wf = cnv_wf;
|
||||
st->clk_gate_wf = clk_gate_wf;
|
||||
|
||||
/* TODO: Add a rounding API for PWMs that can simplify this */
|
||||
target = DIV_ROUND_CLOSEST(st->ref_clk_rate_hz, freq);
|
||||
st->sampling_freq_hz = DIV_ROUND_CLOSEST(st->ref_clk_rate_hz,
|
||||
target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7625_read_raw(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
int *val, int *val2, long info)
|
||||
{
|
||||
struct ad7625_state *st = iio_priv(indio_dev);
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = st->sampling_freq_hz;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = st->vref_mv;
|
||||
*val2 = chan->scan_type.realbits - 1;
|
||||
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad7625_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long info)
|
||||
{
|
||||
struct ad7625_state *st = iio_priv(indio_dev);
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
|
||||
return ad7625_set_sampling_freq(st, val);
|
||||
unreachable();
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad7625_parse_mode(struct device *dev, struct ad7625_state *st,
|
||||
int num_gpios)
|
||||
{
|
||||
bool en_always_on[4], en_always_off[4];
|
||||
bool en_may_be_on[4], en_may_be_off[4];
|
||||
char en_gpio_buf[4];
|
||||
char always_on_buf[18];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_gpios; i++) {
|
||||
snprintf(en_gpio_buf, sizeof(en_gpio_buf), "en%d", i);
|
||||
snprintf(always_on_buf, sizeof(always_on_buf),
|
||||
"adi,en%d-always-on", i);
|
||||
/* Set the device to 0b0000 (power-down mode) by default */
|
||||
st->en_gpios[i] = devm_gpiod_get_optional(dev, en_gpio_buf,
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->en_gpios[i]))
|
||||
return dev_err_probe(dev, PTR_ERR(st->en_gpios[i]),
|
||||
"failed to get EN%d GPIO\n", i);
|
||||
|
||||
en_always_on[i] = device_property_read_bool(dev, always_on_buf);
|
||||
if (st->en_gpios[i] && en_always_on[i])
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"cannot have adi,en%d-always-on and en%d-gpios\n", i, i);
|
||||
|
||||
en_may_be_off[i] = !en_always_on[i];
|
||||
en_may_be_on[i] = en_always_on[i] || st->en_gpios[i];
|
||||
en_always_off[i] = !en_always_on[i] && !st->en_gpios[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* Power down is mode 0bXX00, but not all devices have a valid
|
||||
* power down state.
|
||||
*/
|
||||
st->can_power_down = en_may_be_off[1] && en_may_be_off[0] &&
|
||||
st->info->has_power_down_state;
|
||||
/*
|
||||
* The REFIN pin can take a 1.2V (AD762x) or 2.048V (AD796x)
|
||||
* external reference when the mode is 0bXX01.
|
||||
*/
|
||||
st->can_refin = en_may_be_off[1] && en_may_be_on[0];
|
||||
/* 4.096V can be applied to REF when the EN mode is 0bXX10. */
|
||||
st->can_ref_4v096 = en_may_be_on[1] && en_may_be_off[0];
|
||||
|
||||
/* Avoid AD796x-specific setup if the part is an AD762x */
|
||||
if (num_gpios == 2)
|
||||
return 0;
|
||||
|
||||
/* mode 0b1100 (AD796x) is invalid */
|
||||
if (en_always_on[3] && en_always_on[2] &&
|
||||
en_always_off[1] && en_always_off[0])
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"EN GPIOs set to invalid mode 0b1100\n");
|
||||
/*
|
||||
* 5V can be applied to the AD796x REF pin when the EN mode is
|
||||
* the same (0bX001 or 0bX101) as for can_refin, and REFIN is
|
||||
* 0V.
|
||||
*/
|
||||
st->can_ref_5v = st->can_refin;
|
||||
/*
|
||||
* Bandwidth (AD796x) is controlled solely by EN2. If it's
|
||||
* specified and not hard-wired, then we can configure it to
|
||||
* change the bandwidth between 28MHz and 9MHz.
|
||||
*/
|
||||
st->can_narrow_bandwidth = en_may_be_on[2];
|
||||
/* Wide bandwidth mode is possible if EN2 can be 0. */
|
||||
st->can_wide_bandwidth = en_may_be_off[2];
|
||||
/* Snooze mode (AD796x) is 0bXX11 when REFIN = 0V. */
|
||||
st->can_snooze = en_may_be_on[1] && en_may_be_on[0];
|
||||
/* Test pattern mode (AD796x) is 0b0100. */
|
||||
st->can_test_pattern = en_may_be_off[3] && en_may_be_on[2] &&
|
||||
en_may_be_off[1] && en_may_be_off[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set EN1 and EN0 based on reference voltage source */
|
||||
static void ad7625_set_en_gpios_for_vref(struct ad7625_state *st,
|
||||
bool have_refin, int ref_mv)
|
||||
{
|
||||
if (have_refin || ref_mv == 5000) {
|
||||
gpiod_set_value_cansleep(st->en_gpios[1], 0);
|
||||
gpiod_set_value_cansleep(st->en_gpios[0], 1);
|
||||
} else if (ref_mv == 4096) {
|
||||
gpiod_set_value_cansleep(st->en_gpios[1], 1);
|
||||
gpiod_set_value_cansleep(st->en_gpios[0], 0);
|
||||
} else {
|
||||
/*
|
||||
* Unreachable by AD796x, since the driver will error if
|
||||
* neither REF nor REFIN is provided
|
||||
*/
|
||||
gpiod_set_value_cansleep(st->en_gpios[1], 1);
|
||||
gpiod_set_value_cansleep(st->en_gpios[0], 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int ad7960_set_mode(struct ad7625_state *st, enum ad7960_mode mode,
|
||||
bool have_refin, int ref_mv)
|
||||
{
|
||||
switch (mode) {
|
||||
case AD7960_MODE_POWER_DOWN:
|
||||
if (!st->can_power_down)
|
||||
return -EINVAL;
|
||||
|
||||
gpiod_set_value_cansleep(st->en_gpios[2], 0);
|
||||
gpiod_set_value_cansleep(st->en_gpios[1], 0);
|
||||
gpiod_set_value_cansleep(st->en_gpios[0], 0);
|
||||
|
||||
return 0;
|
||||
|
||||
case AD7960_MODE_SNOOZE:
|
||||
if (!st->can_snooze)
|
||||
return -EINVAL;
|
||||
|
||||
gpiod_set_value_cansleep(st->en_gpios[1], 1);
|
||||
gpiod_set_value_cansleep(st->en_gpios[0], 1);
|
||||
|
||||
return 0;
|
||||
|
||||
case AD7960_MODE_NARROW_BANDWIDTH:
|
||||
if (!st->can_narrow_bandwidth)
|
||||
return -EINVAL;
|
||||
|
||||
gpiod_set_value_cansleep(st->en_gpios[2], 1);
|
||||
ad7625_set_en_gpios_for_vref(st, have_refin, ref_mv);
|
||||
|
||||
return 0;
|
||||
|
||||
case AD7960_MODE_WIDE_BANDWIDTH:
|
||||
if (!st->can_wide_bandwidth)
|
||||
return -EINVAL;
|
||||
|
||||
gpiod_set_value_cansleep(st->en_gpios[2], 0);
|
||||
ad7625_set_en_gpios_for_vref(st, have_refin, ref_mv);
|
||||
|
||||
return 0;
|
||||
|
||||
case AD7960_MODE_TEST_PATTERN:
|
||||
if (!st->can_test_pattern)
|
||||
return -EINVAL;
|
||||
|
||||
gpiod_set_value_cansleep(st->en_gpios[3], 0);
|
||||
gpiod_set_value_cansleep(st->en_gpios[2], 1);
|
||||
gpiod_set_value_cansleep(st->en_gpios[1], 0);
|
||||
gpiod_set_value_cansleep(st->en_gpios[0], 0);
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad7625_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad7625_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = pwm_set_waveform_might_sleep(st->cnv_pwm, &st->cnv_wf, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pwm_set_waveform_might_sleep(st->clk_gate_pwm,
|
||||
&st->clk_gate_wf, false);
|
||||
if (ret) {
|
||||
/* Disable cnv PWM if clk_gate setup failed */
|
||||
pwm_disable(st->cnv_pwm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7625_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad7625_state *st = iio_priv(indio_dev);
|
||||
|
||||
pwm_disable(st->clk_gate_pwm);
|
||||
pwm_disable(st->cnv_pwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_info ad7625_info = {
|
||||
.read_raw = ad7625_read_raw,
|
||||
.write_raw = ad7625_write_raw,
|
||||
};
|
||||
|
||||
static const struct iio_buffer_setup_ops ad7625_buffer_setup_ops = {
|
||||
.preenable = &ad7625_buffer_preenable,
|
||||
.postdisable = &ad7625_buffer_postdisable,
|
||||
};
|
||||
|
||||
static int devm_ad7625_pwm_get(struct device *dev,
|
||||
struct ad7625_state *st)
|
||||
{
|
||||
struct clk *ref_clk;
|
||||
u32 ref_clk_rate_hz;
|
||||
|
||||
st->cnv_pwm = devm_pwm_get(dev, "cnv");
|
||||
if (IS_ERR(st->cnv_pwm))
|
||||
return dev_err_probe(dev, PTR_ERR(st->cnv_pwm),
|
||||
"failed to get cnv pwm\n");
|
||||
|
||||
/* Preemptively disable the PWM in case it was enabled at boot */
|
||||
pwm_disable(st->cnv_pwm);
|
||||
|
||||
st->clk_gate_pwm = devm_pwm_get(dev, "clk_gate");
|
||||
if (IS_ERR(st->clk_gate_pwm))
|
||||
return dev_err_probe(dev, PTR_ERR(st->clk_gate_pwm),
|
||||
"failed to get clk_gate pwm\n");
|
||||
|
||||
/* Preemptively disable the PWM in case it was enabled at boot */
|
||||
pwm_disable(st->clk_gate_pwm);
|
||||
|
||||
ref_clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(ref_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(ref_clk),
|
||||
"failed to get ref_clk");
|
||||
|
||||
ref_clk_rate_hz = clk_get_rate(ref_clk);
|
||||
if (!ref_clk_rate_hz)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"failed to get ref_clk rate");
|
||||
|
||||
st->ref_clk_rate_hz = ref_clk_rate_hz;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are three required input voltages for each device, plus two
|
||||
* conditionally-optional (depending on part) REF and REFIN voltages
|
||||
* where their validity depends upon the EN pin configuration.
|
||||
*
|
||||
* Power-up info for the device says to bring up vio, then vdd2, then
|
||||
* vdd1, so list them in that order in the regulator_names array.
|
||||
*
|
||||
* The reference voltage source is determined like so:
|
||||
* - internal reference: neither REF or REFIN is connected (invalid for
|
||||
* AD796x)
|
||||
* - internal buffer, external reference: REF not connected, REFIN
|
||||
* connected
|
||||
* - external reference: REF connected, REFIN not connected
|
||||
*/
|
||||
static int devm_ad7625_regulator_setup(struct device *dev,
|
||||
struct ad7625_state *st)
|
||||
{
|
||||
static const char * const regulator_names[] = { "vio", "vdd2", "vdd1" };
|
||||
int ret, ref_mv;
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
|
||||
regulator_names);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, "ref");
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret, "failed to get REF voltage\n");
|
||||
|
||||
ref_mv = ret == -ENODEV ? 0 : ret / 1000;
|
||||
|
||||
ret = devm_regulator_get_enable_optional(dev, "refin");
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret, "failed to get REFIN voltage\n");
|
||||
|
||||
st->have_refin = ret != -ENODEV;
|
||||
|
||||
if (st->have_refin && !st->can_refin)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"REFIN provided in unsupported mode\n");
|
||||
|
||||
if (!st->info->has_internal_vref && !st->have_refin && !ref_mv)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Need either REFIN or REF");
|
||||
|
||||
if (st->have_refin && ref_mv)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"cannot have both REFIN and REF supplies\n");
|
||||
|
||||
if (ref_mv == 4096 && !st->can_ref_4v096)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"REF is 4.096V in unsupported mode\n");
|
||||
|
||||
if (ref_mv == 5000 && !st->can_ref_5v)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"REF is 5V in unsupported mode\n");
|
||||
|
||||
st->vref_mv = ref_mv ?: AD7625_INTERNAL_REF_MV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7625_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad7625_state *st;
|
||||
int ret;
|
||||
u32 default_sample_freq;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
st->info = device_get_match_data(dev);
|
||||
if (!st->info)
|
||||
return dev_err_probe(dev, -EINVAL, "no chip info\n");
|
||||
|
||||
if (device_property_read_bool(dev, "adi,no-dco"))
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"self-clocked mode not supported\n");
|
||||
|
||||
if (st->info->has_bandwidth_control)
|
||||
ret = ad7625_parse_mode(dev, st, 4);
|
||||
else
|
||||
ret = ad7625_parse_mode(dev, st, 2);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_ad7625_regulator_setup(dev, st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set the device mode based on detected EN configuration. */
|
||||
if (!st->info->has_bandwidth_control) {
|
||||
ad7625_set_en_gpios_for_vref(st, st->have_refin, st->vref_mv);
|
||||
} else {
|
||||
/*
|
||||
* If neither sampling mode is available, then report an error,
|
||||
* since the other modes are not useful defaults.
|
||||
*/
|
||||
if (st->can_wide_bandwidth) {
|
||||
ret = ad7960_set_mode(st, AD7960_MODE_WIDE_BANDWIDTH,
|
||||
st->have_refin, st->vref_mv);
|
||||
} else if (st->can_narrow_bandwidth) {
|
||||
ret = ad7960_set_mode(st, AD7960_MODE_NARROW_BANDWIDTH,
|
||||
st->have_refin, st->vref_mv);
|
||||
} else {
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"couldn't set device to wide or narrow bandwidth modes\n");
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"failed to set EN pins\n");
|
||||
}
|
||||
|
||||
ret = devm_ad7625_pwm_get(dev, st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->channels = &st->info->chan_spec;
|
||||
indio_dev->num_channels = 1;
|
||||
indio_dev->name = st->info->name;
|
||||
indio_dev->info = &ad7625_info;
|
||||
indio_dev->setup_ops = &ad7625_buffer_setup_ops;
|
||||
|
||||
st->back = devm_iio_backend_get(dev, NULL);
|
||||
if (IS_ERR(st->back))
|
||||
return dev_err_probe(dev, PTR_ERR(st->back),
|
||||
"failed to get IIO backend");
|
||||
|
||||
ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_backend_enable(dev, st->back);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Set the initial sampling frequency to the maximum, unless the
|
||||
* AD796x device is limited to narrow bandwidth by EN2 == 1, in
|
||||
* which case the sampling frequency should be limited to 2MSPS
|
||||
*/
|
||||
default_sample_freq = st->info->max_sample_freq_hz;
|
||||
if (st->info->has_bandwidth_control && !st->can_wide_bandwidth)
|
||||
default_sample_freq = AD7960_MAX_NBW_FREQ;
|
||||
|
||||
ret = ad7625_set_sampling_freq(st, default_sample_freq);
|
||||
if (ret)
|
||||
dev_err_probe(dev, ret,
|
||||
"failed to set valid sampling frequency\n");
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id ad7625_of_match[] = {
|
||||
{ .compatible = "adi,ad7625", .data = &ad7625_chip_info },
|
||||
{ .compatible = "adi,ad7626", .data = &ad7626_chip_info },
|
||||
{ .compatible = "adi,ad7960", .data = &ad7960_chip_info },
|
||||
{ .compatible = "adi,ad7961", .data = &ad7961_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7625_of_match);
|
||||
|
||||
static const struct platform_device_id ad7625_device_ids[] = {
|
||||
{ .name = "ad7625", .driver_data = (kernel_ulong_t)&ad7625_chip_info },
|
||||
{ .name = "ad7626", .driver_data = (kernel_ulong_t)&ad7626_chip_info },
|
||||
{ .name = "ad7960", .driver_data = (kernel_ulong_t)&ad7960_chip_info },
|
||||
{ .name = "ad7961", .driver_data = (kernel_ulong_t)&ad7961_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, ad7625_device_ids);
|
||||
|
||||
static struct platform_driver ad7625_driver = {
|
||||
.probe = ad7625_probe,
|
||||
.driver = {
|
||||
.name = "ad7625",
|
||||
.of_match_table = ad7625_of_match,
|
||||
},
|
||||
.id_table = ad7625_device_ids,
|
||||
};
|
||||
module_platform_driver(ad7625_driver);
|
||||
|
||||
MODULE_AUTHOR("Trevor Gamblin <tgamblin@baylibre.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD7625 ADC");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_IMPORT_NS(IIO_BACKEND);
|
||||
@@ -371,7 +371,7 @@ static const struct iio_info ad7791_no_filter_info = {
|
||||
};
|
||||
|
||||
static int ad7791_setup(struct ad7791_state *st,
|
||||
struct ad7791_platform_data *pdata)
|
||||
const struct ad7791_platform_data *pdata)
|
||||
{
|
||||
/* Set to poweron-reset default values */
|
||||
st->mode = AD7791_MODE_BUFFER;
|
||||
@@ -401,7 +401,7 @@ static void ad7791_reg_disable(void *reg)
|
||||
|
||||
static int ad7791_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad7791_platform_data *pdata = spi->dev.platform_data;
|
||||
const struct ad7791_platform_data *pdata = dev_get_platdata(&spi->dev);
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad7791_state *st;
|
||||
int ret;
|
||||
|
||||
@@ -770,7 +770,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
|
||||
|
||||
static int ad7793_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct ad7793_platform_data *pdata = spi->dev.platform_data;
|
||||
const struct ad7793_platform_data *pdata = dev_get_platdata(&spi->dev);
|
||||
struct ad7793_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret, vref_mv = 0;
|
||||
|
||||
@@ -41,7 +41,7 @@ enum ad7887_channels {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ad7887_chip_info - chip specifc information
|
||||
* struct ad7887_chip_info - chip specific information
|
||||
* @int_vref_mv: the internal reference voltage
|
||||
* @channels: channels specification
|
||||
* @num_channels: number of channels
|
||||
@@ -234,7 +234,7 @@ static void ad7887_reg_disable(void *data)
|
||||
|
||||
static int ad7887_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad7887_platform_data *pdata = spi->dev.platform_data;
|
||||
const struct ad7887_platform_data *pdata = dev_get_platdata(&spi->dev);
|
||||
struct ad7887_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
uint8_t mode;
|
||||
|
||||
@@ -80,7 +80,7 @@ struct ad7944_adc {
|
||||
};
|
||||
|
||||
/* quite time before CNV rising edge */
|
||||
#define T_QUIET_NS 20
|
||||
#define AD7944_T_QUIET_NS 20
|
||||
|
||||
static const struct ad7944_timing_spec ad7944_timing_spec = {
|
||||
.conv_ns = 420,
|
||||
@@ -150,7 +150,7 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc *
|
||||
* CS is tied to CNV and we need a low to high transition to start the
|
||||
* conversion, so place CNV low for t_QUIET to prepare for this.
|
||||
*/
|
||||
xfers[0].delay.value = T_QUIET_NS;
|
||||
xfers[0].delay.value = AD7944_T_QUIET_NS;
|
||||
xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
|
||||
/*
|
||||
|
||||
@@ -469,7 +469,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
|
||||
/*
|
||||
* Data array after transfer will look like (if status is appended):
|
||||
* data[] = { [0][sample][sample][sample][status] }
|
||||
* Keeping the first byte 0 shifts the status postion by 1 byte to the right.
|
||||
* Keeping the first byte 0 shifts the status position by 1 byte to the right.
|
||||
*/
|
||||
status_pos = reg_size + 1;
|
||||
|
||||
@@ -656,7 +656,7 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
|
||||
sigma_delta->spi = spi;
|
||||
sigma_delta->info = info;
|
||||
|
||||
/* If the field is unset in ad_sigma_delta_info, asume there can only be 1 slot. */
|
||||
/* If the field is unset in ad_sigma_delta_info, assume there can only be 1 slot. */
|
||||
if (!info->num_slots)
|
||||
sigma_delta->num_slots = 1;
|
||||
else
|
||||
|
||||
@@ -2625,7 +2625,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_match);
|
||||
|
||||
static struct platform_driver at91_adc_driver = {
|
||||
.probe = at91_adc_probe,
|
||||
.remove_new = at91_adc_remove,
|
||||
.remove = at91_adc_remove,
|
||||
.driver = {
|
||||
.name = "at91-sama5d2_adc",
|
||||
.of_match_table = at91_adc_dt_match,
|
||||
|
||||
@@ -1341,7 +1341,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
|
||||
|
||||
static struct platform_driver at91_adc_driver = {
|
||||
.probe = at91_adc_probe,
|
||||
.remove_new = at91_adc_remove,
|
||||
.remove = at91_adc_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = at91_adc_dt_ids,
|
||||
|
||||
@@ -155,52 +155,22 @@ enum axp813_adc_channel_v {
|
||||
AXP813_BATT_V,
|
||||
};
|
||||
|
||||
static struct iio_map axp20x_maps[] = {
|
||||
{
|
||||
.consumer_dev_name = "axp20x-usb-power-supply",
|
||||
.consumer_channel = "vbus_v",
|
||||
.adc_channel_label = "vbus_v",
|
||||
}, {
|
||||
.consumer_dev_name = "axp20x-usb-power-supply",
|
||||
.consumer_channel = "vbus_i",
|
||||
.adc_channel_label = "vbus_i",
|
||||
}, {
|
||||
.consumer_dev_name = "axp20x-ac-power-supply",
|
||||
.consumer_channel = "acin_v",
|
||||
.adc_channel_label = "acin_v",
|
||||
}, {
|
||||
.consumer_dev_name = "axp20x-ac-power-supply",
|
||||
.consumer_channel = "acin_i",
|
||||
.adc_channel_label = "acin_i",
|
||||
}, {
|
||||
.consumer_dev_name = "axp20x-battery-power-supply",
|
||||
.consumer_channel = "batt_v",
|
||||
.adc_channel_label = "batt_v",
|
||||
}, {
|
||||
.consumer_dev_name = "axp20x-battery-power-supply",
|
||||
.consumer_channel = "batt_chrg_i",
|
||||
.adc_channel_label = "batt_chrg_i",
|
||||
}, {
|
||||
.consumer_dev_name = "axp20x-battery-power-supply",
|
||||
.consumer_channel = "batt_dischrg_i",
|
||||
.adc_channel_label = "batt_dischrg_i",
|
||||
}, { /* sentinel */ }
|
||||
static const struct iio_map axp20x_maps[] = {
|
||||
IIO_MAP("vbus_v", "axp20x-usb-power-supply", "vbus_v"),
|
||||
IIO_MAP("vbus_i", "axp20x-usb-power-supply", "vbus_i"),
|
||||
IIO_MAP("acin_v", "axp20x-ac-power-supply", "acin_v"),
|
||||
IIO_MAP("acin_i", "axp20x-ac-power-supply", "acin_i"),
|
||||
IIO_MAP("batt_v", "axp20x-battery-power-supply", "batt_v"),
|
||||
IIO_MAP("batt_chrg_i", "axp20x-battery-power-supply", "batt_chrg_i"),
|
||||
IIO_MAP("batt_dischrg_i", "axp20x-battery-power-supply", "batt_dischrg_i"),
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct iio_map axp22x_maps[] = {
|
||||
{
|
||||
.consumer_dev_name = "axp20x-battery-power-supply",
|
||||
.consumer_channel = "batt_v",
|
||||
.adc_channel_label = "batt_v",
|
||||
}, {
|
||||
.consumer_dev_name = "axp20x-battery-power-supply",
|
||||
.consumer_channel = "batt_chrg_i",
|
||||
.adc_channel_label = "batt_chrg_i",
|
||||
}, {
|
||||
.consumer_dev_name = "axp20x-battery-power-supply",
|
||||
.consumer_channel = "batt_dischrg_i",
|
||||
.adc_channel_label = "batt_dischrg_i",
|
||||
}, { /* sentinel */ }
|
||||
static const struct iio_map axp22x_maps[] = {
|
||||
IIO_MAP("batt_v", "axp20x-battery-power-supply", "batt_v"),
|
||||
IIO_MAP("batt_chrg_i", "axp20x-battery-power-supply", "batt_chrg_i"),
|
||||
IIO_MAP("batt_dischrg_i", "axp20x-battery-power-supply", "batt_dischrg_i"),
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct iio_map axp717_maps[] = {
|
||||
@@ -1044,7 +1014,7 @@ struct axp_data {
|
||||
unsigned long adc_en2_mask;
|
||||
int (*adc_rate)(struct axp20x_adc_iio *info,
|
||||
int rate);
|
||||
struct iio_map *maps;
|
||||
const struct iio_map *maps;
|
||||
};
|
||||
|
||||
static const struct axp_data axp192_data = {
|
||||
@@ -1212,7 +1182,7 @@ static struct platform_driver axp20x_adc_driver = {
|
||||
},
|
||||
.id_table = axp20x_adc_id_match,
|
||||
.probe = axp20x_probe,
|
||||
.remove_new = axp20x_remove,
|
||||
.remove = axp20x_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(axp20x_adc_driver);
|
||||
|
||||
@@ -103,7 +103,7 @@ static const struct iio_chan_spec axp288_adc_channels[] = {
|
||||
};
|
||||
|
||||
/* for consumer drivers */
|
||||
static struct iio_map axp288_adc_default_maps[] = {
|
||||
static const struct iio_map axp288_adc_default_maps[] = {
|
||||
IIO_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
|
||||
IIO_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
|
||||
IIO_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
|
||||
|
||||
@@ -611,10 +611,10 @@ static const struct of_device_id iproc_adc_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, iproc_adc_of_match);
|
||||
|
||||
static struct platform_driver iproc_adc_driver = {
|
||||
.probe = iproc_adc_probe,
|
||||
.remove_new = iproc_adc_remove,
|
||||
.driver = {
|
||||
.name = "iproc-static-adc",
|
||||
.probe = iproc_adc_probe,
|
||||
.remove = iproc_adc_remove,
|
||||
.driver = {
|
||||
.name = "iproc-static-adc",
|
||||
.of_match_table = iproc_adc_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -291,27 +291,11 @@ static const struct iio_chan_spec da9150_gpadc_channels[] = {
|
||||
};
|
||||
|
||||
/* Default maps used by da9150-charger */
|
||||
static struct iio_map da9150_gpadc_default_maps[] = {
|
||||
{
|
||||
.consumer_dev_name = "da9150-charger",
|
||||
.consumer_channel = "CHAN_IBUS",
|
||||
.adc_channel_label = "IBUS",
|
||||
},
|
||||
{
|
||||
.consumer_dev_name = "da9150-charger",
|
||||
.consumer_channel = "CHAN_VBUS",
|
||||
.adc_channel_label = "VBUS",
|
||||
},
|
||||
{
|
||||
.consumer_dev_name = "da9150-charger",
|
||||
.consumer_channel = "CHAN_TJUNC",
|
||||
.adc_channel_label = "TJUNC_CORE",
|
||||
},
|
||||
{
|
||||
.consumer_dev_name = "da9150-charger",
|
||||
.consumer_channel = "CHAN_VBAT",
|
||||
.adc_channel_label = "VBAT",
|
||||
},
|
||||
static const struct iio_map da9150_gpadc_default_maps[] = {
|
||||
IIO_MAP("IBUS", "da9150-charger", "CHAN_IBUS"),
|
||||
IIO_MAP("VBUS", "da9150-charger", "CHAN_VBUS"),
|
||||
IIO_MAP("TJUNC_CORE", "da9150-charger", "CHAN_TJUNC"),
|
||||
IIO_MAP("VBAT", "da9150-charger", "CHAN_VBAT"),
|
||||
{},
|
||||
};
|
||||
|
||||
|
||||
@@ -700,7 +700,7 @@ static void dln2_adc_remove(struct platform_device *pdev)
|
||||
static struct platform_driver dln2_adc_driver = {
|
||||
.driver.name = DLN2_ADC_MOD_NAME,
|
||||
.probe = dln2_adc_probe,
|
||||
.remove_new = dln2_adc_remove,
|
||||
.remove = dln2_adc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(dln2_adc_driver);
|
||||
|
||||
@@ -238,7 +238,7 @@ static struct platform_driver ep93xx_adc_driver = {
|
||||
.of_match_table = ep93xx_adc_of_ids,
|
||||
},
|
||||
.probe = ep93xx_adc_probe,
|
||||
.remove_new = ep93xx_adc_remove,
|
||||
.remove = ep93xx_adc_remove,
|
||||
};
|
||||
module_platform_driver(ep93xx_adc_driver);
|
||||
|
||||
|
||||
@@ -1008,7 +1008,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops, exynos_adc_suspend,
|
||||
|
||||
static struct platform_driver exynos_adc_driver = {
|
||||
.probe = exynos_adc_probe,
|
||||
.remove_new = exynos_adc_remove,
|
||||
.remove = exynos_adc_remove,
|
||||
.driver = {
|
||||
.name = "exynos-adc",
|
||||
.of_match_table = exynos_adc_match,
|
||||
|
||||
228
drivers/iio/adc/gehc-pmc-adc.c
Normal file
228
drivers/iio/adc/gehc-pmc-adc.c
Normal file
@@ -0,0 +1,228 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* The GE HealthCare PMC ADC is a 16-Channel (Voltage and current), 16-Bit
|
||||
* ADC with an I2C Interface.
|
||||
*
|
||||
* Copyright (C) 2024, GE HealthCare
|
||||
*
|
||||
* Authors:
|
||||
* Herve Codina <herve.codina@bootlin.com>
|
||||
*/
|
||||
#include <dt-bindings/iio/adc/gehc,pmc-adc.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct pmc_adc {
|
||||
struct i2c_client *client;
|
||||
};
|
||||
|
||||
#define PMC_ADC_CMD_REQUEST_PROTOCOL_VERSION 0x01
|
||||
#define PMC_ADC_CMD_READ_VOLTAGE(_ch) (0x10 | (_ch))
|
||||
#define PMC_ADC_CMD_READ_CURRENT(_ch) (0x20 | (_ch))
|
||||
|
||||
#define PMC_ADC_VOLTAGE_CHANNEL(_ch, _ds_name) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = (_ch), \
|
||||
.address = PMC_ADC_CMD_READ_VOLTAGE(_ch), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
|
||||
.datasheet_name = (_ds_name), \
|
||||
}
|
||||
|
||||
#define PMC_ADC_CURRENT_CHANNEL(_ch, _ds_name) { \
|
||||
.type = IIO_CURRENT, \
|
||||
.indexed = 1, \
|
||||
.channel = (_ch), \
|
||||
.address = PMC_ADC_CMD_READ_CURRENT(_ch), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
|
||||
.datasheet_name = (_ds_name), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec pmc_adc_channels[] = {
|
||||
PMC_ADC_VOLTAGE_CHANNEL(0, "CH0_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(1, "CH1_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(2, "CH2_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(3, "CH3_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(4, "CH4_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(5, "CH5_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(6, "CH6_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(7, "CH7_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(8, "CH8_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(9, "CH9_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(10, "CH10_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(11, "CH11_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(12, "CH12_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(13, "CH13_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(14, "CH14_V"),
|
||||
PMC_ADC_VOLTAGE_CHANNEL(15, "CH15_V"),
|
||||
|
||||
PMC_ADC_CURRENT_CHANNEL(0, "CH0_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(1, "CH1_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(2, "CH2_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(3, "CH3_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(4, "CH4_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(5, "CH5_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(6, "CH6_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(7, "CH7_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(8, "CH8_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(9, "CH9_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(10, "CH10_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(11, "CH11_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(12, "CH12_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(13, "CH13_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(14, "CH14_I"),
|
||||
PMC_ADC_CURRENT_CHANNEL(15, "CH15_I"),
|
||||
};
|
||||
|
||||
static int pmc_adc_read_raw_ch(struct pmc_adc *pmc_adc, u8 cmd, int *val)
|
||||
{
|
||||
s32 ret;
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(pmc_adc->client, cmd);
|
||||
if (ret < 0) {
|
||||
dev_err(&pmc_adc->client->dev, "i2c read word failed (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*val = sign_extend32(ret, 15);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmc_adc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct pmc_adc *pmc_adc = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
/* Values are directly read in mV or mA */
|
||||
ret = pmc_adc_read_raw_ch(pmc_adc, chan->address, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int pmc_adc_fwnode_xlate(struct iio_dev *indio_dev,
|
||||
const struct fwnode_reference_args *iiospec)
|
||||
{
|
||||
enum iio_chan_type expected_type;
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* args[0]: Acquisition type (i.e. voltage or current)
|
||||
* args[1]: PMC ADC channel number
|
||||
*/
|
||||
if (iiospec->nargs != 2)
|
||||
return -EINVAL;
|
||||
|
||||
switch (iiospec->args[0]) {
|
||||
case GEHC_PMC_ADC_VOLTAGE:
|
||||
expected_type = IIO_VOLTAGE;
|
||||
break;
|
||||
case GEHC_PMC_ADC_CURRENT:
|
||||
expected_type = IIO_CURRENT;
|
||||
break;
|
||||
default:
|
||||
dev_err(&indio_dev->dev, "Invalid channel type %llu\n",
|
||||
iiospec->args[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < indio_dev->num_channels; i++)
|
||||
if (indio_dev->channels[i].type == expected_type &&
|
||||
indio_dev->channels[i].channel == iiospec->args[1])
|
||||
return i;
|
||||
|
||||
dev_err(&indio_dev->dev, "Invalid channel type %llu number %llu\n",
|
||||
iiospec->args[0], iiospec->args[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info pmc_adc_info = {
|
||||
.read_raw = pmc_adc_read_raw,
|
||||
.fwnode_xlate = pmc_adc_fwnode_xlate,
|
||||
};
|
||||
|
||||
static const char *const pmc_adc_regulator_names[] = {
|
||||
"vdd",
|
||||
"vdda",
|
||||
"vddio",
|
||||
"vref",
|
||||
};
|
||||
|
||||
static int pmc_adc_probe(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct pmc_adc *pmc_adc;
|
||||
struct clk *clk;
|
||||
s32 val;
|
||||
int ret;
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(&client->dev, ARRAY_SIZE(pmc_adc_regulator_names),
|
||||
pmc_adc_regulator_names);
|
||||
if (ret)
|
||||
return dev_err_probe(&client->dev, ret, "Failed to get regulators\n");
|
||||
|
||||
clk = devm_clk_get_optional_enabled(&client->dev, "osc");
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(clk), "Failed to get osc clock\n");
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*pmc_adc));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
pmc_adc = iio_priv(indio_dev);
|
||||
pmc_adc->client = client;
|
||||
|
||||
val = i2c_smbus_read_byte_data(pmc_adc->client, PMC_ADC_CMD_REQUEST_PROTOCOL_VERSION);
|
||||
if (val < 0)
|
||||
return dev_err_probe(&client->dev, val, "Failed to get protocol version\n");
|
||||
|
||||
if (val != 0x01)
|
||||
return dev_err_probe(&client->dev, -EINVAL,
|
||||
"Unsupported protocol version 0x%02x\n", val);
|
||||
|
||||
indio_dev->name = "pmc_adc";
|
||||
indio_dev->info = &pmc_adc_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = pmc_adc_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(pmc_adc_channels);
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id pmc_adc_of_match[] = {
|
||||
{ .compatible = "gehc,pmc-adc"},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pmc_adc_of_match);
|
||||
|
||||
static const struct i2c_device_id pmc_adc_id_table[] = {
|
||||
{ "pmc-adc" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pmc_adc_id_table);
|
||||
|
||||
static struct i2c_driver pmc_adc_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "pmc-adc",
|
||||
.of_match_table = pmc_adc_of_match,
|
||||
},
|
||||
.id_table = pmc_adc_id_table,
|
||||
.probe = pmc_adc_probe,
|
||||
};
|
||||
|
||||
module_i2c_driver(pmc_adc_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
|
||||
MODULE_DESCRIPTION("GE HealthCare PMC ADC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -487,7 +487,7 @@ MODULE_DEVICE_TABLE(of, imx8qxp_adc_match);
|
||||
|
||||
static struct platform_driver imx8qxp_adc_driver = {
|
||||
.probe = imx8qxp_adc_probe,
|
||||
.remove_new = imx8qxp_adc_remove,
|
||||
.remove = imx8qxp_adc_remove,
|
||||
.driver = {
|
||||
.name = ADC_DRIVER_NAME,
|
||||
.of_match_table = imx8qxp_adc_match,
|
||||
|
||||
@@ -470,7 +470,7 @@ MODULE_DEVICE_TABLE(of, imx93_adc_match);
|
||||
|
||||
static struct platform_driver imx93_adc_driver = {
|
||||
.probe = imx93_adc_probe,
|
||||
.remove_new = imx93_adc_remove,
|
||||
.remove = imx93_adc_remove,
|
||||
.driver = {
|
||||
.name = IMX93_ADC_DRIVER_NAME,
|
||||
.of_match_table = imx93_adc_match,
|
||||
|
||||
@@ -164,7 +164,7 @@ static const struct iio_chan_spec mrfld_adc_channels[] = {
|
||||
BCOVE_ADC_CHANNEL(IIO_TEMP, 8, "CH8", 0xC6),
|
||||
};
|
||||
|
||||
static struct iio_map iio_maps[] = {
|
||||
static const struct iio_map iio_maps[] = {
|
||||
IIO_MAP("CH0", "bcove-battery", "VBATRSLT"),
|
||||
IIO_MAP("CH1", "bcove-battery", "BATTID"),
|
||||
IIO_MAP("CH2", "bcove-battery", "IBATRSLT"),
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
struct lp8788_adc {
|
||||
struct lp8788 *lp;
|
||||
struct iio_map *map;
|
||||
const struct iio_map *map;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
@@ -149,17 +149,9 @@ static const struct iio_chan_spec lp8788_adc_channels[] = {
|
||||
};
|
||||
|
||||
/* default maps used by iio consumer (lp8788-charger driver) */
|
||||
static struct iio_map lp8788_default_iio_maps[] = {
|
||||
{
|
||||
.consumer_dev_name = "lp8788-charger",
|
||||
.consumer_channel = "lp8788_vbatt_5p0",
|
||||
.adc_channel_label = "VBATT_5P0",
|
||||
},
|
||||
{
|
||||
.consumer_dev_name = "lp8788-charger",
|
||||
.consumer_channel = "lp8788_adc1",
|
||||
.adc_channel_label = "ADC1",
|
||||
},
|
||||
static const struct iio_map lp8788_default_iio_maps[] = {
|
||||
IIO_MAP("VBATT_5P0", "lp8788-charger", "lp8788_vbatt_5p0"),
|
||||
IIO_MAP("ADC1", "lp8788-charger", "lp8788_adc1"),
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -168,7 +160,7 @@ static int lp8788_iio_map_register(struct device *dev,
|
||||
struct lp8788_platform_data *pdata,
|
||||
struct lp8788_adc *adc)
|
||||
{
|
||||
struct iio_map *map;
|
||||
const struct iio_map *map;
|
||||
int ret;
|
||||
|
||||
map = (!pdata || !pdata->adc_pdata) ?
|
||||
|
||||
@@ -168,6 +168,7 @@ static const struct iio_info ltc2497core_info = {
|
||||
int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
|
||||
struct iio_map *plat_data = dev_get_platdata(dev);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@@ -200,16 +201,10 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dev->platform_data) {
|
||||
struct iio_map *plat_data;
|
||||
|
||||
plat_data = (struct iio_map *)dev->platform_data;
|
||||
|
||||
ret = iio_map_array_register(indio_dev, plat_data);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
|
||||
goto err_regulator_disable;
|
||||
}
|
||||
ret = iio_map_array_register(indio_dev, plat_data);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
|
||||
goto err_regulator_disable;
|
||||
}
|
||||
|
||||
ddata->addr_prev = LTC2497_CONFIG_DEFAULT;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@@ -392,7 +393,7 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev,
|
||||
if (data < 0)
|
||||
return data;
|
||||
|
||||
data = (rxbuf[1] | rxbuf[0] << 8) &
|
||||
data = get_unaligned_be16(rxbuf) &
|
||||
((1 << st->chip_info->bits) - 1);
|
||||
} else {
|
||||
/* Get reading */
|
||||
|
||||
@@ -161,7 +161,7 @@ static int max34408_read_raw(struct iio_dev *indio_dev,
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
/*
|
||||
* calcluate current for 8bit ADC with Rsense
|
||||
* calculate current for 8bit ADC with Rsense
|
||||
* value.
|
||||
* 10 mV * 1000 / Rsense uOhm = max current
|
||||
* (max current * adc val * 1000) / (2^8 - 1) mA
|
||||
|
||||
@@ -1483,7 +1483,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops,
|
||||
|
||||
static struct platform_driver meson_sar_adc_driver = {
|
||||
.probe = meson_sar_adc_probe,
|
||||
.remove_new = meson_sar_adc_remove,
|
||||
.remove = meson_sar_adc_remove,
|
||||
.driver = {
|
||||
.name = "meson-saradc",
|
||||
.of_match_table = meson_sar_adc_of_match,
|
||||
|
||||
@@ -52,7 +52,7 @@ static struct iio_chan_spec mp2629_channels[] = {
|
||||
MP2629_ADC_CHAN(INPUT_CURRENT, IIO_CURRENT)
|
||||
};
|
||||
|
||||
static struct iio_map mp2629_adc_maps[] = {
|
||||
static const struct iio_map mp2629_adc_maps[] = {
|
||||
MP2629_MAP(BATT_VOLT, "batt-volt"),
|
||||
MP2629_MAP(SYSTEM_VOLT, "system-volt"),
|
||||
MP2629_MAP(INPUT_VOLT, "input-volt"),
|
||||
@@ -195,7 +195,7 @@ static struct platform_driver mp2629_adc_driver = {
|
||||
.of_match_table = mp2629_adc_of_match,
|
||||
},
|
||||
.probe = mp2629_adc_probe,
|
||||
.remove_new = mp2629_adc_remove,
|
||||
.remove = mp2629_adc_remove,
|
||||
};
|
||||
module_platform_driver(mp2629_adc_driver);
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ static int mt6360_adc_read_channel(struct mt6360_adc_data *mad, int channel, int
|
||||
usleep_range(ADC_LOOP_TIME_US / 2, ADC_LOOP_TIME_US);
|
||||
}
|
||||
|
||||
*val = rpt[1] << 8 | rpt[2];
|
||||
*val = get_unaligned_be16(&rpt[1]);
|
||||
ret = IIO_VAL_INT;
|
||||
|
||||
out_adc_conv:
|
||||
|
||||
@@ -819,10 +819,10 @@ static void mxs_lradc_adc_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver mxs_lradc_adc_driver = {
|
||||
.driver = {
|
||||
.name = "mxs-lradc-adc",
|
||||
.name = "mxs-lradc-adc",
|
||||
},
|
||||
.probe = mxs_lradc_adc_probe,
|
||||
.remove_new = mxs_lradc_adc_remove,
|
||||
.probe = mxs_lradc_adc_probe,
|
||||
.remove = mxs_lradc_adc_remove,
|
||||
};
|
||||
module_platform_driver(mxs_lradc_adc_driver);
|
||||
|
||||
|
||||
@@ -337,7 +337,7 @@ static void npcm_adc_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver npcm_adc_driver = {
|
||||
.probe = npcm_adc_probe,
|
||||
.remove_new = npcm_adc_remove,
|
||||
.remove = npcm_adc_remove,
|
||||
.driver = {
|
||||
.name = "npcm_adc",
|
||||
.of_match_table = npcm_adc_match,
|
||||
|
||||
@@ -241,7 +241,7 @@ static inline void pac1921_calc_scale(int dividend, int divisor, int *val,
|
||||
s64 tmp;
|
||||
|
||||
tmp = div_s64(dividend * (s64)NANO, divisor);
|
||||
*val = (int)div_s64_rem(tmp, NANO, val2);
|
||||
*val = div_s64_rem(tmp, NANO, val2);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -260,7 +260,7 @@ static void pac1921_calc_current_scales(struct pac1921_priv *priv)
|
||||
int max = (PAC1921_MAX_VSENSE_MV * MICRO) >> i;
|
||||
int vsense_lsb = DIV_ROUND_CLOSEST(max, PAC1921_RES_RESOLUTION);
|
||||
|
||||
pac1921_calc_scale(vsense_lsb, (int)priv->rshunt_uohm,
|
||||
pac1921_calc_scale(vsense_lsb, priv->rshunt_uohm,
|
||||
&priv->current_scales[i][0],
|
||||
&priv->current_scales[i][1]);
|
||||
}
|
||||
@@ -314,7 +314,7 @@ static int pac1921_check_push_overflow(struct iio_dev *indio_dev, s64 timestamp)
|
||||
timestamp);
|
||||
}
|
||||
|
||||
priv->prev_ovf_flags = (u8)flags;
|
||||
priv->prev_ovf_flags = flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -329,8 +329,7 @@ static int pac1921_check_push_overflow(struct iio_dev *indio_dev, s64 timestamp)
|
||||
static int pac1921_read_res(struct pac1921_priv *priv, unsigned long reg,
|
||||
u16 *val)
|
||||
{
|
||||
int ret = regmap_bulk_read(priv->regmap, (unsigned int)reg, val,
|
||||
sizeof(*val));
|
||||
int ret = regmap_bulk_read(priv->regmap, reg, val, sizeof(*val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -366,7 +365,7 @@ static int pac1921_read_raw(struct iio_dev *indio_dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = (int)res_val;
|
||||
*val = res_val;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
@@ -400,10 +399,10 @@ static int pac1921_read_raw(struct iio_dev *indio_dev,
|
||||
s64 tmp = curr_scale[0] * (s64)NANO + curr_scale[1];
|
||||
|
||||
/* Multiply by max_vbus (V) / dv_gain */
|
||||
tmp *= PAC1921_MAX_VBUS_V >> (int)priv->dv_gain;
|
||||
tmp *= PAC1921_MAX_VBUS_V >> priv->dv_gain;
|
||||
|
||||
/* Convert back to INT_PLUS_NANO */
|
||||
*val = (int)div_s64_rem(tmp, NANO, val2);
|
||||
*val = div_s64_rem(tmp, NANO, val2);
|
||||
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
}
|
||||
@@ -426,7 +425,7 @@ static int pac1921_read_raw(struct iio_dev *indio_dev,
|
||||
* 1/(integr_period_usecs/MICRO) = MICRO/integr_period_usecs
|
||||
*/
|
||||
*val = MICRO;
|
||||
*val2 = (int)priv->integr_period_usecs;
|
||||
*val2 = priv->integr_period_usecs;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
|
||||
default:
|
||||
@@ -503,7 +502,7 @@ static int pac1921_lookup_scale(const int (*const scales_tbl)[2], size_t size,
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
if (scales_tbl[i][0] == scale_val &&
|
||||
scales_tbl[i][1] == scale_val2)
|
||||
return (int)i;
|
||||
return i;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -553,7 +552,7 @@ static int pac1921_update_gain_from_scale(struct pac1921_priv *priv,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return pac1921_update_gain(priv, &priv->dv_gain, (u8)ret,
|
||||
return pac1921_update_gain(priv, &priv->dv_gain, ret,
|
||||
PAC1921_GAIN_DV_GAIN_MASK);
|
||||
case PAC1921_CHAN_VSENSE:
|
||||
ret = pac1921_lookup_scale(pac1921_vsense_scales,
|
||||
@@ -562,7 +561,7 @@ static int pac1921_update_gain_from_scale(struct pac1921_priv *priv,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return pac1921_update_gain(priv, &priv->di_gain, (u8)ret,
|
||||
return pac1921_update_gain(priv, &priv->di_gain, ret,
|
||||
PAC1921_GAIN_DI_GAIN_MASK);
|
||||
case PAC1921_CHAN_CURRENT:
|
||||
ret = pac1921_lookup_scale(priv->current_scales,
|
||||
@@ -571,7 +570,7 @@ static int pac1921_update_gain_from_scale(struct pac1921_priv *priv,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return pac1921_update_gain(priv, &priv->di_gain, (u8)ret,
|
||||
return pac1921_update_gain(priv, &priv->di_gain, ret,
|
||||
PAC1921_GAIN_DI_GAIN_MASK);
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -586,7 +585,7 @@ static int pac1921_lookup_int_num_samples(int num_samples)
|
||||
{
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(pac1921_int_num_samples); i++)
|
||||
if (pac1921_int_num_samples[i] == num_samples)
|
||||
return (int)i;
|
||||
return i;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -607,7 +606,7 @@ static int pac1921_update_int_num_samples(struct pac1921_priv *priv,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
n_samples = (u8)ret;
|
||||
n_samples = ret;
|
||||
|
||||
if (priv->n_samples == n_samples)
|
||||
return 0;
|
||||
@@ -770,7 +769,7 @@ static ssize_t pac1921_read_shunt_resistor(struct iio_dev *indio_dev,
|
||||
|
||||
guard(mutex)(&priv->lock);
|
||||
|
||||
vals[0] = (int)priv->rshunt_uohm;
|
||||
vals[0] = priv->rshunt_uohm;
|
||||
vals[1] = MICRO;
|
||||
|
||||
return iio_format_value(buf, IIO_VAL_FRACTIONAL, 1, vals);
|
||||
@@ -793,13 +792,13 @@ static ssize_t pac1921_write_shunt_resistor(struct iio_dev *indio_dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rshunt_uohm = (u32)val * MICRO + (u32)val_fract;
|
||||
rshunt_uohm = val * MICRO + val_fract;
|
||||
if (rshunt_uohm == 0 || rshunt_uohm > INT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
guard(mutex)(&priv->lock);
|
||||
|
||||
priv->rshunt_uohm = (u32)rshunt_uohm;
|
||||
priv->rshunt_uohm = rshunt_uohm;
|
||||
|
||||
pac1921_calc_current_scales(priv);
|
||||
|
||||
@@ -1077,7 +1076,7 @@ static int pac1921_init(struct pac1921_priv *priv)
|
||||
/*
|
||||
* Init control register:
|
||||
* - VPower free run integration mode
|
||||
* - OUT pin full scale range: 3V (HW detault)
|
||||
* - OUT pin full scale range: 3V (HW default)
|
||||
* - no timeout, no sleep, no sleep override, no recalc (HW defaults)
|
||||
*/
|
||||
val = FIELD_PREP(PAC1921_CONTROL_MXSL_MASK,
|
||||
@@ -1168,7 +1167,7 @@ static int pac1921_probe(struct i2c_client *client)
|
||||
|
||||
priv->regmap = devm_regmap_init_i2c(client, &pac1921_regmap_config);
|
||||
if (IS_ERR(priv->regmap))
|
||||
return dev_err_probe(dev, (int)PTR_ERR(priv->regmap),
|
||||
return dev_err_probe(dev, PTR_ERR(priv->regmap),
|
||||
"Cannot initialize register map\n");
|
||||
|
||||
devm_mutex_init(dev, &priv->lock);
|
||||
@@ -1191,7 +1190,7 @@ static int pac1921_probe(struct i2c_client *client)
|
||||
|
||||
priv->vdd = devm_regulator_get(dev, "vdd");
|
||||
if (IS_ERR(priv->vdd))
|
||||
return dev_err_probe(dev, (int)PTR_ERR(priv->vdd),
|
||||
return dev_err_probe(dev, PTR_ERR(priv->vdd),
|
||||
"Cannot get vdd regulator\n");
|
||||
|
||||
ret = regulator_enable(priv->vdd);
|
||||
|
||||
@@ -456,7 +456,7 @@ static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc,
|
||||
* raw high threshold = (ideal threshold + INL) * gain error + offset error
|
||||
*
|
||||
* The gain error include both gain error, as specified in the datasheet, and
|
||||
* the gain error drift. These paramenters vary depending on device and whether
|
||||
* the gain error drift. These parameters vary depending on device and whether
|
||||
* the channel is calibrated (trimmed) or not.
|
||||
*/
|
||||
static int palmas_gpadc_threshold_with_tolerance(int val, const int INL,
|
||||
|
||||
@@ -821,7 +821,6 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev,
|
||||
|
||||
static int pm8xxx_xoadc_parse_channels(struct pm8xxx_xoadc *adc)
|
||||
{
|
||||
struct fwnode_handle *child;
|
||||
struct pm8xxx_chan_info *ch;
|
||||
int ret;
|
||||
int i;
|
||||
@@ -844,16 +843,15 @@ static int pm8xxx_xoadc_parse_channels(struct pm8xxx_xoadc *adc)
|
||||
return -ENOMEM;
|
||||
|
||||
i = 0;
|
||||
device_for_each_child_node(adc->dev, child) {
|
||||
device_for_each_child_node_scoped(adc->dev, child) {
|
||||
ch = &adc->chans[i];
|
||||
ret = pm8xxx_xoadc_parse_channel(adc->dev, child,
|
||||
adc->variant->channels,
|
||||
&adc->iio_chans[i],
|
||||
ch);
|
||||
if (ret) {
|
||||
fwnode_handle_put(child);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -1016,7 +1014,7 @@ static struct platform_driver pm8xxx_xoadc_driver = {
|
||||
.of_match_table = pm8xxx_xoadc_id_table,
|
||||
},
|
||||
.probe = pm8xxx_xoadc_probe,
|
||||
.remove_new = pm8xxx_xoadc_remove,
|
||||
.remove = pm8xxx_xoadc_remove,
|
||||
};
|
||||
module_platform_driver(pm8xxx_xoadc_driver);
|
||||
|
||||
|
||||
@@ -830,7 +830,7 @@ static int adc5_get_fw_data(struct adc5_chip *adc)
|
||||
|
||||
adc->nchannels = device_get_child_node_count(adc->dev);
|
||||
if (!adc->nchannels)
|
||||
return -EINVAL;
|
||||
return dev_err_probe(adc->dev, -EINVAL, "no channels defined\n");
|
||||
|
||||
adc->iio_chans = devm_kcalloc(adc->dev, adc->nchannels,
|
||||
sizeof(*adc->iio_chans), GFP_KERNEL);
|
||||
@@ -903,7 +903,7 @@ static int adc5_probe(struct platform_device *pdev)
|
||||
|
||||
ret = adc5_get_fw_data(adc);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "adc get dt data failed\n");
|
||||
return ret;
|
||||
|
||||
irq_eoc = platform_get_irq(pdev, 0);
|
||||
if (irq_eoc < 0) {
|
||||
|
||||
@@ -754,7 +754,6 @@ static int vadc_get_fw_data(struct vadc_priv *vadc)
|
||||
const struct vadc_channels *vadc_chan;
|
||||
struct iio_chan_spec *iio_chan;
|
||||
struct vadc_channel_prop prop;
|
||||
struct fwnode_handle *child;
|
||||
unsigned int index = 0;
|
||||
int ret;
|
||||
|
||||
@@ -774,12 +773,10 @@ static int vadc_get_fw_data(struct vadc_priv *vadc)
|
||||
|
||||
iio_chan = vadc->iio_chans;
|
||||
|
||||
device_for_each_child_node(vadc->dev, child) {
|
||||
device_for_each_child_node_scoped(vadc->dev, child) {
|
||||
ret = vadc_get_fw_channel_data(vadc->dev, &prop, child);
|
||||
if (ret) {
|
||||
fwnode_handle_put(child);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
prop.scale_fn_type = vadc_chans[prop.channel].scale_fn_type;
|
||||
vadc->chan_props[index] = prop;
|
||||
|
||||
@@ -592,7 +592,7 @@ static const struct dev_pm_ops rcar_gyroadc_pm_ops = {
|
||||
|
||||
static struct platform_driver rcar_gyroadc_driver = {
|
||||
.probe = rcar_gyroadc_probe,
|
||||
.remove_new = rcar_gyroadc_remove,
|
||||
.remove = rcar_gyroadc_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = rcar_gyroadc_match,
|
||||
|
||||
@@ -185,7 +185,7 @@ static const struct iio_chan_spec rn5t618_adc_iio_channels[] = {
|
||||
RN5T618_ADC_CHANNEL(AIN0, IIO_VOLTAGE, "AIN0")
|
||||
};
|
||||
|
||||
static struct iio_map rn5t618_maps[] = {
|
||||
static const struct iio_map rn5t618_maps[] = {
|
||||
IIO_MAP("VADP", "rn5t618-power", "vadp"),
|
||||
IIO_MAP("VUSB", "rn5t618-power", "vusb"),
|
||||
{ /* sentinel */ }
|
||||
|
||||
@@ -906,7 +906,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
|
||||
|
||||
static struct platform_driver stm32_adc_driver = {
|
||||
.probe = stm32_adc_probe,
|
||||
.remove_new = stm32_adc_remove,
|
||||
.remove = stm32_adc_remove,
|
||||
.driver = {
|
||||
.name = "stm32-adc-core",
|
||||
.of_match_table = stm32_adc_of_match,
|
||||
|
||||
@@ -2644,7 +2644,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
|
||||
|
||||
static struct platform_driver stm32_adc_driver = {
|
||||
.probe = stm32_adc_probe,
|
||||
.remove_new = stm32_adc_remove,
|
||||
.remove = stm32_adc_remove,
|
||||
.driver = {
|
||||
.name = "stm32-adc",
|
||||
.of_match_table = stm32_adc_of_match,
|
||||
|
||||
@@ -1890,7 +1890,7 @@ static struct platform_driver stm32_dfsdm_adc_driver = {
|
||||
.pm = pm_sleep_ptr(&stm32_dfsdm_adc_pm_ops),
|
||||
},
|
||||
.probe = stm32_dfsdm_adc_probe,
|
||||
.remove_new = stm32_dfsdm_adc_remove,
|
||||
.remove = stm32_dfsdm_adc_remove,
|
||||
};
|
||||
module_platform_driver(stm32_dfsdm_adc_driver);
|
||||
|
||||
|
||||
@@ -506,7 +506,7 @@ static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = {
|
||||
|
||||
static struct platform_driver stm32_dfsdm_driver = {
|
||||
.probe = stm32_dfsdm_probe,
|
||||
.remove_new = stm32_dfsdm_core_remove,
|
||||
.remove = stm32_dfsdm_core_remove,
|
||||
.driver = {
|
||||
.name = "stm32-dfsdm",
|
||||
.of_match_table = stm32_dfsdm_of_match,
|
||||
|
||||
@@ -155,7 +155,6 @@ static int sun20i_gpadc_alloc_channels(struct iio_dev *indio_dev,
|
||||
unsigned int channel;
|
||||
int num_channels, i, ret;
|
||||
struct iio_chan_spec *channels;
|
||||
struct fwnode_handle *node;
|
||||
|
||||
num_channels = device_get_child_node_count(dev);
|
||||
if (num_channels == 0)
|
||||
@@ -167,12 +166,10 @@ static int sun20i_gpadc_alloc_channels(struct iio_dev *indio_dev,
|
||||
return -ENOMEM;
|
||||
|
||||
i = 0;
|
||||
device_for_each_child_node(dev, node) {
|
||||
device_for_each_child_node_scoped(dev, node) {
|
||||
ret = fwnode_property_read_u32(node, "reg", &channel);
|
||||
if (ret) {
|
||||
fwnode_handle_put(node);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "invalid channel number\n");
|
||||
}
|
||||
|
||||
channels[i].type = IIO_VOLTAGE;
|
||||
channels[i].indexed = 1;
|
||||
|
||||
@@ -114,11 +114,8 @@ struct sun4i_gpadc_iio {
|
||||
.datasheet_name = _name, \
|
||||
}
|
||||
|
||||
static struct iio_map sun4i_gpadc_hwmon_maps[] = {
|
||||
{
|
||||
.adc_channel_label = "temp_adc",
|
||||
.consumer_dev_name = "iio_hwmon.0",
|
||||
},
|
||||
static const struct iio_map sun4i_gpadc_hwmon_maps[] = {
|
||||
IIO_MAP("temp_adc", "iio_hwmon.0", NULL),
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
@@ -700,7 +697,7 @@ static struct platform_driver sun4i_gpadc_driver = {
|
||||
},
|
||||
.id_table = sun4i_gpadc_id,
|
||||
.probe = sun4i_gpadc_probe,
|
||||
.remove_new = sun4i_gpadc_remove,
|
||||
.remove = sun4i_gpadc_remove,
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_id);
|
||||
|
||||
|
||||
@@ -1032,8 +1032,7 @@ static int ads1015_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
if (client->irq && chip->has_comparator) {
|
||||
unsigned long irq_trig =
|
||||
irqd_get_trigger_type(irq_get_irq_data(client->irq));
|
||||
unsigned long irq_trig = irq_get_trigger_type(client->irq);
|
||||
unsigned int cfg_comp_mask = ADS1015_CFG_COMP_QUE_MASK |
|
||||
ADS1015_CFG_COMP_LAT_MASK | ADS1015_CFG_COMP_POL_MASK;
|
||||
unsigned int cfg_comp =
|
||||
|
||||
@@ -804,7 +804,7 @@ static const struct of_device_id __maybe_unused ads1119_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, ads1119_of_match);
|
||||
|
||||
static const struct i2c_device_id ads1119_id[] = {
|
||||
{ "ads1119", 0 },
|
||||
{ "ads1119" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ads1119_id);
|
||||
|
||||
@@ -294,7 +294,7 @@ static int ads1298_get_scale(struct ads1298_private *priv,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Refererence in millivolts */
|
||||
/* Reference in millivolts */
|
||||
*val = regval & ADS1298_MASK_CONFIG3_VREF_4V ? 4000 : 2400;
|
||||
}
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
|
||||
/*
|
||||
* We check the complete FIFO. We programmed just one entry but in case
|
||||
* something went wrong we left empty handed (-EAGAIN previously) and
|
||||
* then the value apeared somehow in the FIFO we would have two entries.
|
||||
* then the value appeared somehow in the FIFO we would have two entries.
|
||||
* Therefore we read every item and keep only the latest version of the
|
||||
* requested channel.
|
||||
*/
|
||||
@@ -740,12 +740,12 @@ MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
|
||||
|
||||
static struct platform_driver tiadc_driver = {
|
||||
.driver = {
|
||||
.name = "TI-am335x-adc",
|
||||
.pm = pm_sleep_ptr(&tiadc_pm_ops),
|
||||
.name = "TI-am335x-adc",
|
||||
.pm = pm_sleep_ptr(&tiadc_pm_ops),
|
||||
.of_match_table = ti_adc_dt_ids,
|
||||
},
|
||||
.probe = tiadc_probe,
|
||||
.remove_new = tiadc_remove,
|
||||
.probe = tiadc_probe,
|
||||
.remove = tiadc_remove,
|
||||
};
|
||||
module_platform_driver(tiadc_driver);
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ static const struct s16_fract twl4030_divider_ratios[16] = {
|
||||
{15, 100}, /* CHANNEL 11 */
|
||||
{1, 4}, /* CHANNEL 12 */
|
||||
{1, 1}, /* CHANNEL 13 Reserved channels */
|
||||
{1, 1}, /* CHANNEL 14 Reseved channels */
|
||||
{1, 1}, /* CHANNEL 14 Reserved channels */
|
||||
{5, 11}, /* CHANNEL 15 */
|
||||
};
|
||||
|
||||
@@ -914,7 +914,7 @@ MODULE_DEVICE_TABLE(of, twl_madc_of_match);
|
||||
|
||||
static struct platform_driver twl4030_madc_driver = {
|
||||
.probe = twl4030_madc_probe,
|
||||
.remove_new = twl4030_madc_remove,
|
||||
.remove = twl4030_madc_remove,
|
||||
.driver = {
|
||||
.name = "twl4030_madc",
|
||||
.of_match_table = twl_madc_of_match,
|
||||
|
||||
@@ -1003,7 +1003,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend,
|
||||
|
||||
static struct platform_driver twl6030_gpadc_driver = {
|
||||
.probe = twl6030_gpadc_probe,
|
||||
.remove_new = twl6030_gpadc_remove,
|
||||
.remove = twl6030_gpadc_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.pm = pm_sleep_ptr(&twl6030_gpadc_pm_ops),
|
||||
|
||||
@@ -972,7 +972,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend,
|
||||
|
||||
static struct platform_driver vf610_adc_driver = {
|
||||
.probe = vf610_adc_probe,
|
||||
.remove_new = vf610_adc_remove,
|
||||
.remove = vf610_adc_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = vf610_adc_match,
|
||||
|
||||
@@ -220,7 +220,7 @@ int xadc_write_event_value(struct iio_dev *indio_dev,
|
||||
/*
|
||||
* Since we store the hysteresis as relative (to the threshold)
|
||||
* value, but the hardware expects an absolute value we need to
|
||||
* recalcualte this value whenever the hysteresis or the
|
||||
* recalculate this value whenever the hysteresis or the
|
||||
* threshold changes.
|
||||
*/
|
||||
if (xadc->threshold[offset] < xadc->temp_hysteresis)
|
||||
|
||||
@@ -191,7 +191,7 @@ enum ad74115_gpio_mode {
|
||||
};
|
||||
|
||||
struct ad74115_channels {
|
||||
struct iio_chan_spec *channels;
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned int num_channels;
|
||||
};
|
||||
|
||||
@@ -1295,46 +1295,46 @@ static const struct iio_info ad74115_info = {
|
||||
_AD74115_ADC_CHANNEL(_type, index, BIT(IIO_CHAN_INFO_SCALE) \
|
||||
| BIT(IIO_CHAN_INFO_OFFSET))
|
||||
|
||||
static struct iio_chan_spec ad74115_voltage_input_channels[] = {
|
||||
static const struct iio_chan_spec ad74115_voltage_input_channels[] = {
|
||||
AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
|
||||
AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74115_voltage_output_channels[] = {
|
||||
static const struct iio_chan_spec ad74115_voltage_output_channels[] = {
|
||||
AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_MAIN),
|
||||
AD74115_ADC_CHANNEL(IIO_CURRENT, AD74115_ADC_CH_CONV1),
|
||||
AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74115_current_input_channels[] = {
|
||||
static const struct iio_chan_spec ad74115_current_input_channels[] = {
|
||||
AD74115_ADC_CHANNEL(IIO_CURRENT, AD74115_ADC_CH_CONV1),
|
||||
AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74115_current_output_channels[] = {
|
||||
static const struct iio_chan_spec ad74115_current_output_channels[] = {
|
||||
AD74115_DAC_CHANNEL(IIO_CURRENT, AD74115_DAC_CH_MAIN),
|
||||
AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
|
||||
AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74115_2_wire_resistance_input_channels[] = {
|
||||
static const struct iio_chan_spec ad74115_2_wire_resistance_input_channels[] = {
|
||||
_AD74115_ADC_CHANNEL(IIO_RESISTANCE, AD74115_ADC_CH_CONV1,
|
||||
BIT(IIO_CHAN_INFO_PROCESSED)),
|
||||
AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74115_3_4_wire_resistance_input_channels[] = {
|
||||
static const struct iio_chan_spec ad74115_3_4_wire_resistance_input_channels[] = {
|
||||
AD74115_ADC_CHANNEL(IIO_RESISTANCE, AD74115_ADC_CH_CONV1),
|
||||
AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74115_digital_input_logic_channels[] = {
|
||||
static const struct iio_chan_spec ad74115_digital_input_logic_channels[] = {
|
||||
AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_COMPARATOR),
|
||||
AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
|
||||
AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74115_digital_input_loop_channels[] = {
|
||||
static const struct iio_chan_spec ad74115_digital_input_loop_channels[] = {
|
||||
AD74115_DAC_CHANNEL(IIO_CURRENT, AD74115_DAC_CH_MAIN),
|
||||
AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_COMPARATOR),
|
||||
AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
|
||||
|
||||
@@ -45,8 +45,8 @@ struct ad74413r_channel_config {
|
||||
};
|
||||
|
||||
struct ad74413r_channels {
|
||||
struct iio_chan_spec *channels;
|
||||
unsigned int num_channels;
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned int num_channels;
|
||||
};
|
||||
|
||||
struct ad74413r_state {
|
||||
@@ -1138,34 +1138,34 @@ static const struct iio_info ad74413r_info = {
|
||||
AD74413R_ADC_CHANNEL(IIO_CURRENT, BIT(IIO_CHAN_INFO_SCALE) \
|
||||
| BIT(IIO_CHAN_INFO_OFFSET))
|
||||
|
||||
static struct iio_chan_spec ad74413r_voltage_output_channels[] = {
|
||||
static const struct iio_chan_spec ad74413r_voltage_output_channels[] = {
|
||||
AD74413R_DAC_CHANNEL(IIO_VOLTAGE, BIT(IIO_CHAN_INFO_SCALE)),
|
||||
AD74413R_ADC_CURRENT_CHANNEL,
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74413r_current_output_channels[] = {
|
||||
static const struct iio_chan_spec ad74413r_current_output_channels[] = {
|
||||
AD74413R_DAC_CHANNEL(IIO_CURRENT, BIT(IIO_CHAN_INFO_SCALE)),
|
||||
AD74413R_ADC_VOLTAGE_CHANNEL,
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74413r_voltage_input_channels[] = {
|
||||
static const struct iio_chan_spec ad74413r_voltage_input_channels[] = {
|
||||
AD74413R_ADC_VOLTAGE_CHANNEL,
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74413r_current_input_channels[] = {
|
||||
static const struct iio_chan_spec ad74413r_current_input_channels[] = {
|
||||
AD74413R_ADC_CURRENT_CHANNEL,
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74413r_current_input_loop_channels[] = {
|
||||
static const struct iio_chan_spec ad74413r_current_input_loop_channels[] = {
|
||||
AD74413R_DAC_CHANNEL(IIO_CURRENT, BIT(IIO_CHAN_INFO_SCALE)),
|
||||
AD74413R_ADC_CURRENT_CHANNEL,
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74413r_resistance_input_channels[] = {
|
||||
static const struct iio_chan_spec ad74413r_resistance_input_channels[] = {
|
||||
AD74413R_ADC_CHANNEL(IIO_RESISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)),
|
||||
};
|
||||
|
||||
static struct iio_chan_spec ad74413r_digital_input_channels[] = {
|
||||
static const struct iio_chan_spec ad74413r_digital_input_channels[] = {
|
||||
AD74413R_ADC_VOLTAGE_CHANNEL,
|
||||
};
|
||||
|
||||
@@ -1270,7 +1270,8 @@ static int ad74413r_setup_channels(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad74413r_state *st = iio_priv(indio_dev);
|
||||
struct ad74413r_channel_config *config;
|
||||
struct iio_chan_spec *channels, *chans;
|
||||
const struct iio_chan_spec *chans;
|
||||
struct iio_chan_spec *channels;
|
||||
unsigned int i, num_chans, chan_i;
|
||||
int ret;
|
||||
|
||||
|
||||
@@ -134,11 +134,11 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
|
||||
iio_trigger_set_drvdata(sdata->trig, indio_dev);
|
||||
sdata->trig->ops = trigger_ops;
|
||||
|
||||
irq_trig = irqd_get_trigger_type(irq_get_irq_data(sdata->irq));
|
||||
/*
|
||||
* If the IRQ is triggered on falling edge, we need to mark the
|
||||
* interrupt as active low, if the hardware supports this.
|
||||
*/
|
||||
irq_trig = irq_get_trigger_type(sdata->irq);
|
||||
switch(irq_trig) {
|
||||
case IRQF_TRIGGER_FALLING:
|
||||
case IRQF_TRIGGER_LOW:
|
||||
|
||||
@@ -301,6 +301,19 @@ config AD7303
|
||||
To compile this driver as module choose M here: the module will be called
|
||||
ad7303.
|
||||
|
||||
config AD8460
|
||||
tristate "Analog Devices AD8460 DAC driver"
|
||||
depends on SPI
|
||||
select REGMAP_SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_BUFFER_DMAENGINE
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD8460 Digital to
|
||||
Analog Converters (DAC).
|
||||
|
||||
To compile this driver as a module choose M here: the module will be called
|
||||
ad8460.
|
||||
|
||||
config AD8801
|
||||
tristate "Analog Devices AD8801/AD8803 DAC driver"
|
||||
depends on SPI_MASTER
|
||||
|
||||
@@ -28,6 +28,7 @@ obj-$(CONFIG_AD5686_SPI) += ad5686-spi.o
|
||||
obj-$(CONFIG_AD5696_I2C) += ad5696-i2c.o
|
||||
obj-$(CONFIG_AD7293) += ad7293.o
|
||||
obj-$(CONFIG_AD7303) += ad7303.o
|
||||
obj-$(CONFIG_AD8460) += ad8460.o
|
||||
obj-$(CONFIG_AD8801) += ad8801.o
|
||||
obj-$(CONFIG_AD9739A) += ad9739a.o
|
||||
obj-$(CONFIG_ADI_AXI_DAC) += adi-axi-dac.o
|
||||
|
||||
@@ -270,7 +270,7 @@ static const struct iio_chan_spec ad5504_channels[] = {
|
||||
|
||||
static int ad5504_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad5504_platform_data *pdata = spi->dev.platform_data;
|
||||
const struct ad5504_platform_data *pdata = dev_get_platdata(&spi->dev);
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad5504_state *st;
|
||||
struct regulator *reg;
|
||||
|
||||
@@ -699,7 +699,6 @@ static const struct ad5755_platform_data ad5755_default_pdata = {
|
||||
|
||||
static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev)
|
||||
{
|
||||
struct fwnode_handle *pp;
|
||||
struct ad5755_platform_data *pdata;
|
||||
unsigned int tmp;
|
||||
unsigned int tmparray[3];
|
||||
@@ -746,11 +745,12 @@ static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev)
|
||||
}
|
||||
|
||||
devnr = 0;
|
||||
device_for_each_child_node(dev, pp) {
|
||||
device_for_each_child_node_scoped(dev, pp) {
|
||||
if (devnr >= AD5755_NUM_CHANNELS) {
|
||||
dev_err(dev,
|
||||
"There are too many channels defined in DT\n");
|
||||
goto error_out;
|
||||
devm_kfree(dev, pdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdata->dac[devnr].mode = AD5755_MODE_CURRENT_4mA_20mA;
|
||||
@@ -800,11 +800,6 @@ static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev)
|
||||
}
|
||||
|
||||
return pdata;
|
||||
|
||||
error_out:
|
||||
fwnode_handle_put(pp);
|
||||
devm_kfree(dev, pdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ad5755_probe(struct spi_device *spi)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#define ADI_SPI_IF_CONFIG_A 0x00
|
||||
#define ADI_SPI_IF_CONFIG_B 0x01
|
||||
@@ -325,7 +326,7 @@ static int ad5770r_read_raw(struct iio_dev *indio_dev,
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
buf16 = st->transf_buf[0] + (st->transf_buf[1] << 8);
|
||||
buf16 = get_unaligned_le16(st->transf_buf);
|
||||
*val = buf16 >> 2;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
|
||||
@@ -341,7 +341,7 @@ static const struct iio_info ad5791_info = {
|
||||
|
||||
static int ad5791_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad5791_platform_data *pdata = spi->dev.platform_data;
|
||||
const struct ad5791_platform_data *pdata = dev_get_platdata(&spi->dev);
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad5791_state *st;
|
||||
int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
|
||||
|
||||
944
drivers/iio/dac/ad8460.c
Normal file
944
drivers/iio/dac/ad8460.c
Normal file
@@ -0,0 +1,944 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* AD8460 Waveform generator DAC Driver
|
||||
*
|
||||
* Copyright (C) 2024 Analog Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/buffer-dma.h>
|
||||
#include <linux/iio/buffer-dmaengine.h>
|
||||
#include <linux/iio/consumer.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
#define AD8460_CTRL_REG(x) (x)
|
||||
#define AD8460_HVDAC_DATA_WORD(x) (0x60 + (2 * (x)))
|
||||
|
||||
#define AD8460_HV_RESET_MSK BIT(7)
|
||||
#define AD8460_HV_SLEEP_MSK BIT(4)
|
||||
#define AD8460_WAVE_GEN_MODE_MSK BIT(0)
|
||||
|
||||
#define AD8460_HVDAC_SLEEP_MSK BIT(3)
|
||||
|
||||
#define AD8460_FAULT_ARM_MSK BIT(7)
|
||||
#define AD8460_FAULT_LIMIT_MSK GENMASK(6, 0)
|
||||
|
||||
#define AD8460_APG_MODE_ENABLE_MSK BIT(5)
|
||||
#define AD8460_PATTERN_DEPTH_MSK GENMASK(3, 0)
|
||||
|
||||
#define AD8460_QUIESCENT_CURRENT_MSK GENMASK(7, 0)
|
||||
|
||||
#define AD8460_SHUTDOWN_FLAG_MSK BIT(7)
|
||||
|
||||
#define AD8460_DATA_BYTE_LOW_MSK GENMASK(7, 0)
|
||||
#define AD8460_DATA_BYTE_HIGH_MSK GENMASK(5, 0)
|
||||
#define AD8460_DATA_BYTE_FULL_MSK GENMASK(13, 0)
|
||||
|
||||
#define AD8460_DEFAULT_FAULT_PROTECT 0x00
|
||||
#define AD8460_DATA_BYTE_WORD_LENGTH 2
|
||||
#define AD8460_NUM_DATA_WORDS 16
|
||||
#define AD8460_NOMINAL_VOLTAGE_SPAN 80
|
||||
#define AD8460_MIN_EXT_RESISTOR_OHMS 2000
|
||||
#define AD8460_MAX_EXT_RESISTOR_OHMS 20000
|
||||
#define AD8460_MIN_VREFIO_UV 120000
|
||||
#define AD8460_MAX_VREFIO_UV 1200000
|
||||
#define AD8460_ABS_MAX_OVERVOLTAGE_UV 55000000
|
||||
#define AD8460_ABS_MAX_OVERCURRENT_UA 1000000
|
||||
#define AD8460_MAX_OVERTEMPERATURE_MC 150000
|
||||
#define AD8460_MIN_OVERTEMPERATURE_MC 20000
|
||||
#define AD8460_CURRENT_LIMIT_CONV(x) ((x) / 15625)
|
||||
#define AD8460_VOLTAGE_LIMIT_CONV(x) ((x) / 1953000)
|
||||
#define AD8460_TEMP_LIMIT_CONV(x) (((x) + 266640) / 6510)
|
||||
|
||||
enum ad8460_fault_type {
|
||||
AD8460_OVERCURRENT_SRC,
|
||||
AD8460_OVERCURRENT_SNK,
|
||||
AD8460_OVERVOLTAGE_POS,
|
||||
AD8460_OVERVOLTAGE_NEG,
|
||||
AD8460_OVERTEMPERATURE,
|
||||
};
|
||||
|
||||
struct ad8460_state {
|
||||
struct spi_device *spi;
|
||||
struct regmap *regmap;
|
||||
struct iio_channel *tmp_adc_channel;
|
||||
struct clk *sync_clk;
|
||||
/* lock to protect against multiple access to the device and shared data */
|
||||
struct mutex lock;
|
||||
int refio_1p2v_mv;
|
||||
u32 ext_resistor_ohms;
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires the
|
||||
* transfer buffers to live in their own cache lines.
|
||||
*/
|
||||
__le16 spi_tx_buf __aligned(IIO_DMA_MINALIGN);
|
||||
};
|
||||
|
||||
static int ad8460_hv_reset(struct ad8460_state *state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_set_bits(state->regmap, AD8460_CTRL_REG(0x00),
|
||||
AD8460_HV_RESET_MSK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fsleep(20);
|
||||
|
||||
return regmap_clear_bits(state->regmap, AD8460_CTRL_REG(0x00),
|
||||
AD8460_HV_RESET_MSK);
|
||||
}
|
||||
|
||||
static int ad8460_reset(const struct ad8460_state *state)
|
||||
{
|
||||
struct device *dev = &state->spi->dev;
|
||||
struct gpio_desc *reset;
|
||||
|
||||
reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(reset))
|
||||
return dev_err_probe(dev, PTR_ERR(reset),
|
||||
"Failed to get reset gpio");
|
||||
if (reset) {
|
||||
/* minimum duration of 10ns */
|
||||
ndelay(10);
|
||||
gpiod_set_value_cansleep(reset, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* bring all registers to their default state */
|
||||
return regmap_write(state->regmap, AD8460_CTRL_REG(0x03), 1);
|
||||
}
|
||||
|
||||
static int ad8460_enable_apg_mode(struct ad8460_state *state, int val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x02),
|
||||
AD8460_APG_MODE_ENABLE_MSK,
|
||||
FIELD_PREP(AD8460_APG_MODE_ENABLE_MSK, val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x00),
|
||||
AD8460_WAVE_GEN_MODE_MSK,
|
||||
FIELD_PREP(AD8460_WAVE_GEN_MODE_MSK, val));
|
||||
}
|
||||
|
||||
static int ad8460_read_shutdown_flag(struct ad8460_state *state, u64 *flag)
|
||||
{
|
||||
int ret, val;
|
||||
|
||||
ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x0E), &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*flag = FIELD_GET(AD8460_SHUTDOWN_FLAG_MSK, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad8460_get_hvdac_word(struct ad8460_state *state, int index, int *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(state->regmap, AD8460_HVDAC_DATA_WORD(index),
|
||||
&state->spi_tx_buf, AD8460_DATA_BYTE_WORD_LENGTH);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = le16_to_cpu(state->spi_tx_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad8460_set_hvdac_word(struct ad8460_state *state, int index, int val)
|
||||
{
|
||||
state->spi_tx_buf = cpu_to_le16(FIELD_PREP(AD8460_DATA_BYTE_FULL_MSK, val));
|
||||
|
||||
return regmap_bulk_write(state->regmap, AD8460_HVDAC_DATA_WORD(index),
|
||||
&state->spi_tx_buf, AD8460_DATA_BYTE_WORD_LENGTH);
|
||||
}
|
||||
|
||||
static ssize_t ad8460_dac_input_read(struct iio_dev *indio_dev, uintptr_t private,
|
||||
const struct iio_chan_spec *chan, char *buf)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = ad8460_get_hvdac_word(state, private, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%u\n", reg);
|
||||
}
|
||||
|
||||
static ssize_t ad8460_dac_input_write(struct iio_dev *indio_dev, uintptr_t private,
|
||||
const struct iio_chan_spec *chan,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou32(buf, 10, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
guard(mutex)(&state->lock);
|
||||
|
||||
return ad8460_set_hvdac_word(state, private, reg);
|
||||
}
|
||||
|
||||
static ssize_t ad8460_read_symbol(struct iio_dev *indio_dev, uintptr_t private,
|
||||
const struct iio_chan_spec *chan, char *buf)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x02), ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%lu\n", FIELD_GET(AD8460_PATTERN_DEPTH_MSK, reg));
|
||||
}
|
||||
|
||||
static ssize_t ad8460_write_symbol(struct iio_dev *indio_dev, uintptr_t private,
|
||||
const struct iio_chan_spec *chan,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
uint16_t sym;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou16(buf, 10, &sym);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
guard(mutex)(&state->lock);
|
||||
|
||||
return regmap_update_bits(state->regmap,
|
||||
AD8460_CTRL_REG(0x02),
|
||||
AD8460_PATTERN_DEPTH_MSK,
|
||||
FIELD_PREP(AD8460_PATTERN_DEPTH_MSK, sym));
|
||||
}
|
||||
|
||||
static ssize_t ad8460_read_toggle_en(struct iio_dev *indio_dev, uintptr_t private,
|
||||
const struct iio_chan_spec *chan, char *buf)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x02), ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%ld\n", FIELD_GET(AD8460_APG_MODE_ENABLE_MSK, reg));
|
||||
}
|
||||
|
||||
static ssize_t ad8460_write_toggle_en(struct iio_dev *indio_dev, uintptr_t private,
|
||||
const struct iio_chan_spec *chan,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
bool toggle_en;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &toggle_en);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
|
||||
return ad8460_enable_apg_mode(state, toggle_en);
|
||||
unreachable();
|
||||
}
|
||||
|
||||
static ssize_t ad8460_read_powerdown(struct iio_dev *indio_dev, uintptr_t private,
|
||||
const struct iio_chan_spec *chan, char *buf)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x01), ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%ld\n", FIELD_GET(AD8460_HVDAC_SLEEP_MSK, reg));
|
||||
}
|
||||
|
||||
static ssize_t ad8460_write_powerdown(struct iio_dev *indio_dev, uintptr_t private,
|
||||
const struct iio_chan_spec *chan,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
bool pwr_down;
|
||||
u64 sdn_flag;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &pwr_down);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
guard(mutex)(&state->lock);
|
||||
|
||||
/*
|
||||
* If powerdown is set, HVDAC is enabled and the HV driver is
|
||||
* enabled via HV_RESET in case it is in shutdown mode,
|
||||
* If powerdown is cleared, HVDAC is set to shutdown state
|
||||
* as well as the HV driver. Quiescent current decreases and ouput is
|
||||
* floating (high impedance).
|
||||
*/
|
||||
|
||||
ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x01),
|
||||
AD8460_HVDAC_SLEEP_MSK,
|
||||
FIELD_PREP(AD8460_HVDAC_SLEEP_MSK, pwr_down));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!pwr_down) {
|
||||
ret = ad8460_read_shutdown_flag(state, &sdn_flag);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (sdn_flag) {
|
||||
ret = ad8460_hv_reset(state);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x00),
|
||||
AD8460_HV_SLEEP_MSK,
|
||||
FIELD_PREP(AD8460_HV_SLEEP_MSK, !pwr_down));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const char * const ad8460_powerdown_modes[] = {
|
||||
"three_state",
|
||||
};
|
||||
|
||||
static int ad8460_get_powerdown_mode(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad8460_set_powerdown_mode(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
unsigned int type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad8460_set_sample(struct ad8460_state *state, int val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ad8460_enable_apg_mode(state, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
guard(mutex)(&state->lock);
|
||||
ret = ad8460_set_hvdac_word(state, 0, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x02),
|
||||
AD8460_PATTERN_DEPTH_MSK,
|
||||
FIELD_PREP(AD8460_PATTERN_DEPTH_MSK, 0));
|
||||
}
|
||||
|
||||
static int ad8460_set_fault_threshold(struct ad8460_state *state,
|
||||
enum ad8460_fault_type fault,
|
||||
unsigned int threshold)
|
||||
{
|
||||
return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x08 + fault),
|
||||
AD8460_FAULT_LIMIT_MSK,
|
||||
FIELD_PREP(AD8460_FAULT_LIMIT_MSK, threshold));
|
||||
}
|
||||
|
||||
static int ad8460_get_fault_threshold(struct ad8460_state *state,
|
||||
enum ad8460_fault_type fault,
|
||||
unsigned int *threshold)
|
||||
{
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x08 + fault), &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*threshold = FIELD_GET(AD8460_FAULT_LIMIT_MSK, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad8460_set_fault_threshold_en(struct ad8460_state *state,
|
||||
enum ad8460_fault_type fault, bool en)
|
||||
{
|
||||
return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x08 + fault),
|
||||
AD8460_FAULT_ARM_MSK,
|
||||
FIELD_PREP(AD8460_FAULT_ARM_MSK, en));
|
||||
}
|
||||
|
||||
static int ad8460_get_fault_threshold_en(struct ad8460_state *state,
|
||||
enum ad8460_fault_type fault, bool *en)
|
||||
{
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x08 + fault), &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*en = FIELD_GET(AD8460_FAULT_ARM_MSK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad8460_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int val, int val2,
|
||||
long mask)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
|
||||
return ad8460_set_sample(state, val);
|
||||
unreachable();
|
||||
case IIO_CURRENT:
|
||||
return regmap_write(state->regmap, AD8460_CTRL_REG(0x04),
|
||||
FIELD_PREP(AD8460_QUIESCENT_CURRENT_MSK, val));
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad8460_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
int data, ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
scoped_guard(mutex, &state->lock) {
|
||||
ret = ad8460_get_hvdac_word(state, 0, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
*val = data;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CURRENT:
|
||||
ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x04),
|
||||
&data);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = data;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_TEMP:
|
||||
ret = iio_read_channel_raw(state->tmp_adc_channel, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = data;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = clk_get_rate(state->sync_clk);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
/*
|
||||
* vCONV = vNOMINAL_SPAN * (DAC_CODE / 2**14) - 40V
|
||||
* vMAX = vNOMINAL_SPAN * (2**14 / 2**14) - 40V
|
||||
* vMIN = vNOMINAL_SPAN * (0 / 2**14) - 40V
|
||||
* vADJ = vCONV * (2000 / rSET) * (vREF / 1.2)
|
||||
* vSPAN = vADJ_MAX - vADJ_MIN
|
||||
* See datasheet page 49, section FULL-SCALE REDUCTION
|
||||
*/
|
||||
*val = AD8460_NOMINAL_VOLTAGE_SPAN * 2000 * state->refio_1p2v_mv;
|
||||
*val2 = state->ext_resistor_ohms * 1200;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad8460_select_fault_type(int chan_type, enum iio_event_direction dir)
|
||||
{
|
||||
switch (chan_type) {
|
||||
case IIO_VOLTAGE:
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
return AD8460_OVERVOLTAGE_POS;
|
||||
case IIO_EV_DIR_FALLING:
|
||||
return AD8460_OVERVOLTAGE_NEG;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CURRENT:
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
return AD8460_OVERCURRENT_SRC;
|
||||
case IIO_EV_DIR_FALLING:
|
||||
return AD8460_OVERCURRENT_SNK;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_TEMP:
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
return AD8460_OVERTEMPERATURE;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad8460_write_event_value(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info, int val, int val2)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
int fault;
|
||||
|
||||
if (type != IIO_EV_TYPE_THRESH)
|
||||
return -EINVAL;
|
||||
|
||||
if (info != IIO_EV_INFO_VALUE)
|
||||
return -EINVAL;
|
||||
|
||||
fault = ad8460_select_fault_type(chan->type, dir);
|
||||
if (fault < 0)
|
||||
return fault;
|
||||
|
||||
return ad8460_set_fault_threshold(state, fault, val);
|
||||
}
|
||||
|
||||
static int ad8460_read_event_value(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info, int *val, int *val2)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
int fault;
|
||||
|
||||
if (type != IIO_EV_TYPE_THRESH)
|
||||
return -EINVAL;
|
||||
|
||||
if (info != IIO_EV_INFO_VALUE)
|
||||
return -EINVAL;
|
||||
|
||||
fault = ad8460_select_fault_type(chan->type, dir);
|
||||
if (fault < 0)
|
||||
return fault;
|
||||
|
||||
return ad8460_get_fault_threshold(state, fault, val);
|
||||
}
|
||||
|
||||
static int ad8460_write_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir, int val)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
int fault;
|
||||
|
||||
if (type != IIO_EV_TYPE_THRESH)
|
||||
return -EINVAL;
|
||||
|
||||
fault = ad8460_select_fault_type(chan->type, dir);
|
||||
if (fault < 0)
|
||||
return fault;
|
||||
|
||||
return ad8460_set_fault_threshold_en(state, fault, val);
|
||||
}
|
||||
|
||||
static int ad8460_read_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
int fault, ret;
|
||||
bool en;
|
||||
|
||||
if (type != IIO_EV_TYPE_THRESH)
|
||||
return -EINVAL;
|
||||
|
||||
fault = ad8460_select_fault_type(chan->type, dir);
|
||||
if (fault < 0)
|
||||
return fault;
|
||||
|
||||
ret = ad8460_get_fault_threshold_en(state, fault, &en);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return en;
|
||||
}
|
||||
|
||||
static int ad8460_reg_access(struct iio_dev *indio_dev, unsigned int reg,
|
||||
unsigned int writeval, unsigned int *readval)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
|
||||
if (readval)
|
||||
return regmap_read(state->regmap, reg, readval);
|
||||
|
||||
return regmap_write(state->regmap, reg, writeval);
|
||||
}
|
||||
|
||||
static int ad8460_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
|
||||
return ad8460_enable_apg_mode(state, 0);
|
||||
}
|
||||
|
||||
static int ad8460_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad8460_state *state = iio_priv(indio_dev);
|
||||
|
||||
return ad8460_enable_apg_mode(state, 1);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops ad8460_buffer_setup_ops = {
|
||||
.preenable = &ad8460_buffer_preenable,
|
||||
.postdisable = &ad8460_buffer_postdisable,
|
||||
};
|
||||
|
||||
static const struct iio_info ad8460_info = {
|
||||
.read_raw = &ad8460_read_raw,
|
||||
.write_raw = &ad8460_write_raw,
|
||||
.write_event_value = &ad8460_write_event_value,
|
||||
.read_event_value = &ad8460_read_event_value,
|
||||
.write_event_config = &ad8460_write_event_config,
|
||||
.read_event_config = &ad8460_read_event_config,
|
||||
.debugfs_reg_access = &ad8460_reg_access,
|
||||
};
|
||||
|
||||
static const struct iio_enum ad8460_powerdown_mode_enum = {
|
||||
.items = ad8460_powerdown_modes,
|
||||
.num_items = ARRAY_SIZE(ad8460_powerdown_modes),
|
||||
.get = ad8460_get_powerdown_mode,
|
||||
.set = ad8460_set_powerdown_mode,
|
||||
};
|
||||
|
||||
#define AD8460_CHAN_EXT_INFO(_name, _what, _read, _write) { \
|
||||
.name = (_name), \
|
||||
.read = (_read), \
|
||||
.write = (_write), \
|
||||
.private = (_what), \
|
||||
.shared = IIO_SEPARATE, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info ad8460_ext_info[] = {
|
||||
AD8460_CHAN_EXT_INFO("raw0", 0, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw1", 1, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw2", 2, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw3", 3, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw4", 4, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw5", 5, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw6", 6, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw7", 7, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw8", 8, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw9", 9, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw10", 10, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw11", 11, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw12", 12, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw13", 13, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw14", 14, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("raw15", 15, ad8460_dac_input_read,
|
||||
ad8460_dac_input_write),
|
||||
AD8460_CHAN_EXT_INFO("toggle_en", 0, ad8460_read_toggle_en,
|
||||
ad8460_write_toggle_en),
|
||||
AD8460_CHAN_EXT_INFO("symbol", 0, ad8460_read_symbol,
|
||||
ad8460_write_symbol),
|
||||
AD8460_CHAN_EXT_INFO("powerdown", 0, ad8460_read_powerdown,
|
||||
ad8460_write_powerdown),
|
||||
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad8460_powerdown_mode_enum),
|
||||
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,
|
||||
&ad8460_powerdown_mode_enum),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct iio_event_spec ad8460_events[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
#define AD8460_VOLTAGE_CHAN { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
|
||||
BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.output = 1, \
|
||||
.indexed = 1, \
|
||||
.channel = 0, \
|
||||
.scan_index = 0, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 14, \
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
.ext_info = ad8460_ext_info, \
|
||||
.event_spec = ad8460_events, \
|
||||
.num_event_specs = ARRAY_SIZE(ad8460_events), \
|
||||
}
|
||||
|
||||
#define AD8460_CURRENT_CHAN { \
|
||||
.type = IIO_CURRENT, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.output = 1, \
|
||||
.indexed = 1, \
|
||||
.channel = 0, \
|
||||
.scan_index = -1, \
|
||||
.event_spec = ad8460_events, \
|
||||
.num_event_specs = ARRAY_SIZE(ad8460_events), \
|
||||
}
|
||||
|
||||
#define AD8460_TEMP_CHAN { \
|
||||
.type = IIO_TEMP, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.indexed = 1, \
|
||||
.channel = 0, \
|
||||
.scan_index = -1, \
|
||||
.event_spec = ad8460_events, \
|
||||
.num_event_specs = 1, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec ad8460_channels[] = {
|
||||
AD8460_VOLTAGE_CHAN,
|
||||
AD8460_CURRENT_CHAN,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad8460_channels_with_tmp_adc[] = {
|
||||
AD8460_VOLTAGE_CHAN,
|
||||
AD8460_CURRENT_CHAN,
|
||||
AD8460_TEMP_CHAN,
|
||||
};
|
||||
|
||||
static const struct regmap_config ad8460_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x7F,
|
||||
};
|
||||
|
||||
static const char * const ad8460_supplies[] = {
|
||||
"avdd_3p3v", "dvdd_3p3v", "vcc_5v", "hvcc", "hvee", "vref_5v"
|
||||
};
|
||||
|
||||
static int ad8460_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct ad8460_state *state;
|
||||
struct iio_dev *indio_dev;
|
||||
u32 tmp[2], temp;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
state = iio_priv(indio_dev);
|
||||
|
||||
indio_dev->name = "ad8460";
|
||||
indio_dev->info = &ad8460_info;
|
||||
|
||||
state->spi = spi;
|
||||
|
||||
state->regmap = devm_regmap_init_spi(spi, &ad8460_regmap_config);
|
||||
if (IS_ERR(state->regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(state->regmap),
|
||||
"Failed to initialize regmap");
|
||||
|
||||
ret = devm_mutex_init(dev, &state->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
state->sync_clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(state->sync_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(state->sync_clk),
|
||||
"Failed to get sync clk\n");
|
||||
|
||||
state->tmp_adc_channel = devm_iio_channel_get(dev, "ad8460-tmp");
|
||||
if (IS_ERR(state->tmp_adc_channel)) {
|
||||
if (PTR_ERR(state->tmp_adc_channel) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
indio_dev->channels = ad8460_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ad8460_channels);
|
||||
} else {
|
||||
indio_dev->channels = ad8460_channels_with_tmp_adc;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ad8460_channels_with_tmp_adc);
|
||||
}
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad8460_supplies),
|
||||
ad8460_supplies);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to enable power supplies\n");
|
||||
|
||||
ret = devm_regulator_get_enable_read_voltage(dev, "refio_1p2v");
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret, "Failed to get reference voltage\n");
|
||||
|
||||
state->refio_1p2v_mv = ret == -ENODEV ? 1200 : ret / 1000;
|
||||
|
||||
if (!in_range(state->refio_1p2v_mv, AD8460_MIN_VREFIO_UV / 1000,
|
||||
AD8460_MAX_VREFIO_UV / 1000))
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Invalid ref voltage range(%u mV) [%u mV, %u mV]\n",
|
||||
state->refio_1p2v_mv,
|
||||
AD8460_MIN_VREFIO_UV / 1000,
|
||||
AD8460_MAX_VREFIO_UV / 1000);
|
||||
|
||||
ret = device_property_read_u32(dev, "adi,external-resistor-ohms",
|
||||
&state->ext_resistor_ohms);
|
||||
if (ret)
|
||||
state->ext_resistor_ohms = 2000;
|
||||
else if (!in_range(state->ext_resistor_ohms, AD8460_MIN_EXT_RESISTOR_OHMS,
|
||||
AD8460_MAX_EXT_RESISTOR_OHMS))
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Invalid resistor set range(%u) [%u, %u]\n",
|
||||
state->ext_resistor_ohms,
|
||||
AD8460_MIN_EXT_RESISTOR_OHMS,
|
||||
AD8460_MAX_EXT_RESISTOR_OHMS);
|
||||
|
||||
ret = device_property_read_u32_array(dev, "adi,range-microamp",
|
||||
tmp, ARRAY_SIZE(tmp));
|
||||
if (!ret) {
|
||||
if (in_range(tmp[1], 0, AD8460_ABS_MAX_OVERCURRENT_UA))
|
||||
regmap_write(state->regmap, AD8460_CTRL_REG(0x08),
|
||||
FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) |
|
||||
AD8460_CURRENT_LIMIT_CONV(tmp[1]));
|
||||
|
||||
if (in_range(tmp[0], -AD8460_ABS_MAX_OVERCURRENT_UA, 0))
|
||||
regmap_write(state->regmap, AD8460_CTRL_REG(0x09),
|
||||
FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) |
|
||||
AD8460_CURRENT_LIMIT_CONV(abs(tmp[0])));
|
||||
}
|
||||
|
||||
ret = device_property_read_u32_array(dev, "adi,range-microvolt",
|
||||
tmp, ARRAY_SIZE(tmp));
|
||||
if (!ret) {
|
||||
if (in_range(tmp[1], 0, AD8460_ABS_MAX_OVERVOLTAGE_UV))
|
||||
regmap_write(state->regmap, AD8460_CTRL_REG(0x0A),
|
||||
FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) |
|
||||
AD8460_VOLTAGE_LIMIT_CONV(tmp[1]));
|
||||
|
||||
if (in_range(tmp[0], -AD8460_ABS_MAX_OVERVOLTAGE_UV, 0))
|
||||
regmap_write(state->regmap, AD8460_CTRL_REG(0x0B),
|
||||
FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) |
|
||||
AD8460_VOLTAGE_LIMIT_CONV(abs(tmp[0])));
|
||||
}
|
||||
|
||||
ret = device_property_read_u32(dev, "adi,max-millicelsius", &temp);
|
||||
if (!ret) {
|
||||
if (in_range(temp, AD8460_MIN_OVERTEMPERATURE_MC,
|
||||
AD8460_MAX_OVERTEMPERATURE_MC))
|
||||
regmap_write(state->regmap, AD8460_CTRL_REG(0x0C),
|
||||
FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) |
|
||||
AD8460_TEMP_LIMIT_CONV(abs(temp)));
|
||||
}
|
||||
|
||||
ret = ad8460_reset(state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enables DAC by default */
|
||||
ret = regmap_clear_bits(state->regmap, AD8460_CTRL_REG(0x01),
|
||||
AD8460_HVDAC_SLEEP_MSK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->setup_ops = &ad8460_buffer_setup_ops;
|
||||
|
||||
ret = devm_iio_dmaengine_buffer_setup_ext(dev, indio_dev, "tx",
|
||||
IIO_BUFFER_DIRECTION_OUT);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to get DMA buffer\n");
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id ad8460_of_match[] = {
|
||||
{ .compatible = "adi, ad8460" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad8460_of_match);
|
||||
|
||||
static struct spi_driver ad8460_driver = {
|
||||
.driver = {
|
||||
.name = "ad8460",
|
||||
.of_match_table = ad8460_of_match,
|
||||
},
|
||||
.probe = ad8460_probe,
|
||||
};
|
||||
module_spi_driver(ad8460_driver);
|
||||
|
||||
MODULE_AUTHOR("Mariel Tinaco <mariel.tinaco@analog.com");
|
||||
MODULE_DESCRIPTION("AD8460 DAC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER);
|
||||
@@ -35,35 +35,37 @@
|
||||
*/
|
||||
|
||||
/* Base controls */
|
||||
#define AXI_DAC_REG_CONFIG 0x0c
|
||||
#define AXI_DDS_DISABLE BIT(6)
|
||||
#define AXI_DAC_CONFIG_REG 0x0c
|
||||
#define AXI_DAC_CONFIG_DDS_DISABLE BIT(6)
|
||||
|
||||
/* DAC controls */
|
||||
#define AXI_DAC_REG_RSTN 0x0040
|
||||
#define AXI_DAC_RSTN_CE_N BIT(2)
|
||||
#define AXI_DAC_RSTN_MMCM_RSTN BIT(1)
|
||||
#define AXI_DAC_RSTN_RSTN BIT(0)
|
||||
#define AXI_DAC_REG_CNTRL_1 0x0044
|
||||
#define AXI_DAC_SYNC BIT(0)
|
||||
#define AXI_DAC_REG_CNTRL_2 0x0048
|
||||
#define ADI_DAC_R1_MODE BIT(4)
|
||||
#define AXI_DAC_DRP_STATUS 0x0074
|
||||
#define AXI_DAC_DRP_LOCKED BIT(17)
|
||||
#define AXI_DAC_RSTN_REG 0x0040
|
||||
#define AXI_DAC_RSTN_CE_N BIT(2)
|
||||
#define AXI_DAC_RSTN_MMCM_RSTN BIT(1)
|
||||
#define AXI_DAC_RSTN_RSTN BIT(0)
|
||||
#define AXI_DAC_CNTRL_1_REG 0x0044
|
||||
#define AXI_DAC_CNTRL_1_SYNC BIT(0)
|
||||
#define AXI_DAC_CNTRL_2_REG 0x0048
|
||||
#define ADI_DAC_CNTRL_2_R1_MODE BIT(5)
|
||||
#define AXI_DAC_DRP_STATUS_REG 0x0074
|
||||
#define AXI_DAC_DRP_STATUS_DRP_LOCKED BIT(17)
|
||||
|
||||
/* DAC Channel controls */
|
||||
#define AXI_DAC_REG_CHAN_CNTRL_1(c) (0x0400 + (c) * 0x40)
|
||||
#define AXI_DAC_REG_CHAN_CNTRL_3(c) (0x0408 + (c) * 0x40)
|
||||
#define AXI_DAC_SCALE_SIGN BIT(15)
|
||||
#define AXI_DAC_SCALE_INT BIT(14)
|
||||
#define AXI_DAC_SCALE GENMASK(14, 0)
|
||||
#define AXI_DAC_REG_CHAN_CNTRL_2(c) (0x0404 + (c) * 0x40)
|
||||
#define AXI_DAC_REG_CHAN_CNTRL_4(c) (0x040c + (c) * 0x40)
|
||||
#define AXI_DAC_PHASE GENMASK(31, 16)
|
||||
#define AXI_DAC_FREQUENCY GENMASK(15, 0)
|
||||
#define AXI_DAC_REG_CHAN_CNTRL_7(c) (0x0418 + (c) * 0x40)
|
||||
#define AXI_DAC_DATA_SEL GENMASK(3, 0)
|
||||
#define AXI_DAC_CHAN_CNTRL_1_REG(c) (0x0400 + (c) * 0x40)
|
||||
#define AXI_DAC_CHAN_CNTRL_3_REG(c) (0x0408 + (c) * 0x40)
|
||||
#define AXI_DAC_CHAN_CNTRL_3_SCALE_SIGN BIT(15)
|
||||
#define AXI_DAC_CHAN_CNTRL_3_SCALE_INT BIT(14)
|
||||
#define AXI_DAC_CHAN_CNTRL_3_SCALE GENMASK(14, 0)
|
||||
#define AXI_DAC_CHAN_CNTRL_2_REG(c) (0x0404 + (c) * 0x40)
|
||||
#define AXI_DAC_CHAN_CNTRL_2_PHASE GENMASK(31, 16)
|
||||
#define AXI_DAC_CHAN_CNTRL_2_FREQUENCY GENMASK(15, 0)
|
||||
#define AXI_DAC_CHAN_CNTRL_4_REG(c) (0x040c + (c) * 0x40)
|
||||
#define AXI_DAC_CHAN_CNTRL_7_REG(c) (0x0418 + (c) * 0x40)
|
||||
#define AXI_DAC_CHAN_CNTRL_7_DATA_SEL GENMASK(3, 0)
|
||||
|
||||
/* 360 degrees in rad */
|
||||
#define AXI_DAC_2_PI_MEGA 6283190
|
||||
#define AXI_DAC_2_PI_MEGA 6283190
|
||||
|
||||
enum {
|
||||
AXI_DAC_DATA_INTERNAL_TONE,
|
||||
AXI_DAC_DATA_DMA = 2,
|
||||
@@ -89,7 +91,7 @@ static int axi_dac_enable(struct iio_backend *back)
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
ret = regmap_set_bits(st->regmap, AXI_DAC_REG_RSTN,
|
||||
ret = regmap_set_bits(st->regmap, AXI_DAC_RSTN_REG,
|
||||
AXI_DAC_RSTN_MMCM_RSTN);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -98,12 +100,14 @@ static int axi_dac_enable(struct iio_backend *back)
|
||||
* designs really use it but if they don't we still get the lock bit
|
||||
* set. So let's do it all the time so the code is generic.
|
||||
*/
|
||||
ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_DRP_STATUS, __val,
|
||||
__val & AXI_DAC_DRP_LOCKED, 100, 1000);
|
||||
ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_DRP_STATUS_REG,
|
||||
__val,
|
||||
__val & AXI_DAC_DRP_STATUS_DRP_LOCKED,
|
||||
100, 1000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_set_bits(st->regmap, AXI_DAC_REG_RSTN,
|
||||
return regmap_set_bits(st->regmap, AXI_DAC_RSTN_REG,
|
||||
AXI_DAC_RSTN_RSTN | AXI_DAC_RSTN_MMCM_RSTN);
|
||||
}
|
||||
|
||||
@@ -112,7 +116,7 @@ static void axi_dac_disable(struct iio_backend *back)
|
||||
struct axi_dac_state *st = iio_backend_get_priv(back);
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
regmap_write(st->regmap, AXI_DAC_REG_RSTN, 0);
|
||||
regmap_write(st->regmap, AXI_DAC_RSTN_REG, 0);
|
||||
}
|
||||
|
||||
static struct iio_buffer *axi_dac_request_buffer(struct iio_backend *back,
|
||||
@@ -155,15 +159,15 @@ static int __axi_dac_frequency_get(struct axi_dac_state *st, unsigned int chan,
|
||||
}
|
||||
|
||||
if (tone_2)
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_4(chan);
|
||||
reg = AXI_DAC_CHAN_CNTRL_4_REG(chan);
|
||||
else
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_2(chan);
|
||||
reg = AXI_DAC_CHAN_CNTRL_2_REG(chan);
|
||||
|
||||
ret = regmap_read(st->regmap, reg, &raw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
raw = FIELD_GET(AXI_DAC_FREQUENCY, raw);
|
||||
raw = FIELD_GET(AXI_DAC_CHAN_CNTRL_2_FREQUENCY, raw);
|
||||
*freq = DIV_ROUND_CLOSEST_ULL(raw * st->dac_clk, BIT(16));
|
||||
|
||||
return 0;
|
||||
@@ -194,17 +198,18 @@ static int axi_dac_scale_get(struct axi_dac_state *st,
|
||||
u32 reg, raw;
|
||||
|
||||
if (tone_2)
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel);
|
||||
reg = AXI_DAC_CHAN_CNTRL_3_REG(chan->channel);
|
||||
else
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel);
|
||||
reg = AXI_DAC_CHAN_CNTRL_1_REG(chan->channel);
|
||||
|
||||
ret = regmap_read(st->regmap, reg, &raw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sign = FIELD_GET(AXI_DAC_SCALE_SIGN, raw);
|
||||
raw = FIELD_GET(AXI_DAC_SCALE, raw);
|
||||
scale = DIV_ROUND_CLOSEST_ULL((u64)raw * MEGA, AXI_DAC_SCALE_INT);
|
||||
sign = FIELD_GET(AXI_DAC_CHAN_CNTRL_3_SCALE_SIGN, raw);
|
||||
raw = FIELD_GET(AXI_DAC_CHAN_CNTRL_3_SCALE, raw);
|
||||
scale = DIV_ROUND_CLOSEST_ULL((u64)raw * MEGA,
|
||||
AXI_DAC_CHAN_CNTRL_3_SCALE_INT);
|
||||
|
||||
vals[0] = scale / MEGA;
|
||||
vals[1] = scale % MEGA;
|
||||
@@ -227,15 +232,15 @@ static int axi_dac_phase_get(struct axi_dac_state *st,
|
||||
int ret, vals[2];
|
||||
|
||||
if (tone_2)
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel);
|
||||
reg = AXI_DAC_CHAN_CNTRL_4_REG(chan->channel);
|
||||
else
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel);
|
||||
reg = AXI_DAC_CHAN_CNTRL_2_REG(chan->channel);
|
||||
|
||||
ret = regmap_read(st->regmap, reg, &raw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
raw = FIELD_GET(AXI_DAC_PHASE, raw);
|
||||
raw = FIELD_GET(AXI_DAC_CHAN_CNTRL_2_PHASE, raw);
|
||||
phase = DIV_ROUND_CLOSEST_ULL((u64)raw * AXI_DAC_2_PI_MEGA, U16_MAX);
|
||||
|
||||
vals[0] = phase / MEGA;
|
||||
@@ -260,18 +265,20 @@ static int __axi_dac_frequency_set(struct axi_dac_state *st, unsigned int chan,
|
||||
}
|
||||
|
||||
if (tone_2)
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_4(chan);
|
||||
reg = AXI_DAC_CHAN_CNTRL_4_REG(chan);
|
||||
else
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_2(chan);
|
||||
reg = AXI_DAC_CHAN_CNTRL_2_REG(chan);
|
||||
|
||||
raw = DIV64_U64_ROUND_CLOSEST((u64)freq * BIT(16), sample_rate);
|
||||
|
||||
ret = regmap_update_bits(st->regmap, reg, AXI_DAC_FREQUENCY, raw);
|
||||
ret = regmap_update_bits(st->regmap, reg,
|
||||
AXI_DAC_CHAN_CNTRL_2_FREQUENCY, raw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* synchronize channels */
|
||||
return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC);
|
||||
return regmap_set_bits(st->regmap, AXI_DAC_CNTRL_1_REG,
|
||||
AXI_DAC_CNTRL_1_SYNC);
|
||||
}
|
||||
|
||||
static int axi_dac_frequency_set(struct axi_dac_state *st,
|
||||
@@ -312,16 +319,16 @@ static int axi_dac_scale_set(struct axi_dac_state *st,
|
||||
|
||||
/* format is 1.1.14 (sign, integer and fractional bits) */
|
||||
if (scale < 0) {
|
||||
raw = FIELD_PREP(AXI_DAC_SCALE_SIGN, 1);
|
||||
raw = FIELD_PREP(AXI_DAC_CHAN_CNTRL_3_SCALE_SIGN, 1);
|
||||
scale *= -1;
|
||||
}
|
||||
|
||||
raw |= div_u64((u64)scale * AXI_DAC_SCALE_INT, MEGA);
|
||||
raw |= div_u64((u64)scale * AXI_DAC_CHAN_CNTRL_3_SCALE_INT, MEGA);
|
||||
|
||||
if (tone_2)
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel);
|
||||
reg = AXI_DAC_CHAN_CNTRL_3_REG(chan->channel);
|
||||
else
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel);
|
||||
reg = AXI_DAC_CHAN_CNTRL_1_REG(chan->channel);
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
ret = regmap_write(st->regmap, reg, raw);
|
||||
@@ -329,7 +336,8 @@ static int axi_dac_scale_set(struct axi_dac_state *st,
|
||||
return ret;
|
||||
|
||||
/* synchronize channels */
|
||||
ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC);
|
||||
ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_1_REG,
|
||||
AXI_DAC_CNTRL_1_SYNC);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -355,18 +363,19 @@ static int axi_dac_phase_set(struct axi_dac_state *st,
|
||||
raw = DIV_ROUND_CLOSEST_ULL((u64)phase * U16_MAX, AXI_DAC_2_PI_MEGA);
|
||||
|
||||
if (tone_2)
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel);
|
||||
reg = AXI_DAC_CHAN_CNTRL_4_REG(chan->channel);
|
||||
else
|
||||
reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel);
|
||||
reg = AXI_DAC_CHAN_CNTRL_2_REG(chan->channel);
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
ret = regmap_update_bits(st->regmap, reg, AXI_DAC_PHASE,
|
||||
FIELD_PREP(AXI_DAC_PHASE, raw));
|
||||
ret = regmap_update_bits(st->regmap, reg, AXI_DAC_CHAN_CNTRL_2_PHASE,
|
||||
FIELD_PREP(AXI_DAC_CHAN_CNTRL_2_PHASE, raw));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* synchronize channels */
|
||||
ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC);
|
||||
ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_1_REG,
|
||||
AXI_DAC_CNTRL_1_SYNC);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -437,7 +446,7 @@ static int axi_dac_extend_chan(struct iio_backend *back,
|
||||
|
||||
if (chan->type != IIO_ALTVOLTAGE)
|
||||
return -EINVAL;
|
||||
if (st->reg_config & AXI_DDS_DISABLE)
|
||||
if (st->reg_config & AXI_DAC_CONFIG_DDS_DISABLE)
|
||||
/* nothing to extend */
|
||||
return 0;
|
||||
|
||||
@@ -454,13 +463,14 @@ static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan,
|
||||
switch (data) {
|
||||
case IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE:
|
||||
return regmap_update_bits(st->regmap,
|
||||
AXI_DAC_REG_CHAN_CNTRL_7(chan),
|
||||
AXI_DAC_DATA_SEL,
|
||||
AXI_DAC_CHAN_CNTRL_7_REG(chan),
|
||||
AXI_DAC_CHAN_CNTRL_7_DATA_SEL,
|
||||
AXI_DAC_DATA_INTERNAL_TONE);
|
||||
case IIO_BACKEND_EXTERNAL:
|
||||
return regmap_update_bits(st->regmap,
|
||||
AXI_DAC_REG_CHAN_CNTRL_7(chan),
|
||||
AXI_DAC_DATA_SEL, AXI_DAC_DATA_DMA);
|
||||
AXI_DAC_CHAN_CNTRL_7_REG(chan),
|
||||
AXI_DAC_CHAN_CNTRL_7_DATA_SEL,
|
||||
AXI_DAC_DATA_DMA);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -475,7 +485,7 @@ static int axi_dac_set_sample_rate(struct iio_backend *back, unsigned int chan,
|
||||
|
||||
if (!sample_rate)
|
||||
return -EINVAL;
|
||||
if (st->reg_config & AXI_DDS_DISABLE)
|
||||
if (st->reg_config & AXI_DAC_CONFIG_DDS_DISABLE)
|
||||
/* sample_rate has no meaning if DDS is disabled */
|
||||
return 0;
|
||||
|
||||
@@ -580,7 +590,7 @@ static int axi_dac_probe(struct platform_device *pdev)
|
||||
* Force disable the core. Up to the frontend to enable us. And we can
|
||||
* still read/write registers...
|
||||
*/
|
||||
ret = regmap_write(st->regmap, AXI_DAC_REG_RSTN, 0);
|
||||
ret = regmap_write(st->regmap, AXI_DAC_RSTN_REG, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -601,7 +611,7 @@ static int axi_dac_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Let's get the core read only configuration */
|
||||
ret = regmap_read(st->regmap, AXI_DAC_REG_CONFIG, &st->reg_config);
|
||||
ret = regmap_read(st->regmap, AXI_DAC_CONFIG_REG, &st->reg_config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -613,7 +623,8 @@ static int axi_dac_probe(struct platform_device *pdev)
|
||||
* want independent channels let's override the core's default value and
|
||||
* set the R1_MODE bit.
|
||||
*/
|
||||
ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_2, ADI_DAC_R1_MODE);
|
||||
ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
|
||||
ADI_DAC_CNTRL_2_R1_MODE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ MODULE_DEVICE_TABLE(of, dpot_dac_match);
|
||||
|
||||
static struct platform_driver dpot_dac_driver = {
|
||||
.probe = dpot_dac_probe,
|
||||
.remove_new = dpot_dac_remove,
|
||||
.remove = dpot_dac_remove,
|
||||
.driver = {
|
||||
.name = "iio-dpot-dac",
|
||||
.of_match_table = dpot_dac_match,
|
||||
|
||||
@@ -184,9 +184,9 @@ static const struct of_device_id lpc18xx_dac_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, lpc18xx_dac_match);
|
||||
|
||||
static struct platform_driver lpc18xx_dac_driver = {
|
||||
.probe = lpc18xx_dac_probe,
|
||||
.remove_new = lpc18xx_dac_remove,
|
||||
.driver = {
|
||||
.probe = lpc18xx_dac_probe,
|
||||
.remove = lpc18xx_dac_remove,
|
||||
.driver = {
|
||||
.name = "lpc18xx-dac",
|
||||
.of_match_table = lpc18xx_dac_match,
|
||||
},
|
||||
|
||||
@@ -201,7 +201,7 @@ static int m62332_probe(struct i2c_client *client)
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &m62332_info;
|
||||
|
||||
ret = iio_map_array_register(indio_dev, client->dev.platform_data);
|
||||
ret = iio_map_array_register(indio_dev, dev_get_platdata(&client->dev));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -143,10 +143,10 @@ static const struct iio_chan_spec max517_channels[] = {
|
||||
|
||||
static int max517_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct max517_platform_data *platform_data = dev_get_platdata(&client->dev);
|
||||
const struct i2c_device_id *id = i2c_client_get_device_id(client);
|
||||
struct max517_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
struct max517_platform_data *platform_data = client->dev.platform_data;
|
||||
int chan;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
|
||||
@@ -245,7 +245,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
|
||||
|
||||
static struct platform_driver stm32_dac_driver = {
|
||||
.probe = stm32_dac_probe,
|
||||
.remove_new = stm32_dac_remove,
|
||||
.remove = stm32_dac_remove,
|
||||
.driver = {
|
||||
.name = "stm32-dac-core",
|
||||
.of_match_table = stm32_dac_of_match,
|
||||
|
||||
@@ -398,7 +398,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
|
||||
|
||||
static struct platform_driver stm32_dac_driver = {
|
||||
.probe = stm32_dac_probe,
|
||||
.remove_new = stm32_dac_remove,
|
||||
.remove = stm32_dac_remove,
|
||||
.driver = {
|
||||
.name = "stm32-dac",
|
||||
.of_match_table = stm32_dac_of_match,
|
||||
|
||||
@@ -272,7 +272,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend,
|
||||
|
||||
static struct platform_driver vf610_dac_driver = {
|
||||
.probe = vf610_dac_probe,
|
||||
.remove_new = vf610_dac_remove,
|
||||
.remove = vf610_dac_remove,
|
||||
.driver = {
|
||||
.name = "vf610-dac",
|
||||
.of_match_table = vf610_dac_match,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user