Merge tag 'iio-for-6.13b' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next

Jonathan writes:

IIO: 2nd set of new device support, features and cleanup for 6.13

Alongside new drivers and device support there are several large
cleanups going on across the IIO tree and we see part of some of those
in this pull request.

Merged char-misc-next at point of 6.12-rc6 merge to avoid a
conflict with a fix for the ad7380 merged earlier this cycle.
Note that I previously messed this merge up and had to reconstruct
it this morning so a coherent pull request was possible. The new
stuff is all the same as has been in linux-next for some time with
the exception of the kernel-doc related __private ordering fix
that went in yesterday.

New device support
==================

adi,ad7380
- Support for adaq4370-4 and adaq4370 quad channel ADCs.
adi,ad7606
- Various cleanups preceeding support of AD7607, AD7608 and AD7609 ADCs.
adi,ad7779
- New driver supproting AD7770, AD7771 and AD7779 ADCs.
allegro,als31300
- New driver for this 3D Linear Hall Effect sensor.
bosch,bmi270
- Add support BMI260 which is similar but requires a different firmware image.
bosch,smi240
- New driver for this IMU.
ti,opt3001
- Add support opt3002 light sensor which has a wider spectral range than
  the opt3001.
vishay,veml3235
- New driver for this ambient light sensor.

Features
========

hid-sensors
- Add support Human Proximity Range and Attention detection (requiring
  a new classification style channel type)
adi,ad3552r
- Add backend support and related platform driver to support use
  with an FPGA IP to allow QSPI + DDR bus operation and much higher
  data aquisition rates.  (various rework preceeded this feature)
adi,ad7606
- Various cleanup prior to enabling use with an IIO Backend and PWM trigger
  enabling much higher speed data capture.
bosch,bme680
- Support control of preheat current
- Support triggered buffer capture
- Add SCALE and RAW channels (needed to enable the buffered capture).
bosch,bmp280
- Enable sleeping to save power.
- Add interrupt support for bmp3xx and bmp5xx devices. Also update bmp085
  to new approach.
- Enable data ready trigger.
bosch,bmi270
- Add triggered buffer support
- Add scale and sampling frequency control.
vishay,veml6070
- Support integration time via DT binding for an external resistor value.

Cleanup and minor fixes
=======================

core
- Fix a longstanding issue with event codes for differential channels.
  Note that not all drivers are yet fixed, but macros have been added
  to avoid potential repeats of this in future.
- Tidy up handling in iio_read_acpi_mount matrix.
- Mark iio_dev::priv with __private. Later move the marking before the
  field name to avoid a kernel-doc issue.
treewide
- Drop some pointless default n entries in Kconfig.
- Add an iio_get_acpi_device_name_and_data() handler to replace some
  commonly repeated code.
- simplify use of 'state' in write_event_config() callback  as it is
  effectively a boolean. Once done make it a boolean (lots of drivers
  were updated to enable this)
- some more use of devm_regulator_get_enable_read_voltage( to replace
  open coded versions.  Where this enables it convert all of remove
  handling to devm based and drop the remove callback.
- check returns from devm_mutex_init()
accel drivers
- Use aligned_s64 instead of s64 __aligned(8)
adi,ad5791
- Add some missing GPIOs and power supplies that presumably were always
  hard wired on previous boards.
- Refactor to use chip_info in device id tables.
- Convert probe entirely to devm based simplify code and allowing remove()
  callback to be dropped.
adi,ad7192
- Check return from spi_get_device_match_data()
adi,ad74413r
- Don't keep an unnecessary copy of the gpio after probe.
- Use devm_regulator_get_enable_read_voltage() instead of open coding.
- Apply cleanup.h approach to reduce complexity.
adi,dac8460
- Fix a wrong compaitble ID due to a stray space.
- Add an spi_device_id table.
bosch,bmc150
- Drop some likely false ACPI IDs.
- Drop left over unused ACPI specific code.
bosch,bme680
- Add mising regmap.h include.
- Reduce excessive sleep on startup.
- Drop some cammelcase usage.
- Use fsleep
- Generalize read functions to allow for reuse.
- Use s16 variable to avoid some incorrect casting
bosch,bmg150
- Drop some likely false ACPI IDs.
bosch,bmi270
- Drop unused FREQUENCY and SCALE attributes that always returned an
  error (they wil be back impelmented correctly).
- Factor out the chip specific data into a structure to enable simple
  support for additional devices.
isil,isl29018
- Drop ACPI_PTR() and CONFIG_ACPI guards as not worth the trouble for very
  minor saving.
invensense,mpu6050
- Use much simpler test for ACPI firmware.
kionix,kxcjk-1013
- Drop unnecessary ACPI entry in the i2c_device_id table.
- Drop support KX022-1020 to fix a bug that was introduced with that change.
  Hopefully a fixed version will replace it soon.
- Drop CONFIG guards for PM in favor of pm_ptr() and the compiler removing
  dead code.
- Switch from enum to chip_info structure and add ODR times to that structure.
- Deduplicate one of those ODR structures
- Drop ACPI_PTR() and move ID table out of config guards.
- Minor additional cleanup.
liteon,ltr401
- Drop some likely false ACPI Ids and add LTER0303 which is know to be in use.
microchip,pac1934
- Use much simpler test for ACPI firmware.
vishay,veml6070
- Use unsigned int instead of just unsigned.
- Use FIELD_PREP to make setting of field value explicit.

Various other minor fixes to documentation

* tag 'iio-for-6.13b' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (153 commits)
  iio: Move __private marking before struct element priv in struct iio_dev
  docs: iio: ad7380: add adaq4370-4 and adaq4380-4
  iio: adc: ad7380: add support for adaq4370-4 and adaq4380-4
  iio: adc: ad7380: use local dev variable to shorten long lines
  iio: adc: ad7380: fix oversampling formula
  dt-bindings: iio: adc: ad7380: add adaq4370-4 and adaq4380-4 compatible parts
  iio: chemical: bme680: Add support for preheat current
  iio: chemical: bme680: Add triggered buffer support
  iio: chemical: bme680: Add SCALE and RAW channels
  iio: chemical: bme680: refactorize set_mode() mode
  iio: events: make IIO_EVENT_CODE macro private
  iio: accel: mma9553: use specialized event code macros
  iio: dummy: use specialized event code macros
  iio: adc: ad7280a: use IIO_DIFF_EVENT_CODE macro helper
  iio: events.h: add event identifier macros for differential channel
  iio: magnetometer: add Allegro MicroSystems ALS31300 3-D Linear Hall Effect driver
  dt-bindings: iio: magnetometer: document the Allegro MicroSystems ALS31300 3-D Linear Hall Effect Sensor
  dt-bindings: vendor-prefixes: Add Allegro MicroSystems, Inc
  iio: light: apds9960: remove useless return
  iio: light: apds9960: convert als_int and pxs_int to bool
  ...
This commit is contained in:
Greg Kroah-Hartman
2024-11-09 14:34:48 +01:00
163 changed files with 8322 additions and 2216 deletions

View File

@@ -2268,6 +2268,30 @@ Description:
An example format is 16-bytes, 2-digits-per-byte, HEX-string
representing the sensor unique ID number.
What: /sys/bus/iio/devices/iio:deviceX/filter_type_available
What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_filter_mode_available
KernelVersion: 6.1
Contact: linux-iio@vger.kernel.org
Description:
Reading returns a list with the possible filter modes. Options
for the attribute:
* "sinc3" - The digital sinc3 filter. Moderate 1st
conversion time. Good noise performance.
* "sinc4" - Sinc 4. Excellent noise performance. Long
1st conversion time.
* "sinc5" - The digital sinc5 filter. Excellent noise
performance
* "sinc4+sinc1" - Sinc4 + averaging by 8. Low 1st conversion
time.
* "sinc3+rej60" - Sinc3 + 60Hz rejection.
* "sinc3+sinc1" - Sinc3 + averaging by 8. Low 1st conversion
time.
* "sinc3+pf1" - Sinc3 + device specific Post Filter 1.
* "sinc3+pf2" - Sinc3 + device specific Post Filter 2.
* "sinc3+pf3" - Sinc3 + device specific Post Filter 3.
* "sinc3+pf4" - Sinc3 + device specific Post Filter 4.
What: /sys/.../events/in_proximity_thresh_either_runningperiod
KernelVersion: 6.6
Contact: linux-iio@vger.kernel.org
@@ -2339,3 +2363,11 @@ KernelVersion: 6.10
Contact: linux-iio@vger.kernel.org
Description:
The value of current sense resistor in Ohms.
What: /sys/.../iio:deviceX/in_attention_input
KernelVersion: 6.13
Contact: linux-iio@vger.kernel.org
Description:
Value representing the user's attention to the system expressed
in units as percentage. This usually means if the user is
looking at the screen or not.

View File

@@ -1,46 +0,0 @@
What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_filter_mode_available
KernelVersion: 6.2
Contact: linux-iio@vger.kernel.org
Description:
Reading returns a list with the possible filter modes.
* "sinc4" - Sinc 4. Excellent noise performance. Long
1st conversion time. No natural 50/60Hz rejection.
* "sinc4+sinc1" - Sinc4 + averaging by 8. Low 1st conversion
time.
* "sinc3" - Sinc3. Moderate 1st conversion time.
Good noise performance.
* "sinc3+rej60" - Sinc3 + 60Hz rejection. At a sampling
frequency of 50Hz, achieves simultaneous 50Hz and 60Hz
rejection.
* "sinc3+sinc1" - Sinc3 + averaging by 8. Low 1st conversion
time. Best used with a sampling frequency of at least
216.19Hz.
* "sinc3+pf1" - Sinc3 + Post Filter 1. 53dB rejection @
50Hz, 58dB rejection @ 60Hz.
* "sinc3+pf2" - Sinc3 + Post Filter 2. 70dB rejection @
50Hz, 70dB rejection @ 60Hz.
* "sinc3+pf3" - Sinc3 + Post Filter 3. 99dB rejection @
50Hz, 103dB rejection @ 60Hz.
* "sinc3+pf4" - Sinc3 + Post Filter 4. 103dB rejection @
50Hz, 109dB rejection @ 60Hz.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_filter_mode
KernelVersion: 6.2
Contact: linux-iio@vger.kernel.org
Description:
Set the filter mode of the differential channel. When the filter
mode changes, the in_voltageY-voltageZ_sampling_frequency and
in_voltageY-voltageZ_sampling_frequency_available attributes
might also change to accommodate the new filter mode.
If the current sampling frequency is out of range for the new
filter mode, the sampling frequency will be changed to the
closest valid one.

View File

@@ -25,6 +25,8 @@ description: |
* https://www.analog.com/en/products/ad7386-4.html
* https://www.analog.com/en/products/ad7387-4.html
* https://www.analog.com/en/products/ad7388-4.html
* https://www.analog.com/en/products/adaq4370-4.html
* https://www.analog.com/en/products/adaq4380-4.html
$ref: /schemas/spi/spi-peripheral-props.yaml#
@@ -46,6 +48,8 @@ properties:
- adi,ad7386-4
- adi,ad7387-4
- adi,ad7388-4
- adi,adaq4370-4
- adi,adaq4380-4
reg:
maxItems: 1
@@ -70,6 +74,20 @@ properties:
refin-supply:
description:
A 2.5V to 3.3V supply for external reference voltage, for ad7380-4 only.
For adaq devices, a 5V supply voltage. A 3.3V internal reference is
derived from it. Connect to vs-p-supply for normal operation.
vs-p-supply:
description:
Amplifiers positive supply.
vs-n-supply:
description:
Amplifiers negative supply.
ldo-supply:
description:
LDO supply. Connect to vs-p-supply or a 3.6 to 5.5 V supply.
aina-supply:
description:
@@ -97,12 +115,45 @@ properties:
specify the ALERT interrupt.
maxItems: 1
"#address-cells":
const: 1
"#size-cells":
const: 0
required:
- compatible
- reg
- vcc-supply
- vlogic-supply
patternProperties:
"^channel@[0-3]$":
$ref: adc.yaml
type: object
properties:
reg:
description:
The channel number. From 0 to 3 corresponding to channels A,B,C,D
minimum: 0
maximum: 3
adi,gain-milli:
description:
The hardware gain applied to the ADC input (in milli units).
If not present, default to 1000 (no actual gain applied).
Refer to the typical connection diagrams section of the datasheet for
pin wiring.
$ref: /schemas/types.yaml#/definitions/uint16
enum: [300, 600, 1000, 1600]
default: 1000
required:
- reg
additionalProperties: false
unevaluatedProperties: false
allOf:
@@ -140,6 +191,7 @@ allOf:
aind-supply: false
# ad7380-4 uses refin-supply as external reference.
# adaq devices use internal reference only, derived from refin-supply
# All other chips from ad738x family use refio as optional external reference.
# When refio-supply is omitted, internal reference is used.
- if:
@@ -147,6 +199,8 @@ allOf:
compatible:
enum:
- adi,ad7380-4
- adi,adaq4370-4
- adi,adaq4380-4
then:
properties:
refio-supply: false
@@ -156,6 +210,27 @@ allOf:
properties:
refin-supply: false
# adaq devices need more supplies and using channel to declare gain property
# only applies to adaq devices
- if:
properties:
compatible:
enum:
- adi,adaq4370-4
- adi,adaq4380-4
then:
required:
- vs-p-supply
- vs-n-supply
- ldo-supply
else:
properties:
vs-p-supply: false
vs-n-supply: false
ldo-supply: false
patternProperties:
"^channel@[0-3]$": false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
@@ -180,3 +255,48 @@ examples:
refio-supply = <&supply_2_5V>;
};
};
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,adaq4380-4";
reg = <0>;
spi-cpol;
spi-cpha;
spi-max-frequency = <80000000>;
interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio0>;
vcc-supply = <&supply_3_3V>;
vlogic-supply = <&supply_3_3V>;
refin-supply = <&supply_5V>;
vs-p-supply = <&supply_5V>;
vs-n-supply = <&supply_0V>;
ldo-supply = <&supply_5V>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
adi,gain-milli = /bits/ 16 <300>;
};
channel@2 {
reg = <2>;
adi,gain-milli = /bits/ 16 <600>;
};
channel@3 {
reg = <3>;
adi,gain-milli = /bits/ 16 <1000>;
};
};
};

View File

@@ -16,6 +16,9 @@ description: |
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/ad7607.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7608.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7609.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf
properties:
@@ -28,6 +31,9 @@ properties:
- adi,ad7606b
- adi,ad7606c-16
- adi,ad7606c-18
- adi,ad7607
- adi,ad7608
- adi,ad7609
- adi,ad7616
reg:
@@ -39,6 +45,11 @@ properties:
"#size-cells":
const: 0
# According to the datasheet, "Data is clocked in from SDI on the falling
# edge of SCLK, while data is clocked out on DOUTA on the rising edge of
# SCLK". Also, even if not stated textually in the datasheet, it is made
# clear on the diagrams that sclk idles at high. Subsequently, in case SPI
# interface is used, the correct way is to only set spi-cpol.
spi-cpha: true
spi-cpol: true
@@ -124,6 +135,29 @@ properties:
assumed that the pins are hardwired to VDD.
type: boolean
pwms:
description:
In case the conversion is triggered by a PWM instead of a GPIO plugged to
the CONVST pin, the PWM must be referenced.
The first is the PWM connected to CONVST or CONVST1 for the chips with the
2nd PWM connected to CONVST2, if CONVST2 is available and not shorted to
CONVST1.
minItems: 1
maxItems: 2
pwm-names:
items:
- const: convst1
- const: convst2
io-backends:
description:
A reference to the iio-backend, which is responsible handling the BUSY
pin's falling edge and communication.
An example of backend can be found at
http://analogdevicesinc.github.io/hdl/library/axi_ad7606x/index.html
patternProperties:
"^channel@[1-8]$":
type: object
@@ -168,15 +202,24 @@ patternProperties:
required:
- compatible
- reg
- spi-cpha
- avcc-supply
- vdrive-supply
- interrupts
- adi,conversion-start-gpios
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
- oneOf:
- required:
- adi,conversion-start-gpios
- required:
- pwms
- oneOf:
- required:
- interrupts
- required:
- io-backends
- if:
properties:
compatible:
@@ -213,11 +256,18 @@ allOf:
- adi,ad7606-4
- adi,ad7606-6
- adi,ad7606-8
- adi,ad7607
- adi,ad7608
- adi,ad7609
then:
properties:
adi,sw-mode: false
else:
properties:
pwms:
maxItems: 1
pwm-names:
maxItems: 1
adi,conversion-start-gpios:
maxItems: 1
@@ -243,6 +293,29 @@ allOf:
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
iio-backend {
#address-cells = <1>;
#size-cells = <0>;
adi_adc@0 {
compatible = "adi,ad7606b";
reg = <0>;
pwms = <&axi_pwm_gen 0 0>;
avcc-supply = <&adc_vref>;
vdrive-supply = <&vdd_supply>;
reset-gpios = <&gpio0 91 GPIO_ACTIVE_HIGH>;
standby-gpios = <&gpio0 90 GPIO_ACTIVE_LOW>;
adi,range-gpios = <&gpio0 89 GPIO_ACTIVE_HIGH>;
adi,oversampling-ratio-gpios = <&gpio0 88 GPIO_ACTIVE_HIGH
&gpio0 87 GPIO_ACTIVE_HIGH
&gpio0 86 GPIO_ACTIVE_HIGH>;
io-backends = <&iio_backend>;
};
};
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
@@ -255,7 +328,6 @@ examples:
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
spi-cpha;
avcc-supply = <&adc_vref>;
vdrive-supply = <&vdd_supply>;
@@ -288,7 +360,6 @@ examples:
spi-max-frequency = <1000000>;
spi-cpol;
spi-cpha;
avcc-supply = <&adc_vref>;
vdrive-supply = <&vdd_supply>;

View File

@@ -0,0 +1,110 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/adi,ad7779.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD777X family 8-Channel, 24-Bit, Simultaneous Sampling ADCs
maintainers:
- Ramona Nechita <ramona.nechita@analog.com>
description: |
The AD777X family consist of 8-channel, simultaneous sampling analog-to-
digital converter (ADC). Eight full Σ-Δ ADCs are on-chip. The
AD7771 provides an ultralow input current to allow direct sensor
connection. Each input channel has a programmable gain stage
allowing gains of 1, 2, 4, and 8 to map lower amplitude sensor
outputs into the full-scale ADC input range, maximizing the
dynamic range of the signal chain.
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7770.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7771.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7779.pdf
$ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
enum:
- adi,ad7770
- adi,ad7771
- adi,ad7779
reg:
maxItems: 1
'#address-cells':
const: 1
'#size-cells':
const: 0
clocks:
maxItems: 1
avdd1-supply:
description: Front-End analog supply AVDD1. Can be used as conversion ref.
avdd2-supply:
description: AVDD2 Analog Supply from 2.2 V to 3.6 V.
avdd4-supply:
description: AVDD4 SAR Analog Supply and Reference Source.
interrupts:
minItems: 1
items:
- description: |
adc_rdy: Interrupt line for DRDY signal which indicates the end of
conversion independently of the interface selected to read back the
Σ-∆ conversion.
- description: |
Alert: The chip includes self diagnostic features to guarantee the
correct operation. If an error is detected, the ALERT pin is pulled
high to generate an external interruption to the controller.
interrupt-names:
minItems: 1
maxItems: 2
items:
enum:
- adc_rdy
- alert
start-gpios:
description:
Pin that controls start synchronization pulse.
maxItems: 1
reset-gpios:
maxItems: 1
required:
- compatible
- reg
- clocks
- interrupts
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,ad7779";
reg = <0>;
start-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpio0 93 GPIO_ACTIVE_LOW>;
interrupt-parent = <&intc>;
interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "adc_rdy";
clocks = <&adc_clk>;
};
};
...

View File

@@ -60,6 +60,12 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
io-backends:
description: The iio backend reference.
Device can be optionally connected to the "axi-ad3552r IP" fpga-based
QSPI + DDR (Double Data Rate) controller to reach high speed transfers.
maxItems: 1
'#address-cells':
const: 1
@@ -128,6 +134,7 @@ patternProperties:
- custom-output-range-config
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
- if:
properties:
compatible:

View File

@@ -26,16 +26,47 @@ properties:
vdd-supply: true
vss-supply: true
vcc-supply:
description:
Supply that powers the chip.
iovcc-supply:
description:
Supply for the digital interface.
vrefp-supply:
description:
Positive referance input voltage range. From 5v to (vdd - 2.5)
vrefn-supply:
description:
Negative referance input voltage range. From (vss + 2.5) to 0.
adi,rbuf-gain2-en:
description: Specify to allow an external amplifier to be connected in a
gain of two configuration.
type: boolean
reset-gpios:
maxItems: 1
clear-gpios:
maxItems: 1
ldac-gpios:
description:
LDAC pin to be used as a hardware trigger to update the DAC channels.
maxItems: 1
required:
- compatible
- reg
- vdd-supply
- vss-supply
- vcc-supply
- iovcc-supply
- vrefp-supply
- vrefn-supply
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
@@ -44,6 +75,7 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
@@ -53,6 +85,13 @@ examples:
reg = <0>;
vss-supply = <&dac_vss>;
vdd-supply = <&dac_vdd>;
vcc-supply = <&dac_vcc>;
iovcc-supply = <&dac_iovcc>;
vrefp-supply = <&dac_vrefp>;
vrefn-supply = <&dac_vrefn>;
reset-gpios = <&gpio_bd 16 GPIO_ACTIVE_LOW>;
clear-gpios = <&gpio_bd 17 GPIO_ACTIVE_LOW>;
ldac-gpios = <&gpio_bd 18 GPIO_ACTIVE_HIGH>;
};
};
...

View File

@@ -19,11 +19,13 @@ description: |
memory via DMA into the DAC.
https://wiki.analog.com/resources/fpga/docs/axi_dac_ip
https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html
properties:
compatible:
enum:
- adi,axi-dac-9.1.b
- adi,axi-ad3552r
reg:
maxItems: 1
@@ -36,7 +38,14 @@ properties:
- const: tx
clocks:
maxItems: 1
minItems: 1
maxItems: 2
clock-names:
items:
- const: s_axi_aclk
- const: dac_clk
minItems: 1
'#io-backend-cells':
const: 0
@@ -47,7 +56,29 @@ required:
- reg
- clocks
additionalProperties: false
allOf:
- if:
properties:
compatible:
contains:
const: adi,axi-ad3552r
then:
$ref: /schemas/spi/spi-controller.yaml#
properties:
clocks:
minItems: 2
clock-names:
minItems: 2
required:
- clock-names
else:
properties:
clocks:
maxItems: 1
clock-names:
maxItems: 1
unevaluatedProperties: false
examples:
- |
@@ -57,6 +88,38 @@ examples:
dmas = <&tx_dma 0>;
dma-names = "tx";
#io-backend-cells = <0>;
clocks = <&axi_clk>;
clocks = <&clkc 15>;
clock-names = "s_axi_aclk";
};
- |
#include <dt-bindings/gpio/gpio.h>
axi_dac: spi@44a70000 {
compatible = "adi,axi-ad3552r";
reg = <0x44a70000 0x1000>;
dmas = <&dac_tx_dma 0>;
dma-names = "tx";
#io-backend-cells = <0>;
clocks = <&clkc 15>, <&ref_clk>;
clock-names = "s_axi_aclk", "dac_clk";
#address-cells = <1>;
#size-cells = <0>;
dac@0 {
compatible = "adi,ad3552r";
reg = <0>;
reset-gpios = <&gpio0 92 GPIO_ACTIVE_HIGH>;
io-backends = <&axi_dac>;
spi-max-frequency = <20000000>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
adi,output-range-microvolt = <(-10000000) (10000000)>;
};
};
};
...

View File

@@ -18,7 +18,9 @@ description: |
properties:
compatible:
const: bosch,bmi270
enum:
- bosch,bmi260
- bosch,bmi270
reg:
maxItems: 1

View File

@@ -0,0 +1,51 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/imu/bosch,smi240.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bosch smi240 imu
maintainers:
- Jianping Shen <Jianping.Shen@de.bosch.com>
description:
Inertial Measurement Unit with Accelerometer and Gyroscope
with a measurement range of +/-300°/s and up to 16g.
https://www.bosch-semiconductors.com/mems-sensors/highly-automated-driving/smi240/
properties:
compatible:
const: bosch,smi240
reg:
maxItems: 1
vdd-supply: true
vddio-supply: true
required:
- compatible
- reg
- vdd-supply
- vddio-supply
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
imu@0 {
compatible = "bosch,smi240";
reg = <0>;
vdd-supply = <&vdd>;
vddio-supply = <&vddio>;
spi-max-frequency = <10000000>;
};
};

View File

@@ -15,7 +15,9 @@ description: |
properties:
compatible:
const: ti,opt3001
enum:
- ti,opt3001
- ti,opt3002
reg:
maxItems: 1

View File

@@ -4,7 +4,7 @@
$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)
title: VEML3235, VEML6030, VEML6035 and VEML7700 Ambient Light Sensors (ALS)
maintainers:
- Rishi Gupta <gupt21@gmail.com>
@@ -20,6 +20,7 @@ description: |
whenever configured threshold is crossed.
Specifications about the sensors can be found at:
https://www.vishay.com/docs/80131/veml3235.pdf
https://www.vishay.com/docs/84366/veml6030.pdf
https://www.vishay.com/docs/84889/veml6035.pdf
https://www.vishay.com/docs/84286/veml7700.pdf
@@ -27,6 +28,7 @@ description: |
properties:
compatible:
enum:
- vishay,veml3235
- vishay,veml6030
- vishay,veml6035
- vishay,veml7700
@@ -76,6 +78,7 @@ allOf:
properties:
compatible:
enum:
- vishay,veml3235
- vishay,veml7700
then:
properties:

View File

@@ -22,6 +22,13 @@ properties:
reg:
maxItems: 1
vishay,rset-ohms:
description:
Resistor used to select the integration time.
default: 270000
minimum: 75000
maximum: 1200000
vdd-supply: true
required:
@@ -29,6 +36,17 @@ required:
- reg
- vdd-supply
allOf:
- if:
properties:
compatible:
enum:
- vishay,veml6040
- vishay,veml6075
then:
properties:
vishay,rset-ohms: false
additionalProperties: false
examples:

View File

@@ -0,0 +1,46 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/magnetometer/allegromicro,als31300.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Allegro MicroSystems ALS31300 3-D Linear Hall Effect sensor
maintainers:
- Neil Armstrong <neil.armstrong@linaro.org>
properties:
$nodename:
pattern: '^magnetometer@[0-9a-f]+$'
compatible:
enum:
- allegromicro,als31300-500 # Factory configured at 500 Gauss input range
- allegromicro,als31300-1000 # Factory configured at 1000 Gauss input range
- allegromicro,als31300-2000 # Factory configured at 2000 Gauss input range
reg:
maxItems: 1
vcc-supply:
description: 5.5V supply
interrupts:
maxItems: 1
required:
- compatible
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
magnetometer@61 {
compatible = "allegromicro,als31300-500";
reg = <0x61>;
vcc-supply = <&hall_vcc>;
};
};

View File

@@ -47,15 +47,33 @@ properties:
maxItems: 1
interrupts:
description:
interrupt mapping for IRQ (BMP085 only)
maxItems: 1
drive-open-drain:
description:
set if the interrupt pin should be configured as open drain.
If not set, defaults to push-pull configuration.
type: boolean
required:
- compatible
- vddd-supply
- vdda-supply
allOf:
- if:
properties:
compatible:
not:
contains:
enum:
- bosch,bmp085
- bosch,bmp380
- bosch,bmp580
then:
properties:
interrupts: false
additionalProperties: false
examples:

View File

@@ -83,6 +83,8 @@ patternProperties:
description: ALFA Network Inc.
"^allegro,.*":
description: Allegro DVT
"^allegromicro,.*":
description: Allegro MicroSystems, Inc.
"^alliedvision,.*":
description: Allied Vision Technologies GmbH
"^allo,.*":

View File

@@ -27,6 +27,8 @@ The following chips are supported by this driver:
* `AD7386-4 <https://www.analog.com/en/products/ad7386-4.html>`_
* `AD7387-4 <https://www.analog.com/en/products/ad7387-4.html>`_
* `AD7388-4 <https://www.analog.com/en/products/ad7388-4.html>`_
* `ADAQ4370-4 <https://www.analog.com/en/products/adaq4370-4.html>`_
* `ADAQ4380-4 <https://www.analog.com/en/products/adaq4380-4.html>`_
Supported features
@@ -47,6 +49,12 @@ ad7380-4
ad7380-4 supports only an external reference voltage (2.5V to 3.3V). It must be
declared in the device tree as ``refin-supply``.
ADAQ devices
~~~~~~~~~~~~
adaq4370-4 and adaq4380-4 don't have an external reference, but use a 3.3V
internal reference derived from one of its supplies (``refin-supply``)
All other devices from ad738x family
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -121,6 +129,14 @@ Example for AD7386/7/8 (2 channels parts):
When enabling sequencer mode, the effective sampling rate is divided by two.
Gain (ADAQ devices only)
~~~~~~~~~~~~~~~~~~~~~~~~
ADAQ devices have a pin selectable gain in front of each ADC. The appropriate
gain is selectable from device tree using the ``adi,gain-milli`` property.
Refer to the typical connection diagrams section of the datasheet for pin
wiring.
Unimplemented features
----------------------

View File

@@ -0,0 +1,144 @@
.. SPDX-License-Identifier: GPL-2.0-only
=============
AD7606 driver
=============
ADC driver for Analog Devices Inc. AD7606 and similar devices. The module name
is ``ad7606``.
Supported devices
=================
The following chips are supported by this driver:
* `AD7605 <https://www.analog.com/en/products/ad7605.html>`_
* `AD7606 <https://www.analog.com/en/products/ad7606.html>`_
* `AD7606B <https://www.analog.com/en/products/ad7606b.html>`_
* `AD7616 <https://www.analog.com/en/products/ad7616.html>`_
Supported features
==================
SPI wiring modes
----------------
These ADCs can output data on several SDO lines (1/2/4/8). The driver
currently supports only 1 SDO line.
Parallel wiring mode
--------------------
There is also a parallel interface, with 16 lines (that can be reduced to 8 in
byte mode). The parallel interface is selected by declaring the device as
platform in the device tree (with no io-backends node defined, see below).
IIO-backend mode
----------------
This mode allows to reach the best sample rates, but it requires an external
hardware (eg HDL or APU) to handle the low level communication.
The backend mode is enabled when through the definition of the "io-backends"
property in the device tree.
The reference configuration for the current implementation of IIO-backend mode
is the HDL reference provided by ADI:
https://wiki.analog.com/resources/eval/user-guides/ad7606x-fmc/hdl
This implementation embeds an IIO-backend compatible IP (adi-axi-adc) and a PWM
connected to the conversion trigger pin.
.. code-block::
+---+ +----------------------------
| | +-------+ |AD76xx
| A | controls | | |
| D |-------------->| PWM |-------------->| cnvst
| 7 | | | |
| 6 | +-------+ |
| 0 | controls +-----------+-----------+ |
| 6 |---------->| | |<--| frstdata
| | | Backend | Backend |<--| busy
| D | | Driver | | |
| R | | | |-->| clk
| I | requests |+---------+| DMA | |
| V |----------->| Buffer ||<---- |<=>| DATA
| E | |+---------+| | |
| R | +-----------+-----------+ |
| |-------------------------------------->| reset/configuration gpios
+---+ +-----------------------------
Software and hardware modes
---------------------------
While all the AD7606/AD7616 series parts can be configured using GPIOs, some of
them can be configured using register.
The chips that support software mode have more values available for configuring
the device, as well as more settings, and allow to control the range and
calibration per channel.
The following settings are available per channel in software mode:
- Scale
Also, there is a broader choice of oversampling ratios in software mode.
Conversion triggering
---------------------
The conversion can be triggered by two distinct ways:
- A GPIO is connected to the conversion trigger pin, and this GPIO is controlled
by the driver directly. In this configuration, the driver sets back the
conversion trigger pin to high as soon as it has read all the conversions.
- An external source is connected to the conversion trigger pin. In the
current implementation, it must be a PWM. In this configuration, the driver
does not control directly the conversion trigger pin. Instead, it can
control the PWM's frequency. This trigger is enabled only for iio-backend.
Reference voltage
-----------------
2 possible reference voltage sources are supported:
- Internal reference (2.5V)
- External reference (2.5V)
The source is determined by the device tree. If ``refin-supply`` is present,
then the external reference is used, otherwise the internal reference is used.
Oversampling
------------
This family supports oversampling to improve SNR.
In software mode, the following ratios are available:
1 (oversampling disabled)/2/4/8/16/32/64/128/256.
Unimplemented features
----------------------
- 2/4/8 SDO lines
- CRC indication
- Calibration
Device buffers
==============
IIO triggered buffer
--------------------
This driver supports IIO triggered buffers, with a "built in" trigger, i.e the
trigger is allocated and linked by the driver, and a new conversion is triggered
as soon as the samples are transferred, and a timestamp channel is added to make
up for the potential jitter induced by the delays in the interrupt handling.
IIO backend buffer
------------------
When IIO backend is used, the trigger is not needed, and the sample rate is
considered as stable. There is no timestamp channel. The communication is
delegated to an external logic, called a backend, and the backend's driver
handles the buffer. When this mode is enabled, the driver cannot control the
conversion pin, because the busy pin is bound to the backend.

View File

@@ -21,6 +21,7 @@ Industrial I/O Kernel Drivers
ad4000
ad4695
ad7380
ad7606
ad7625
ad7944
adis16475

View File

@@ -1255,7 +1255,6 @@ M: Cosmin Tanislav <cosmin.tanislav@analog.com>
L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
F: Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130
F: Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml
F: drivers/iio/adc/ad4130.c
@@ -1565,6 +1564,7 @@ F: Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
F: Documentation/devicetree/bindings/iio/*/adi,*
F: Documentation/devicetree/bindings/iio/adc/lltc,ltc2496.yaml
F: Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml
F: Documentation/iio/ad7606.rst
F: drivers/iio/*/ad*
F: drivers/iio/adc/ltc249*
F: drivers/iio/amplifiers/hmc425a.c
@@ -24652,6 +24652,12 @@ S: Maintained
F: drivers/input/serio/userio.c
F: include/uapi/linux/userio.h
VISHAY VEML3235 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/veml3235.c
VISHAY VEML6030 AMBIENT LIGHT SENSOR DRIVER
M: Javier Carrasco <javier.carrasco.cruz@gmail.com>
S: Maintained

View File

@@ -643,7 +643,7 @@ static irqreturn_t adxl355_trigger_handler(int irq, void *p)
* The acceleration data is 24 bits and big endian. It has to be saved
* in 32 bits, hence, it is saved in the 2nd byte of the 4 byte buffer.
* The buf array is 14 bytes as it includes 3x4=12 bytes for
* accelaration data of x, y, and z axis. It also includes 2 bytes for
* acceleration data of x, y, and z axis. It also includes 2 bytes for
* temperature data.
*/
ret = regmap_bulk_read(data->regmap, ADXL355_XDATA3_REG,

View File

@@ -1073,7 +1073,7 @@ static int adxl367_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
enum adxl367_activity_type act;

View File

@@ -940,7 +940,7 @@ static int adxl372_read_event_config(struct iio_dev *indio_dev, const struct iio
static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan,
enum iio_event_type type, enum iio_event_direction dir,
int state)
bool state)
{
struct adxl372_state *st = iio_priv(indio_dev);

View File

@@ -1386,7 +1386,7 @@ static int adxl380_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
struct adxl380_state *st = iio_priv(indio_dev);
enum adxl380_axis axis;

View File

@@ -21,6 +21,7 @@
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
@@ -144,7 +145,7 @@ struct bma180_data {
/* Ensure timestamp is naturally aligned */
struct {
s16 chan[4];
s64 timestamp __aligned(8);
aligned_s64 timestamp;
} scan;
};

View File

@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/spi/spi.h>
#include <linux/iio/buffer.h>

View File

@@ -115,7 +115,7 @@ struct bma400_data {
struct {
__le16 buff[3];
u8 temperature;
s64 ts __aligned(8);
aligned_s64 ts;
} buffer __aligned(IIO_DMA_MINALIGN);
__le16 status;
__be16 duration;
@@ -1293,7 +1293,7 @@ static int bma400_disable_adv_interrupt(struct bma400_data *data)
static int bma400_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir, int state)
enum iio_event_direction dir, bool state)
{
struct bma400_data *data = iio_priv(indio_dev);
int ret;

View File

@@ -804,7 +804,7 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
struct bmc150_accel_data *data = iio_priv(indio_dev);
int ret;

View File

@@ -6,6 +6,7 @@
#include <linux/iio/iio.h>
#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
#include <linux/workqueue.h>
struct regmap;
@@ -69,7 +70,7 @@ struct bmc150_accel_data {
*/
struct {
__le16 channels[3];
s64 ts __aligned(8);
aligned_s64 ts;
} scan;
u8 bw_bits;
u32 slope_dur;

View File

@@ -22,6 +22,7 @@
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/types.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
@@ -163,7 +164,7 @@ struct fxls8962af_data {
const struct fxls8962af_chip_info *chip_info;
struct {
__le16 channels[3];
s64 ts __aligned(8);
aligned_s64 ts;
} scan;
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
struct iio_mount_matrix orientation;
@@ -616,7 +617,7 @@ static int
fxls8962af_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir, int state)
enum iio_event_direction dir, bool state)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
u8 enable_event, enable_bits;

View File

@@ -16,6 +16,7 @@
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/string_choices.h>
#include <linux/types.h>
#include <linux/units.h>
#include <linux/iio/iio.h>
@@ -292,7 +293,7 @@ struct kx022a_data {
__le16 buffer[8] __aligned(IIO_DMA_MINALIGN);
struct {
__le16 channels[3];
s64 ts __aligned(8);
aligned_s64 ts;
} scan;
};

View File

@@ -4,13 +4,15 @@
* Copyright (c) 2014, Intel Corporation.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/acpi.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@@ -168,14 +170,73 @@
#define KXCJK1013_DEFAULT_WAKE_THRES 1
enum kx_chipset {
KXCJK1013,
KXCJ91008,
KXTJ21009,
KXTF9,
KX0221020,
KX0231025,
KX_MAX_CHIPS /* this must be last */
/* Refer to section 4 of the specification */
struct kx_odr_start_up_time {
int odr_bits;
int usec;
};
/* KXCJK-1013 */
static const struct kx_odr_start_up_time kxcjk1013_odr_start_up_times[] = {
{ 0x08, 100000 },
{ 0x09, 100000 },
{ 0x0A, 100000 },
{ 0x0B, 100000 },
{ 0x00, 80000 },
{ 0x01, 41000 },
{ 0x02, 21000 },
{ 0x03, 11000 },
{ 0x04, 6400 },
{ 0x05, 3900 },
{ 0x06, 2700 },
{ 0x07, 2100 },
{ }
};
/* KXCTJ2-1009 */
static const struct kx_odr_start_up_time kxtj21009_odr_start_up_times[] = {
{ 0x08, 1240000 },
{ 0x09, 621000 },
{ 0x0A, 309000 },
{ 0x0B, 151000 },
{ 0x00, 80000 },
{ 0x01, 41000 },
{ 0x02, 21000 },
{ 0x03, 11000 },
{ 0x04, 6000 },
{ 0x05, 4000 },
{ 0x06, 3000 },
{ 0x07, 2000 },
{ }
};
/* KXTF9 */
static const struct kx_odr_start_up_time kxtf9_odr_start_up_times[] = {
{ 0x01, 81000 },
{ 0x02, 41000 },
{ 0x03, 21000 },
{ 0x04, 11000 },
{ 0x05, 5100 },
{ 0x06, 2700 },
{ }
};
/* KX023-1025 */
static const struct kx_odr_start_up_time kx0231025_odr_start_up_times[] = {
/* First 4 are not in datasheet, taken from KXCTJ2-1009 */
{ 0x08, 1240000 },
{ 0x09, 621000 },
{ 0x0A, 309000 },
{ 0x0B, 151000 },
{ 0x00, 81000 },
{ 0x01, 40000 },
{ 0x02, 22000 },
{ 0x03, 12000 },
{ 0x04, 7000 },
{ 0x05, 4400 },
{ 0x06, 3000 },
{ 0x07, 3000 },
{ }
};
enum kx_acpi_type {
@@ -234,6 +295,55 @@ static const struct kx_chipset_regs kx0231025_regs = {
.wake_thres = KX023_REG_ATH,
};
struct kx_chipset_info {
const struct kx_chipset_regs *regs;
const struct kx_odr_start_up_time *times;
enum kx_acpi_type acpi_type;
};
static const struct kx_chipset_info kxcjk1013_info = {
.regs = &kxcjk1013_regs,
.times = pm_ptr(kxcjk1013_odr_start_up_times),
};
static const struct kx_chipset_info kxcj91008_info = {
.regs = &kxcjk1013_regs,
.times = pm_ptr(kxcjk1013_odr_start_up_times),
};
static const struct kx_chipset_info kxcj91008_kiox010a_info = {
.regs = &kxcjk1013_regs,
.times = pm_ptr(kxcjk1013_odr_start_up_times),
.acpi_type = ACPI_KIOX010A,
};
static const struct kx_chipset_info kxcj91008_kiox020a_info = {
.regs = &kxcjk1013_regs,
.times = pm_ptr(kxcjk1013_odr_start_up_times),
.acpi_type = ACPI_GENERIC,
};
static const struct kx_chipset_info kxcj91008_smo8500_info = {
.regs = &kxcjk1013_regs,
.times = pm_ptr(kxcjk1013_odr_start_up_times),
.acpi_type = ACPI_SMO8500,
};
static const struct kx_chipset_info kxtj21009_info = {
.regs = &kxcjk1013_regs,
.times = pm_ptr(kxtj21009_odr_start_up_times),
};
static const struct kx_chipset_info kxtf9_info = {
.regs = &kxtf9_regs,
.times = pm_ptr(kxtf9_odr_start_up_times),
};
static const struct kx_chipset_info kx0231025_info = {
.regs = &kx0231025_regs,
.times = pm_ptr(kx0231025_odr_start_up_times),
};
enum kxcjk1013_axis {
AXIS_X,
AXIS_Y,
@@ -250,7 +360,7 @@ struct kxcjk1013_data {
/* Ensure timestamp naturally aligned */
struct {
s16 chans[AXIS_MAX];
s64 timestamp __aligned(8);
aligned_s64 timestamp;
} scan;
u8 odr_bits;
u8 range;
@@ -261,9 +371,7 @@ struct kxcjk1013_data {
int ev_enable_state;
bool motion_trigger_on;
int64_t timestamp;
enum kx_chipset chipset;
enum kx_acpi_type acpi_type;
const struct kx_chipset_regs *regs;
const struct kx_chipset_info *info;
};
enum kxcjk1013_mode {
@@ -314,83 +422,6 @@ static const struct kx_odr_map kxtf9_samp_freq_table[] = {
static const char *const kxtf9_samp_freq_avail =
"25 50 100 200 400 800";
/* Refer to section 4 of the specification */
static __maybe_unused const struct {
int odr_bits;
int usec;
} odr_start_up_times[KX_MAX_CHIPS][12] = {
/* KXCJK-1013 */
{
{0x08, 100000},
{0x09, 100000},
{0x0A, 100000},
{0x0B, 100000},
{0, 80000},
{0x01, 41000},
{0x02, 21000},
{0x03, 11000},
{0x04, 6400},
{0x05, 3900},
{0x06, 2700},
{0x07, 2100},
},
/* KXCJ9-1008 */
{
{0x08, 100000},
{0x09, 100000},
{0x0A, 100000},
{0x0B, 100000},
{0, 80000},
{0x01, 41000},
{0x02, 21000},
{0x03, 11000},
{0x04, 6400},
{0x05, 3900},
{0x06, 2700},
{0x07, 2100},
},
/* KXCTJ2-1009 */
{
{0x08, 1240000},
{0x09, 621000},
{0x0A, 309000},
{0x0B, 151000},
{0, 80000},
{0x01, 41000},
{0x02, 21000},
{0x03, 11000},
{0x04, 6000},
{0x05, 4000},
{0x06, 3000},
{0x07, 2000},
},
/* KXTF9 */
{
{0x01, 81000},
{0x02, 41000},
{0x03, 21000},
{0x04, 11000},
{0x05, 5100},
{0x06, 2700},
},
/* KX023-1025 */
{
/* First 4 are not in datasheet, taken from KXCTJ2-1009 */
{0x08, 1240000},
{0x09, 621000},
{0x0A, 309000},
{0x0B, 151000},
{0, 81000},
{0x01, 40000},
{0x02, 22000},
{0x03, 12000},
{0x04, 7000},
{0x05, 4400},
{0x06, 3000},
{0x07, 3000},
},
};
static const struct {
u16 scale;
u8 gsel_0;
@@ -424,30 +455,15 @@ static int kiox010a_dsm(struct device *dev, int fn_index)
return 0;
}
static const struct acpi_device_id kx_acpi_match[] = {
{"KXCJ1013", KXCJK1013},
{"KXCJ1008", KXCJ91008},
{"KXCJ9000", KXCJ91008},
{"KIOX0008", KXCJ91008},
{"KIOX0009", KXTJ21009},
{"KIOX000A", KXCJ91008},
{"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */
{"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */
{"KXTJ1009", KXTJ21009},
{"KXJ2109", KXTJ21009},
{"SMO8500", KXCJ91008},
{ }
};
MODULE_DEVICE_TABLE(acpi, kx_acpi_match);
#endif
static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
enum kxcjk1013_mode mode)
{
const struct kx_chipset_regs *regs = data->info->regs;
int ret;
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -458,7 +474,7 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
else
ret |= KXCJK1013_REG_CTRL1_BIT_PC1;
ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -470,9 +486,10 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
static int kxcjk1013_get_mode(struct kxcjk1013_data *data,
enum kxcjk1013_mode *mode)
{
const struct kx_chipset_regs *regs = data->info->regs;
int ret;
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -488,9 +505,10 @@ static int kxcjk1013_get_mode(struct kxcjk1013_data *data,
static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index)
{
const struct kx_chipset_regs *regs = data->info->regs;
int ret;
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -501,7 +519,7 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index)
ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3);
ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4);
ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -514,10 +532,11 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index)
static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
{
const struct kx_chipset_regs *regs = data->info->regs;
int ret;
#ifdef CONFIG_ACPI
if (data->acpi_type == ACPI_KIOX010A) {
if (data->info->acpi_type == ACPI_KIOX010A) {
/* Make sure the kbd and touchpad on 2-in-1s using 2 KXCJ91008-s work */
kiox010a_dsm(&data->client->dev, KIOX010A_SET_LAPTOP_MODE);
}
@@ -535,7 +554,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
if (ret < 0)
return ret;
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -544,7 +563,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
/* Set 12 bit mode */
ret |= KXCJK1013_REG_CTRL1_BIT_RES;
ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl\n");
return ret;
@@ -555,7 +574,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
if (ret < 0)
return ret;
ret = i2c_smbus_read_byte_data(data->client, data->regs->data_ctrl);
ret = i2c_smbus_read_byte_data(data->client, regs->data_ctrl);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_data_ctrl\n");
return ret;
@@ -564,7 +583,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
data->odr_bits = ret;
/* Set up INT polarity */
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
return ret;
@@ -575,14 +594,14 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
else
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEA;
ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
ret = i2c_smbus_write_byte_data(data->client, regs->int_ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
return ret;
}
/* On KX023 and KX022, route all used interrupts to INT1 for now */
if ((data->chipset == KX0231025 || data->chipset == KX0221020) && data->client->irq > 0) {
/* On KX023, route all used interrupts to INT1 for now */
if (data->info == &kx0231025_info && data->client->irq > 0) {
ret = i2c_smbus_write_byte_data(data->client, KX023_REG_INC4,
KX023_REG_INC4_DRDY1 |
KX023_REG_INC4_WUFI1);
@@ -601,20 +620,17 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
return 0;
}
#ifdef CONFIG_PM
static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data)
{
int i;
int idx = data->chipset;
const struct kx_odr_start_up_time *times;
for (i = 0; i < ARRAY_SIZE(odr_start_up_times[idx]); ++i) {
if (odr_start_up_times[idx][i].odr_bits == data->odr_bits)
return odr_start_up_times[idx][i].usec;
for (times = data->info->times; times->usec; times++) {
if (times->odr_bits == data->odr_bits)
return times->usec;
}
return KXCJK1013_MAX_STARTUP_TIME_US;
}
#endif
static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
{
@@ -639,18 +655,17 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
{
const struct kx_chipset_regs *regs = data->info->regs;
int ret;
ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_timer,
data->wake_dur);
ret = i2c_smbus_write_byte_data(data->client, regs->wake_timer, data->wake_dur);
if (ret < 0) {
dev_err(&data->client->dev,
"Error writing reg_wake_timer\n");
return ret;
}
ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_thres,
data->wake_thres);
ret = i2c_smbus_write_byte_data(data->client, regs->wake_thres, data->wake_thres);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_wake_thres\n");
return ret;
@@ -662,6 +677,7 @@ static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
bool status)
{
const struct kx_chipset_regs *regs = data->info->regs;
int ret;
enum kxcjk1013_mode store_mode;
@@ -678,7 +694,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
if (ret < 0)
return ret;
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
return ret;
@@ -689,13 +705,13 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN;
ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
ret = i2c_smbus_write_byte_data(data->client, regs->int_ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
return ret;
}
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -706,7 +722,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE;
ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -724,6 +740,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
bool status)
{
const struct kx_chipset_regs *regs = data->info->regs;
int ret;
enum kxcjk1013_mode store_mode;
@@ -736,7 +753,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
if (ret < 0)
return ret;
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
return ret;
@@ -747,13 +764,13 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN;
ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
ret = i2c_smbus_write_byte_data(data->client, regs->int_ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
return ret;
}
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -764,7 +781,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY;
ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -811,6 +828,7 @@ static int kxcjk1013_convert_odr_value(const struct kx_odr_map *map,
static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
{
const struct kx_chipset_regs *regs = data->info->regs;
int ret;
enum kxcjk1013_mode store_mode;
const struct kx_odr_map *odr_setting;
@@ -819,7 +837,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
if (ret < 0)
return ret;
if (data->chipset == KXTF9)
if (data->info == &kxtf9_info)
odr_setting = kxcjk1013_find_odr_value(kxtf9_samp_freq_table,
ARRAY_SIZE(kxtf9_samp_freq_table),
val, val2);
@@ -836,7 +854,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(data->client, data->regs->data_ctrl,
ret = i2c_smbus_write_byte_data(data->client, regs->data_ctrl,
odr_setting->odr_bits);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing data_ctrl\n");
@@ -845,7 +863,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
data->odr_bits = odr_setting->odr_bits;
ret = i2c_smbus_write_byte_data(data->client, data->regs->wuf_ctrl,
ret = i2c_smbus_write_byte_data(data->client, regs->wuf_ctrl,
odr_setting->wuf_bits);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl2\n");
@@ -863,7 +881,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
static int kxcjk1013_get_odr(struct kxcjk1013_data *data, int *val, int *val2)
{
if (data->chipset == KXTF9)
if (data->info == &kxtf9_info)
return kxcjk1013_convert_odr_value(kxtf9_samp_freq_table,
ARRAY_SIZE(kxtf9_samp_freq_table),
data->odr_bits, val, val2);
@@ -1063,7 +1081,7 @@ static int kxcjk1013_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
struct kxcjk1013_data *data = iio_priv(indio_dev);
int ret;
@@ -1130,7 +1148,7 @@ static ssize_t kxcjk1013_get_samp_freq_avail(struct device *dev,
struct kxcjk1013_data *data = iio_priv(indio_dev);
const char *str;
if (data->chipset == KXTF9)
if (data->info == &kxtf9_info)
str = kxtf9_samp_freq_avail;
else
str = kxcjk1013_samp_freq_avail;
@@ -1207,7 +1225,7 @@ static const struct iio_buffer_setup_ops kxcjk1013_buffer_setup_ops = {
.postdisable = kxcjk1013_buffer_postdisable,
};
static const struct iio_info kxcjk1013_info = {
static const struct iio_info kxcjk1013_iio_info = {
.attrs = &kxcjk1013_attrs_group,
.read_raw = kxcjk1013_read_raw,
.write_raw = kxcjk1013_write_raw,
@@ -1247,9 +1265,10 @@ static void kxcjk1013_trig_reen(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct kxcjk1013_data *data = iio_priv(indio_dev);
const struct kx_chipset_regs *regs = data->info->regs;
int ret;
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel);
ret = i2c_smbus_read_byte_data(data->client, regs->int_rel);
if (ret < 0)
dev_err(&data->client->dev, "Error reading reg_int_rel\n");
}
@@ -1301,8 +1320,9 @@ static const struct iio_trigger_ops kxcjk1013_trigger_ops = {
static void kxcjk1013_report_motion_event(struct iio_dev *indio_dev)
{
struct kxcjk1013_data *data = iio_priv(indio_dev);
const struct kx_chipset_regs *regs = data->info->regs;
int ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src2);
int ret = i2c_smbus_read_byte_data(data->client, regs->int_src2);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_src2\n");
return;
@@ -1367,16 +1387,17 @@ static irqreturn_t kxcjk1013_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct kxcjk1013_data *data = iio_priv(indio_dev);
const struct kx_chipset_regs *regs = data->info->regs;
int ret;
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src1);
ret = i2c_smbus_read_byte_data(data->client, regs->int_src1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_src1\n");
goto ack_intr;
}
if (ret & KXCJK1013_REG_INT_SRC1_BIT_WUFS) {
if (data->chipset == KXTF9)
if (data->info == &kxtf9_info)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
@@ -1392,7 +1413,7 @@ ack_intr:
if (data->dready_trigger_on)
return IRQ_HANDLED;
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel);
ret = i2c_smbus_read_byte_data(data->client, regs->int_rel);
if (ret < 0)
dev_err(&data->client->dev, "Error reading reg_int_rel\n");
@@ -1417,31 +1438,6 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private)
return IRQ_HANDLED;
}
static const char *kxcjk1013_match_acpi_device(struct device *dev,
enum kx_chipset *chipset,
enum kx_acpi_type *acpi_type,
const char **label)
{
const struct acpi_device_id *id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return NULL;
if (strcmp(id->id, "SMO8500") == 0) {
*acpi_type = ACPI_SMO8500;
} else if (strcmp(id->id, "KIOX010A") == 0) {
*acpi_type = ACPI_KIOX010A;
*label = "accel-display";
} else if (strcmp(id->id, "KIOX020A") == 0) {
*label = "accel-base";
}
*chipset = (enum kx_chipset)id->driver_data;
return dev_name(dev);
}
static int kxcjk1013_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
@@ -1449,6 +1445,7 @@ static int kxcjk1013_probe(struct i2c_client *client)
struct kxcjk1013_data *data;
struct iio_dev *indio_dev;
struct kxcjk_1013_platform_data *pdata;
const void *ddata = NULL;
const char *name;
int ret;
@@ -1489,32 +1486,18 @@ static int kxcjk1013_probe(struct i2c_client *client)
msleep(20);
if (id) {
data->chipset = (enum kx_chipset)(id->driver_data);
name = id->name;
} else if (ACPI_HANDLE(&client->dev)) {
name = kxcjk1013_match_acpi_device(&client->dev,
&data->chipset,
&data->acpi_type,
&indio_dev->label);
} else
return -ENODEV;
switch (data->chipset) {
case KXCJK1013:
case KXCJ91008:
case KXTJ21009:
data->regs = &kxcjk1013_regs;
break;
case KXTF9:
data->regs = &kxtf9_regs;
break;
case KX0221020:
case KX0231025:
data->regs = &kx0231025_regs;
break;
default:
return -EINVAL;
data->info = (const struct kx_chipset_info *)(id->driver_data);
} else {
name = iio_get_acpi_device_name_and_data(&client->dev, &ddata);
data->info = ddata;
if (data->info == &kxcj91008_kiox010a_info)
indio_dev->label = "accel-display";
else if (data->info == &kxcj91008_kiox020a_info)
indio_dev->label = "accel-base";
}
if (!name)
return -ENODEV;
ret = kxcjk1013_chip_init(data);
if (ret < 0)
@@ -1527,9 +1510,9 @@ static int kxcjk1013_probe(struct i2c_client *client)
indio_dev->available_scan_masks = kxcjk1013_scan_masks;
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &kxcjk1013_info;
indio_dev->info = &kxcjk1013_iio_info;
if (client->irq > 0 && data->acpi_type != ACPI_SMO8500) {
if (client->irq > 0 && data->info->acpi_type != ACPI_SMO8500) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
kxcjk1013_data_rdy_trig_poll,
kxcjk1013_event_handler,
@@ -1637,7 +1620,6 @@ static void kxcjk1013_remove(struct i2c_client *client)
mutex_unlock(&data->mutex);
}
#ifdef CONFIG_PM_SLEEP
static int kxcjk1013_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -1665,9 +1647,7 @@ static int kxcjk1013_resume(struct device *dev)
return ret;
}
#endif
#ifdef CONFIG_PM
static int kxcjk1013_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -1701,44 +1681,56 @@ static int kxcjk1013_runtime_resume(struct device *dev)
return 0;
}
#endif
static const struct dev_pm_ops kxcjk1013_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(kxcjk1013_suspend, kxcjk1013_resume)
SET_RUNTIME_PM_OPS(kxcjk1013_runtime_suspend,
kxcjk1013_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(kxcjk1013_suspend, kxcjk1013_resume)
RUNTIME_PM_OPS(kxcjk1013_runtime_suspend, kxcjk1013_runtime_resume, NULL)
};
static const struct i2c_device_id kxcjk1013_id[] = {
{"kxcjk1013", KXCJK1013},
{"kxcj91008", KXCJ91008},
{"kxtj21009", KXTJ21009},
{"kxtf9", KXTF9},
{"kx022-1020", KX0221020},
{"kx023-1025", KX0231025},
{"SMO8500", KXCJ91008},
{}
{ "kxcjk1013", (kernel_ulong_t)&kxcjk1013_info },
{ "kxcj91008", (kernel_ulong_t)&kxcj91008_info },
{ "kxtj21009", (kernel_ulong_t)&kxtj21009_info },
{ "kxtf9", (kernel_ulong_t)&kxtf9_info },
{ "kx023-1025", (kernel_ulong_t)&kx0231025_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, kxcjk1013_id);
static const struct of_device_id kxcjk1013_of_match[] = {
{ .compatible = "kionix,kxcjk1013", },
{ .compatible = "kionix,kxcj91008", },
{ .compatible = "kionix,kxtj21009", },
{ .compatible = "kionix,kxtf9", },
{ .compatible = "kionix,kx022-1020", },
{ .compatible = "kionix,kx023-1025", },
{ .compatible = "kionix,kxcjk1013", &kxcjk1013_info },
{ .compatible = "kionix,kxcj91008", &kxcj91008_info },
{ .compatible = "kionix,kxtj21009", &kxtj21009_info },
{ .compatible = "kionix,kxtf9", &kxtf9_info },
{ .compatible = "kionix,kx023-1025", &kx0231025_info },
{ }
};
MODULE_DEVICE_TABLE(of, kxcjk1013_of_match);
static const struct acpi_device_id kx_acpi_match[] = {
{ "KIOX0008", (kernel_ulong_t)&kxcj91008_info },
{ "KIOX0009", (kernel_ulong_t)&kxtj21009_info },
{ "KIOX000A", (kernel_ulong_t)&kxcj91008_info },
/* KXCJ91008 in the display of a yoga 2-in-1 */
{ "KIOX010A", (kernel_ulong_t)&kxcj91008_kiox010a_info },
/* KXCJ91008 in the base of a yoga 2-in-1 */
{ "KIOX020A", (kernel_ulong_t)&kxcj91008_kiox020a_info },
{ "KXCJ1008", (kernel_ulong_t)&kxcj91008_info },
{ "KXCJ1013", (kernel_ulong_t)&kxcjk1013_info },
{ "KXCJ9000", (kernel_ulong_t)&kxcj91008_info },
{ "KXJ2109", (kernel_ulong_t)&kxtj21009_info },
{ "KXTJ1009", (kernel_ulong_t)&kxtj21009_info },
{ "SMO8500", (kernel_ulong_t)&kxcj91008_smo8500_info },
{ }
};
MODULE_DEVICE_TABLE(acpi, kx_acpi_match);
static struct i2c_driver kxcjk1013_driver = {
.driver = {
.name = KXCJK1013_DRV_NAME,
.acpi_match_table = ACPI_PTR(kx_acpi_match),
.acpi_match_table = kx_acpi_match,
.of_match_table = kxcjk1013_of_match,
.pm = &kxcjk1013_pm_ops,
.pm = pm_ptr(&kxcjk1013_pm_ops),
},
.probe = kxcjk1013_probe,
.remove = kxcjk1013_remove,

View File

@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/bitops.h>
@@ -215,7 +216,7 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p)
*/
struct {
__be16 chan[4];
s64 ts __aligned(8);
aligned_s64 ts;
} hw_values;
int ret;

View File

@@ -19,6 +19,7 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/types.h>
#include "mma7455.h"
@@ -58,7 +59,7 @@ struct mma7455_data {
*/
struct {
__le16 channels[3];
s64 ts __aligned(8);
aligned_s64 ts;
} scan;
};

View File

@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
#define MMA8452_STATUS 0x00
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
@@ -115,7 +116,7 @@ struct mma8452_data {
/* Ensure correct alignment of time stamp when present */
struct {
__be16 channels[3];
s64 ts __aligned(8);
aligned_s64 ts;
} buffer;
};
@@ -973,7 +974,7 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
struct mma8452_data *data = iio_priv(indio_dev);
int val, ret;

View File

@@ -4,11 +4,11 @@
* Copyright (c) 2014, Intel Corporation.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/iio.h>
@@ -45,7 +45,7 @@ enum mma9551_tilt_axis {
struct mma9551_data {
struct i2c_client *client;
struct mutex mutex;
int event_enabled[3];
bool event_enabled[3];
int irqs[MMA9551_GPIO_COUNT];
};
@@ -162,7 +162,7 @@ static int mma9551_read_event_config(struct iio_dev *indio_dev,
static int mma9551_config_incli_event(struct iio_dev *indio_dev,
enum iio_modifier axis,
int state)
bool state)
{
struct mma9551_data *data = iio_priv(indio_dev);
enum mma9551_tilt_axis mma_axis;
@@ -174,7 +174,7 @@ static int mma9551_config_incli_event(struct iio_dev *indio_dev,
if (data->event_enabled[mma_axis] == state)
return 0;
if (state == 0) {
if (!state) {
ret = mma9551_gpio_config(data->client,
(enum mma9551_gpio_pin)mma_axis,
MMA9551_APPID_NONE, 0, 0);
@@ -225,7 +225,7 @@ static int mma9551_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
struct mma9551_data *data = iio_priv(indio_dev);
int ret;
@@ -435,17 +435,6 @@ static int mma9551_gpio_probe(struct iio_dev *indio_dev)
return 0;
}
static const char *mma9551_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return NULL;
return dev_name(dev);
}
static int mma9551_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
@@ -464,8 +453,8 @@ static int mma9551_probe(struct i2c_client *client)
if (id)
name = id->name;
else if (ACPI_HANDLE(&client->dev))
name = mma9551_match_acpi_device(&client->dev);
else
name = iio_get_acpi_device_name(&client->dev);
ret = mma9551_init(data);
if (ret < 0)

View File

@@ -4,11 +4,11 @@
* Copyright (c) 2014, Intel Corporation.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
@@ -725,7 +725,8 @@ static int mma9553_read_event_config(struct iio_dev *indio_dev,
static int mma9553_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir, int state)
enum iio_event_direction dir,
bool state)
{
struct mma9553_data *data = iio_priv(indio_dev);
struct mma9553_event *event;
@@ -1030,9 +1031,9 @@ static irqreturn_t mma9553_event_handler(int irq, void *private)
if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) {
data->stepcnt = stepcnt;
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
IIO_EV_DIR_NONE,
IIO_EV_TYPE_CHANGE, 0, 0, 0),
IIO_UNMOD_EVENT_CODE(IIO_STEPS, 0,
IIO_EV_TYPE_CHANGE,
IIO_EV_DIR_NONE),
data->timestamp);
}
@@ -1041,20 +1042,18 @@ static irqreturn_t mma9553_event_handler(int irq, void *private)
/* ev_activity can be NULL if activity == ACTIVITY_UNKNOWN */
if (ev_prev_activity && ev_prev_activity->enabled)
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_ACTIVITY, 0,
ev_prev_activity->info->mod,
IIO_EV_DIR_FALLING,
IIO_EV_TYPE_THRESH, 0, 0,
0),
IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0,
ev_prev_activity->info->mod,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
data->timestamp);
if (ev_activity && ev_activity->enabled)
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_ACTIVITY, 0,
ev_activity->info->mod,
IIO_EV_DIR_RISING,
IIO_EV_TYPE_THRESH, 0, 0,
0),
IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0,
ev_activity->info->mod,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
data->timestamp);
}
mutex_unlock(&data->mutex);
@@ -1062,17 +1061,6 @@ static irqreturn_t mma9553_event_handler(int irq, void *private)
return IRQ_HANDLED;
}
static const char *mma9553_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return NULL;
return dev_name(dev);
}
static int mma9553_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
@@ -1091,9 +1079,9 @@ static int mma9553_probe(struct i2c_client *client)
if (id)
name = id->name;
else if (ACPI_HANDLE(&client->dev))
name = mma9553_match_acpi_device(&client->dev);
else
name = iio_get_acpi_device_name(&client->dev);
if (!name)
return -ENOSYS;
mutex_init(&data->mutex);

View File

@@ -34,6 +34,7 @@
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/string_choices.h>
#include <linux/types.h>
#include <linux/units.h>
#include <linux/iio/buffer.h>
@@ -893,7 +894,7 @@ static irqreturn_t msa311_buffer_thread(int irq, void *p)
__le16 axis;
struct {
__le16 channels[MSA311_SI_Z + 1];
s64 ts __aligned(8);
aligned_s64 ts;
} buf;
memset(&buf, 0, sizeof(buf));

View File

@@ -11,6 +11,7 @@
#include <linux/iio/iio.h>
#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/types.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/buffer.h>
@@ -69,7 +70,7 @@ struct mxc4005_data {
/* Ensure timestamp is naturally aligned */
struct {
__be16 chans[3];
s64 timestamp __aligned(8);
aligned_s64 timestamp;
} scan;
bool trigger_enabled;
unsigned int control;

View File

@@ -1158,7 +1158,7 @@ error_ret:
return ret;
}
static int sca3000_freefall_set_state(struct iio_dev *indio_dev, int state)
static int sca3000_freefall_set_state(struct iio_dev *indio_dev, bool state)
{
struct sca3000_state *st = iio_priv(indio_dev);
int ret;
@@ -1181,7 +1181,7 @@ static int sca3000_freefall_set_state(struct iio_dev *indio_dev, int state)
}
static int sca3000_motion_detect_set_state(struct iio_dev *indio_dev, int axis,
int state)
bool state)
{
struct sca3000_state *st = iio_priv(indio_dev);
int ret, ctrlval;
@@ -1253,7 +1253,7 @@ static int sca3000_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
struct sca3000_state *st = iio_priv(indio_dev);
int ret;

View File

@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -105,7 +106,7 @@ struct stk8312_data {
/* Ensure timestamp is naturally aligned */
struct {
s8 chans[3];
s64 timestamp __aligned(8);
aligned_s64 timestamp;
} scan;
};

View File

@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/types.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -94,7 +95,7 @@ struct stk8ba50_data {
/* Ensure timestamp is naturally aligned */
struct {
s16 chans[3];
s64 timetamp __aligned(8);
aligned_s64 timetamp;
} scan;
};

View File

@@ -226,9 +226,11 @@ config AD7606_IFACE_PARALLEL
tristate "Analog Devices AD7606 ADC driver with parallel interface support"
depends on HAS_IOPORT
select AD7606
select IIO_BACKEND
help
Say yes here to build parallel interface support for Analog Devices:
ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
It also support iio_backended devices for AD7606B.
To compile this driver as a module, choose M here: the
module will be called ad7606_par.
@@ -285,6 +287,18 @@ config AD7768_1
To compile this driver as a module, choose M here: the module will be
called ad7768-1.
config AD7779
tristate "Analog Devices AD7779 ADC driver"
depends on SPI
select CRC8
select IIO_BUFFER
help
Say yes here to build support for Analog Devices AD777X family
(AD7770, AD7771, AD7779) analog to digital converter (ADC).
To compile this driver as a module, choose M here: the module will be
called ad7779.
config AD7780
tristate "Analog Devices AD7780 and similar ADCs driver"
depends on SPI
@@ -1606,7 +1620,6 @@ config TWL4030_MADC
config TWL6030_GPADC
tristate "TWL6030 GPADC (General Purpose A/D Converter) Support"
depends on TWL4030_CORE
default n
help
Say yes here if you want support for the TWL6030/TWL6032 General
Purpose A/D Converter. This will add support for battery type

View File

@@ -28,6 +28,7 @@ obj-$(CONFIG_AD7606) += ad7606.o
obj-$(CONFIG_AD7625) += ad7625.o
obj-$(CONFIG_AD7766) += ad7766.o
obj-$(CONFIG_AD7768_1) += ad7768-1.o
obj-$(CONFIG_AD7779) += ad7779.o
obj-$(CONFIG_AD7780) += ad7780.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o

View File

@@ -639,7 +639,9 @@ static int ad4000_probe(struct spi_device *spi)
indio_dev->name = chip->dev_name;
indio_dev->num_channels = 1;
devm_mutex_init(dev, &st->lock);
ret = devm_mutex_init(dev, &st->lock);
if (ret)
return ret;
st->gain_milli = 1000;
if (chip->has_hardware_gain) {

View File

@@ -150,7 +150,8 @@ static int ad7091r_read_event_config(struct iio_dev *indio_dev,
static int ad7091r_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir, int state)
enum iio_event_direction dir,
bool state)
{
struct ad7091r_state *st = iio_priv(indio_dev);

View File

@@ -1394,6 +1394,9 @@ static int ad7192_probe(struct spi_device *spi)
st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI;
st->chip_info = spi_get_device_match_data(spi);
if (!st->chip_info)
return -ENODEV;
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = st->chip_info->info;

View File

@@ -822,17 +822,15 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, channels[i]) <=
AD7280A_CELL_VOLTAGE_6_REG) {
if (val >= st->cell_threshhigh) {
u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0,
IIO_EV_DIR_RISING,
IIO_EV_TYPE_THRESH,
0, 0, 0);
u64 tmp = IIO_DIFF_EVENT_CODE(IIO_VOLTAGE, 0, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING);
iio_push_event(indio_dev, tmp,
iio_get_time_ns(indio_dev));
} else if (val <= st->cell_threshlow) {
u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0,
IIO_EV_DIR_FALLING,
IIO_EV_TYPE_THRESH,
0, 0, 0);
u64 tmp = IIO_DIFF_EVENT_CODE(IIO_VOLTAGE, 0, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING);
iio_push_event(indio_dev, tmp,
iio_get_time_ns(indio_dev));
}

View File

@@ -269,7 +269,7 @@ static int ad7291_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
int ret = 0;
struct ad7291_chip_info *chip = iio_priv(indio_dev);

View File

@@ -13,6 +13,8 @@
* ad7381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7381-4.pdf
* ad7383/4-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-4-ad7384-4.pdf
* ad7386/7/8-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7386-4-7387-4-7388-4.pdf
* adaq4370-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4370-4.pdf
* adaq4380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4380-4.pdf
*/
#include <linux/align.h>
@@ -22,11 +24,14 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/units.h>
#include <linux/util_macros.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
@@ -36,6 +41,8 @@
#define MAX_NUM_CHANNELS 8
/* 2.5V internal reference voltage */
#define AD7380_INTERNAL_REF_MV 2500
/* 3.3V internal reference voltage for ADAQ */
#define ADAQ4380_INTERNAL_REF_MV 3300
/* reading and writing registers is more reliable at lower than max speed */
#define AD7380_REG_WR_SPEED_HZ 10000000
@@ -77,6 +84,13 @@
#define T_CONVERT_X_NS 500 /* xth conversion start time (oversampling) */
#define T_POWERUP_US 5000 /* Power up */
/*
* AD738x support several SDO lines to increase throughput, but driver currently
* supports only 1 SDO line (standard SPI transaction)
*/
#define AD7380_NUM_SDO_LINES 1
#define AD7380_DEFAULT_GAIN_MILLI 1000
struct ad7380_timing_specs {
const unsigned int t_csh_ns; /* CS minimum high time */
};
@@ -86,10 +100,12 @@ struct ad7380_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
unsigned int num_simult_channels;
bool has_hardware_gain;
bool has_mux;
const char * const *supplies;
unsigned int num_supplies;
bool external_ref_only;
bool adaq_internal_ref_only;
const char * const *vcm_supplies;
unsigned int num_vcm_supplies;
const unsigned long *available_scan_masks;
@@ -181,11 +197,12 @@ static const struct iio_scan_type ad7380_scan_type_16_u[] = {
},
};
#define AD7380_CHANNEL(index, bits, diff, sign) { \
#define _AD7380_CHANNEL(index, bits, diff, sign, gain) { \
.type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
((gain) ? BIT(IIO_CHAN_INFO_SCALE) : 0) | \
((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
.info_mask_shared_by_type = ((gain) ? 0 : BIT(IIO_CHAN_INFO_SCALE)) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.info_mask_shared_by_type_available = \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
@@ -199,6 +216,12 @@ static const struct iio_scan_type ad7380_scan_type_16_u[] = {
.num_ext_scan_type = ARRAY_SIZE(ad7380_scan_type_##bits##_##sign), \
}
#define AD7380_CHANNEL(index, bits, diff, sign) \
_AD7380_CHANNEL(index, bits, diff, sign, false)
#define ADAQ4380_CHANNEL(index, bits, diff, sign) \
_AD7380_CHANNEL(index, bits, diff, sign, true)
#define DEFINE_AD7380_2_CHANNEL(name, bits, diff, sign) \
static const struct iio_chan_spec name[] = { \
AD7380_CHANNEL(0, bits, diff, sign), \
@@ -215,6 +238,15 @@ static const struct iio_chan_spec name[] = { \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
#define DEFINE_ADAQ4380_4_CHANNEL(name, bits, diff, sign) \
static const struct iio_chan_spec name[] = { \
ADAQ4380_CHANNEL(0, bits, diff, sign), \
ADAQ4380_CHANNEL(1, bits, diff, sign), \
ADAQ4380_CHANNEL(2, bits, diff, sign), \
ADAQ4380_CHANNEL(3, bits, diff, sign), \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
#define DEFINE_AD7380_8_CHANNEL(name, bits, diff, sign) \
static const struct iio_chan_spec name[] = { \
AD7380_CHANNEL(0, bits, diff, sign), \
@@ -233,6 +265,7 @@ DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1, s);
DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1, s);
DEFINE_AD7380_4_CHANNEL(ad7380_4_channels, 16, 1, s);
DEFINE_AD7380_4_CHANNEL(ad7381_4_channels, 14, 1, s);
DEFINE_ADAQ4380_4_CHANNEL(adaq4380_4_channels, 16, 1, s);
/* pseudo differential */
DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0, s);
DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0, s);
@@ -251,6 +284,10 @@ static const char * const ad7380_supplies[] = {
"vcc", "vlogic",
};
static const char * const adaq4380_supplies[] = {
"ldo", "vcc", "vlogic", "vs-p", "vs-n", "refin",
};
static const char * const ad7380_2_channel_vcm_supplies[] = {
"aina", "ainb",
};
@@ -341,6 +378,11 @@ static const int ad7380_oversampling_ratios[] = {
1, 2, 4, 8, 16, 32,
};
/* Gains stored as fractions of 1000 so they can be expressed by integers. */
static const int ad7380_gains[] = {
300, 600, 1000, 1600,
};
static const struct ad7380_chip_info ad7380_chip_info = {
.name = "ad7380",
.channels = ad7380_channels,
@@ -510,6 +552,32 @@ static const struct ad7380_chip_info ad7388_4_chip_info = {
.timing_specs = &ad7380_4_timing,
};
static const struct ad7380_chip_info adaq4370_4_chip_info = {
.name = "adaq4370-4",
.channels = adaq4380_4_channels,
.num_channels = ARRAY_SIZE(adaq4380_4_channels),
.num_simult_channels = 4,
.supplies = adaq4380_supplies,
.num_supplies = ARRAY_SIZE(adaq4380_supplies),
.adaq_internal_ref_only = true,
.has_hardware_gain = true,
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
};
static const struct ad7380_chip_info adaq4380_4_chip_info = {
.name = "adaq4380-4",
.channels = adaq4380_4_channels,
.num_channels = ARRAY_SIZE(adaq4380_4_channels),
.num_simult_channels = 4,
.supplies = adaq4380_supplies,
.num_supplies = ARRAY_SIZE(adaq4380_supplies),
.adaq_internal_ref_only = true,
.has_hardware_gain = true,
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
};
struct ad7380_state {
const struct ad7380_chip_info *chip_info;
struct spi_device *spi;
@@ -520,6 +588,7 @@ struct ad7380_state {
bool seq;
unsigned int vref_mv;
unsigned int vcm_mv[MAX_NUM_CHANNELS];
unsigned int gain_milli[MAX_NUM_CHANNELS];
/* xfers, message an buffer for reading sample data */
struct spi_transfer normal_xfer[2];
struct spi_message normal_msg;
@@ -649,7 +718,8 @@ static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch)
if (st->oversampling_ratio > 1)
xfer.delay.value = T_CONVERT_0_NS +
T_CONVERT_X_NS * (st->oversampling_ratio - 1);
T_CONVERT_X_NS * (st->oversampling_ratio - 1) *
st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES;
return spi_sync_transfer(st->spi, &xfer, 1);
}
@@ -672,7 +742,8 @@ static void ad7380_update_xfers(struct ad7380_state *st,
*/
if (st->oversampling_ratio > 1)
t_convert = T_CONVERT_0_NS + T_CONVERT_X_NS *
(st->oversampling_ratio - 1);
(st->oversampling_ratio - 1) *
st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES;
if (st->seq) {
xfer[0].delay.value = xfer[1].delay.value = t_convert;
@@ -868,8 +939,15 @@ static int ad7380_read_raw(struct iio_dev *indio_dev,
* * (2 × VREF) / 2^N, for differential chips
* * VREF / 2^N, for pseudo-differential chips
* where N is the ADC resolution (i.e realbits)
*
* The gain is stored as a fraction of 1000 and, as we need to
* divide vref_mv by the gain, we invert the gain/1000 fraction.
*/
*val = st->vref_mv;
if (st->chip_info->has_hardware_gain)
*val = mult_frac(st->vref_mv, MILLI,
st->gain_milli[chan->scan_index]);
else
*val = st->vref_mv;
*val2 = scan_type->realbits - chan->differential;
return IIO_VAL_FRACTIONAL_LOG2;
@@ -1021,17 +1099,19 @@ static int ad7380_init(struct ad7380_state *st, bool external_ref_en)
/* SPI 1-wire mode */
return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
AD7380_CONFIG2_SDO,
FIELD_PREP(AD7380_CONFIG2_SDO, 1));
FIELD_PREP(AD7380_CONFIG2_SDO,
AD7380_NUM_SDO_LINES));
}
static int ad7380_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct iio_dev *indio_dev;
struct ad7380_state *st;
bool external_ref_en;
int ret, i;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -1039,21 +1119,32 @@ static int ad7380_probe(struct spi_device *spi)
st->spi = spi;
st->chip_info = spi_get_device_match_data(spi);
if (!st->chip_info)
return dev_err_probe(&spi->dev, -EINVAL, "missing match data\n");
return dev_err_probe(dev, -EINVAL, "missing match data\n");
ret = devm_regulator_bulk_get_enable(&spi->dev, st->chip_info->num_supplies,
ret = devm_regulator_bulk_get_enable(dev, st->chip_info->num_supplies,
st->chip_info->supplies);
if (ret)
return dev_err_probe(&spi->dev, ret,
return dev_err_probe(dev, ret,
"Failed to enable power supplies\n");
fsleep(T_POWERUP_US);
if (st->chip_info->external_ref_only) {
ret = devm_regulator_get_enable_read_voltage(&spi->dev,
"refin");
if (st->chip_info->adaq_internal_ref_only) {
/*
* ADAQ chips use fixed internal reference but still
* require a specific reference supply to power it.
* "refin" is already enabled with other power supplies
* in bulk_get_enable().
*/
st->vref_mv = ADAQ4380_INTERNAL_REF_MV;
/* these chips don't have a register bit for this */
external_ref_en = false;
} else if (st->chip_info->external_ref_only) {
ret = devm_regulator_get_enable_read_voltage(dev, "refin");
if (ret < 0)
return dev_err_probe(&spi->dev, ret,
return dev_err_probe(dev, ret,
"Failed to get refin regulator\n");
st->vref_mv = ret / 1000;
@@ -1065,10 +1156,9 @@ static int ad7380_probe(struct spi_device *spi)
* If there is no REFIO supply, then it means that we are using
* the internal reference, otherwise REFIO is reference voltage.
*/
ret = devm_regulator_get_enable_read_voltage(&spi->dev,
"refio");
ret = devm_regulator_get_enable_read_voltage(dev, "refio");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(&spi->dev, ret,
return dev_err_probe(dev, ret,
"Failed to get refio regulator\n");
external_ref_en = ret != -ENODEV;
@@ -1076,7 +1166,7 @@ static int ad7380_probe(struct spi_device *spi)
}
if (st->chip_info->num_vcm_supplies > ARRAY_SIZE(st->vcm_mv))
return dev_err_probe(&spi->dev, -EINVAL,
return dev_err_probe(dev, -EINVAL,
"invalid number of VCM supplies\n");
/*
@@ -1086,18 +1176,54 @@ static int ad7380_probe(struct spi_device *spi)
for (i = 0; i < st->chip_info->num_vcm_supplies; i++) {
const char *vcm = st->chip_info->vcm_supplies[i];
ret = devm_regulator_get_enable_read_voltage(&spi->dev, vcm);
ret = devm_regulator_get_enable_read_voltage(dev, vcm);
if (ret < 0)
return dev_err_probe(&spi->dev, ret,
return dev_err_probe(dev, ret,
"Failed to get %s regulator\n",
vcm);
st->vcm_mv[i] = ret / 1000;
}
st->regmap = devm_regmap_init(&spi->dev, NULL, st, &ad7380_regmap_config);
for (i = 0; i < MAX_NUM_CHANNELS; i++)
st->gain_milli[i] = AD7380_DEFAULT_GAIN_MILLI;
if (st->chip_info->has_hardware_gain) {
device_for_each_child_node_scoped(dev, node) {
unsigned int channel, gain;
int gain_idx;
ret = fwnode_property_read_u32(node, "reg", &channel);
if (ret)
return dev_err_probe(dev, ret,
"Failed to read reg property\n");
if (channel >= st->chip_info->num_channels - 1)
return dev_err_probe(dev, -EINVAL,
"Invalid channel number %i\n",
channel);
ret = fwnode_property_read_u32(node, "adi,gain-milli",
&gain);
if (ret && ret != -EINVAL)
return dev_err_probe(dev, ret,
"Failed to read gain for channel %i\n",
channel);
if (ret != -EINVAL) {
/*
* Match gain value from dt to one of supported
* gains
*/
gain_idx = find_closest(gain, ad7380_gains,
ARRAY_SIZE(ad7380_gains));
st->gain_milli[channel] = ad7380_gains[gain_idx];
}
}
}
st->regmap = devm_regmap_init(dev, NULL, st, &ad7380_regmap_config);
if (IS_ERR(st->regmap))
return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
return dev_err_probe(dev, PTR_ERR(st->regmap),
"failed to allocate register map\n");
/*
@@ -1148,7 +1274,7 @@ static int ad7380_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->available_scan_masks = st->chip_info->available_scan_masks;
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
ad7380_trigger_handler,
&ad7380_buffer_setup_ops);
@@ -1159,7 +1285,7 @@ static int ad7380_probe(struct spi_device *spi)
if (ret)
return ret;
return devm_iio_device_register(&spi->dev, indio_dev);
return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id ad7380_of_match_table[] = {
@@ -1177,6 +1303,8 @@ static const struct of_device_id ad7380_of_match_table[] = {
{ .compatible = "adi,ad7386-4", .data = &ad7386_4_chip_info },
{ .compatible = "adi,ad7387-4", .data = &ad7387_4_chip_info },
{ .compatible = "adi,ad7388-4", .data = &ad7388_4_chip_info },
{ .compatible = "adi,adaq4370-4", .data = &adaq4370_4_chip_info },
{ .compatible = "adi,adaq4380-4", .data = &adaq4380_4_chip_info },
{ }
};
@@ -1195,6 +1323,8 @@ static const struct spi_device_id ad7380_id_table[] = {
{ "ad7386-4", (kernel_ulong_t)&ad7386_4_chip_info },
{ "ad7387-4", (kernel_ulong_t)&ad7387_4_chip_info },
{ "ad7388-4", (kernel_ulong_t)&ad7388_4_chip_info },
{ "adaq4370-4", (kernel_ulong_t)&adaq4370_4_chip_info },
{ "adaq4380-4", (kernel_ulong_t)&adaq4380_4_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7380_id_table);

File diff suppressed because it is too large Load Diff

View File

@@ -61,6 +61,12 @@
#define AD7616_CHANNEL(num) AD7606_SW_CHANNEL(num, 16)
#define AD7606_BI_CHANNEL(num) \
AD760X_CHANNEL(num, 0, \
BIT(IIO_CHAN_INFO_SCALE), \
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 16)
struct ad7606_state;
typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st,
@@ -69,7 +75,10 @@ typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st,
/**
* struct ad7606_chip_info - chip specific information
* @channels: channel specification
* @max_samplerate: maximum supported samplerate
* @name device name
* @num_channels: number of channels
* @num_adc_channels the number of channels the ADC actually inputs.
* @scale_setup_cb: callback to setup the scales for each channel
* @oversampling_avail pointer to the array which stores the available
* oversampling ratios.
@@ -80,6 +89,9 @@ typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st,
*/
struct ad7606_chip_info {
const struct iio_chan_spec *channels;
unsigned int max_samplerate;
const char *name;
unsigned int num_adc_channels;
unsigned int num_channels;
ad7606_scale_setup_cb_t scale_setup_cb;
const unsigned int *oversampling_avail;
@@ -91,8 +103,6 @@ struct ad7606_chip_info {
/**
* 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
@@ -100,9 +110,7 @@ struct ad7606_chip_info {
*/
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];
const unsigned int (*scale_avail)[2];
unsigned int num_scales;
unsigned int range;
unsigned int reg_offset;
@@ -115,6 +123,7 @@ struct ad7606_chan_scale {
* @bops bus operations (SPI or parallel)
* @chan_scales scale configuration for channels
* @oversampling oversampling selection
* @cnvst_pwm pointer to the PWM device connected to the cnvst pin
* @base_address address from where to read data in parallel operation
* @sw_mode_en software mode enabled
* @oversampling_avail pointer to the array which stores the available
@@ -142,10 +151,12 @@ struct ad7606_state {
const struct ad7606_bus_ops *bops;
struct ad7606_chan_scale chan_scales[AD760X_MAX_CHANNELS];
unsigned int oversampling;
struct pwm_device *cnvst_pwm;
void __iomem *base_address;
bool sw_mode_en;
const unsigned int *oversampling_avail;
unsigned int num_os_ratios;
struct iio_backend *back;
int (*write_scale)(struct iio_dev *indio_dev, int ch, int val);
int (*write_os)(struct iio_dev *indio_dev, int val);
@@ -174,16 +185,21 @@ struct ad7606_state {
/**
* struct ad7606_bus_ops - driver bus operations
* @iio_backend_config function pointer for configuring the iio_backend for
* the compatibles that use it
* @read_block function pointer for reading blocks of data
* @sw_mode_config: pointer to a function which configured the device
* for software mode
* @reg_read function pointer for reading spi register
* @reg_write function pointer for writing spi register
* @write_mask function pointer for write spi register with mask
* @update_scan_mode function pointer for handling the calls to iio_info's update_scan
* mode when enabling/disabling channels.
* @rd_wr_cmd pointer to the function which calculates the spi address
*/
struct ad7606_bus_ops {
/* more methods added in future? */
int (*iio_backend_config)(struct device *dev, struct iio_dev *indio_dev);
int (*read_block)(struct device *dev, int num, void *data);
int (*sw_mode_config)(struct iio_dev *indio_dev);
int (*reg_read)(struct ad7606_state *st, unsigned int addr);
@@ -194,25 +210,37 @@ struct ad7606_bus_ops {
unsigned int addr,
unsigned long mask,
unsigned int val);
int (*update_scan_mode)(struct iio_dev *indio_dev, const unsigned long *scan_mask);
u16 (*rd_wr_cmd)(int addr, char isWriteOp);
};
/**
* struct ad7606_bus_info - agregate ad7606_chip_info and ad7606_bus_ops
* @chip_info entry in the table of chips that describes this device
* @bops bus operations (SPI or parallel)
*/
struct ad7606_bus_info {
const struct ad7606_chip_info *chip_info;
const struct ad7606_bus_ops *bops;
};
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
const char *name, unsigned int id,
const struct ad7606_chip_info *info,
const struct ad7606_bus_ops *bops);
int ad7606_reset(struct ad7606_state *st);
enum ad7606_supported_device_ids {
ID_AD7605_4,
ID_AD7606_8,
ID_AD7606_6,
ID_AD7606_4,
ID_AD7606B,
ID_AD7606C_16,
ID_AD7606C_18,
ID_AD7616,
};
extern const struct ad7606_chip_info ad7605_4_info;
extern const struct ad7606_chip_info ad7606_8_info;
extern const struct ad7606_chip_info ad7606_6_info;
extern const struct ad7606_chip_info ad7606_4_info;
extern const struct ad7606_chip_info ad7606b_info;
extern const struct ad7606_chip_info ad7606c_16_info;
extern const struct ad7606_chip_info ad7606c_18_info;
extern const struct ad7606_chip_info ad7607_info;
extern const struct ad7606_chip_info ad7608_info;
extern const struct ad7606_chip_info ad7609_info;
extern const struct ad7606_chip_info ad7616_info;
#ifdef CONFIG_PM_SLEEP
extern const struct dev_pm_ops ad7606_pm_ops;

View File

@@ -2,7 +2,8 @@
/*
* AD7606 Parallel Interface ADC driver
*
* Copyright 2011 Analog Devices Inc.
* Copyright 2011 - 2024 Analog Devices Inc.
* Copyright 2024 BayLibre SAS.
*/
#include <linux/err.h>
@@ -11,11 +12,85 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/types.h>
#include <linux/iio/backend.h>
#include <linux/iio/iio.h>
#include "ad7606.h"
static const struct iio_chan_spec ad7606b_bi_channels[] = {
AD7606_BI_CHANNEL(0),
AD7606_BI_CHANNEL(1),
AD7606_BI_CHANNEL(2),
AD7606_BI_CHANNEL(3),
AD7606_BI_CHANNEL(4),
AD7606_BI_CHANNEL(5),
AD7606_BI_CHANNEL(6),
AD7606_BI_CHANNEL(7),
};
static int ad7606_bi_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask)
{
struct ad7606_state *st = iio_priv(indio_dev);
unsigned int c, ret;
for (c = 0; c < indio_dev->num_channels; c++) {
if (test_bit(c, scan_mask))
ret = iio_backend_chan_enable(st->back, c);
else
ret = iio_backend_chan_disable(st->back, c);
if (ret)
return ret;
}
return 0;
}
static int ad7606_bi_setup_iio_backend(struct device *dev, struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
unsigned int ret, c;
struct iio_backend_data_fmt data = {
.sign_extend = true,
.enable = true,
};
st->back = devm_iio_backend_get(dev, NULL);
if (IS_ERR(st->back))
return PTR_ERR(st->back);
/* If the device is iio_backend powered the PWM is mandatory */
if (!st->cnvst_pwm)
return dev_err_probe(st->dev, -EINVAL,
"A PWM is mandatory when using backend.\n");
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;
for (c = 0; c < indio_dev->num_channels; c++) {
ret = iio_backend_data_format_set(st->back, c, &data);
if (ret)
return ret;
}
indio_dev->channels = ad7606b_bi_channels;
indio_dev->num_channels = 8;
return 0;
}
static const struct ad7606_bus_ops ad7606_bi_bops = {
.iio_backend_config = ad7606_bi_setup_iio_backend,
.update_scan_mode = ad7606_bi_update_scan_mode,
};
static int ad7606_par16_read_block(struct device *dev,
int count, void *buf)
{
@@ -89,12 +164,32 @@ static const struct ad7606_bus_ops ad7606_par8_bops = {
static int ad7606_par_probe(struct platform_device *pdev)
{
const struct platform_device_id *id = platform_get_device_id(pdev);
const struct ad7606_chip_info *chip_info;
const struct platform_device_id *id;
struct resource *res;
void __iomem *addr;
resource_size_t remap_size;
int irq;
/*
* If a firmware node is available (ACPI or DT), platform_device_id is null
* and we must use get_match_data.
*/
if (dev_fwnode(&pdev->dev)) {
chip_info = device_get_match_data(&pdev->dev);
if (device_property_present(&pdev->dev, "io-backends"))
/*
* If a backend is available ,call the core probe with backend
* bops, otherwise use the former bops.
*/
return ad7606_probe(&pdev->dev, 0, NULL,
chip_info,
&ad7606_bi_bops);
} else {
id = platform_get_device_id(pdev);
chip_info = (const struct ad7606_chip_info *)id->driver_data;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -105,26 +200,33 @@ static int ad7606_par_probe(struct platform_device *pdev)
remap_size = resource_size(res);
return ad7606_probe(&pdev->dev, irq, addr,
id->name, id->driver_data,
return ad7606_probe(&pdev->dev, irq, addr, chip_info,
remap_size > 1 ? &ad7606_par16_bops :
&ad7606_par8_bops);
}
static const struct platform_device_id ad7606_driver_ids[] = {
{ .name = "ad7605-4", .driver_data = ID_AD7605_4, },
{ .name = "ad7606-4", .driver_data = ID_AD7606_4, },
{ .name = "ad7606-6", .driver_data = ID_AD7606_6, },
{ .name = "ad7606-8", .driver_data = ID_AD7606_8, },
{ .name = "ad7605-4", .driver_data = (kernel_ulong_t)&ad7605_4_info, },
{ .name = "ad7606-4", .driver_data = (kernel_ulong_t)&ad7606_4_info, },
{ .name = "ad7606-6", .driver_data = (kernel_ulong_t)&ad7606_6_info, },
{ .name = "ad7606-8", .driver_data = (kernel_ulong_t)&ad7606_8_info, },
{ .name = "ad7606b", .driver_data = (kernel_ulong_t)&ad7606b_info, },
{ .name = "ad7607", .driver_data = (kernel_ulong_t)&ad7607_info, },
{ .name = "ad7608", .driver_data = (kernel_ulong_t)&ad7608_info, },
{ .name = "ad7609", .driver_data = (kernel_ulong_t)&ad7609_info, },
{ }
};
MODULE_DEVICE_TABLE(platform, ad7606_driver_ids);
static const struct of_device_id ad7606_of_match[] = {
{ .compatible = "adi,ad7605-4" },
{ .compatible = "adi,ad7606-4" },
{ .compatible = "adi,ad7606-6" },
{ .compatible = "adi,ad7606-8" },
{ .compatible = "adi,ad7605-4", .data = &ad7605_4_info },
{ .compatible = "adi,ad7606-4", .data = &ad7606_4_info },
{ .compatible = "adi,ad7606-6", .data = &ad7606_6_info },
{ .compatible = "adi,ad7606-8", .data = &ad7606_8_info },
{ .compatible = "adi,ad7606b", .data = &ad7606b_info },
{ .compatible = "adi,ad7607", .data = &ad7607_info },
{ .compatible = "adi,ad7608", .data = &ad7608_info },
{ .compatible = "adi,ad7609", .data = &ad7609_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad7606_of_match);
@@ -144,3 +246,4 @@ MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(IIO_AD7606);
MODULE_IMPORT_NS(IIO_BACKEND);

View File

@@ -132,6 +132,19 @@ static int ad7606_spi_read_block(struct device *dev,
return 0;
}
static int ad7606_spi_read_block14to16(struct device *dev,
int count, void *buf)
{
struct spi_device *spi = to_spi_device(dev);
struct spi_transfer xfer = {
.bits_per_word = 14,
.len = count * sizeof(u16),
.rx_buf = buf,
};
return spi_sync_transfer(spi, &xfer, 1);
}
static int ad7606_spi_read_block18to32(struct device *dev,
int count, void *buf)
{
@@ -325,6 +338,14 @@ static const struct ad7606_bus_ops ad7606_spi_bops = {
.read_block = ad7606_spi_read_block,
};
static const struct ad7606_bus_ops ad7607_spi_bops = {
.read_block = ad7606_spi_read_block14to16,
};
static const struct ad7606_bus_ops ad7608_spi_bops = {
.read_block = ad7606_spi_read_block18to32,
};
static const struct ad7606_bus_ops ad7616_spi_bops = {
.read_block = ad7606_spi_read_block,
.reg_read = ad7606_spi_reg_read,
@@ -334,7 +355,7 @@ static const struct ad7606_bus_ops ad7616_spi_bops = {
.sw_mode_config = ad7616_sw_mode_config,
};
static const struct ad7606_bus_ops ad7606B_spi_bops = {
static const struct ad7606_bus_ops ad7606b_spi_bops = {
.read_block = ad7606_spi_read_block,
.reg_read = ad7606_spi_reg_read,
.reg_write = ad7606_spi_reg_write,
@@ -352,54 +373,97 @@ static const struct ad7606_bus_ops ad7606c_18_spi_bops = {
.sw_mode_config = ad7606c_18_sw_mode_config,
};
static const struct ad7606_bus_info ad7605_4_bus_info = {
.chip_info = &ad7605_4_info,
.bops = &ad7606_spi_bops,
};
static const struct ad7606_bus_info ad7606_8_bus_info = {
.chip_info = &ad7606_8_info,
.bops = &ad7606_spi_bops,
};
static const struct ad7606_bus_info ad7606_6_bus_info = {
.chip_info = &ad7606_6_info,
.bops = &ad7606_spi_bops,
};
static const struct ad7606_bus_info ad7606_4_bus_info = {
.chip_info = &ad7606_4_info,
.bops = &ad7606_spi_bops,
};
static const struct ad7606_bus_info ad7606b_bus_info = {
.chip_info = &ad7606b_info,
.bops = &ad7606b_spi_bops,
};
static const struct ad7606_bus_info ad7606c_16_bus_info = {
.chip_info = &ad7606c_16_info,
.bops = &ad7606b_spi_bops,
};
static const struct ad7606_bus_info ad7606c_18_bus_info = {
.chip_info = &ad7606c_18_info,
.bops = &ad7606c_18_spi_bops,
};
static const struct ad7606_bus_info ad7607_bus_info = {
.chip_info = &ad7607_info,
.bops = &ad7607_spi_bops,
};
static const struct ad7606_bus_info ad7608_bus_info = {
.chip_info = &ad7608_info,
.bops = &ad7608_spi_bops,
};
static const struct ad7606_bus_info ad7609_bus_info = {
.chip_info = &ad7609_info,
.bops = &ad7608_spi_bops,
};
static const struct ad7606_bus_info ad7616_bus_info = {
.chip_info = &ad7616_info,
.bops = &ad7616_spi_bops,
};
static int ad7606_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
const struct ad7606_bus_ops *bops;
switch (id->driver_data) {
case ID_AD7616:
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;
}
const struct ad7606_bus_info *bus_info = spi_get_device_match_data(spi);
return ad7606_probe(&spi->dev, spi->irq, NULL,
id->name, id->driver_data,
bops);
bus_info->chip_info, bus_info->bops);
}
static const struct spi_device_id ad7606_id_table[] = {
{ "ad7605-4", ID_AD7605_4 },
{ "ad7606-4", ID_AD7606_4 },
{ "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 },
{ "ad7605-4", (kernel_ulong_t)&ad7605_4_bus_info },
{ "ad7606-4", (kernel_ulong_t)&ad7606_4_bus_info },
{ "ad7606-6", (kernel_ulong_t)&ad7606_6_bus_info },
{ "ad7606-8", (kernel_ulong_t)&ad7606_8_bus_info },
{ "ad7606b", (kernel_ulong_t)&ad7606b_bus_info },
{ "ad7606c-16", (kernel_ulong_t)&ad7606c_16_bus_info },
{ "ad7606c-18", (kernel_ulong_t)&ad7606c_18_bus_info },
{ "ad7607", (kernel_ulong_t)&ad7607_bus_info },
{ "ad7608", (kernel_ulong_t)&ad7608_bus_info },
{ "ad7609", (kernel_ulong_t)&ad7609_bus_info },
{ "ad7616", (kernel_ulong_t)&ad7616_bus_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7606_id_table);
static const struct of_device_id ad7606_of_match[] = {
{ .compatible = "adi,ad7605-4" },
{ .compatible = "adi,ad7606-4" },
{ .compatible = "adi,ad7606-6" },
{ .compatible = "adi,ad7606-8" },
{ .compatible = "adi,ad7606b" },
{ .compatible = "adi,ad7606c-16" },
{ .compatible = "adi,ad7606c-18" },
{ .compatible = "adi,ad7616" },
{ .compatible = "adi,ad7605-4", .data = &ad7605_4_bus_info },
{ .compatible = "adi,ad7606-4", .data = &ad7606_4_bus_info },
{ .compatible = "adi,ad7606-6", .data = &ad7606_6_bus_info },
{ .compatible = "adi,ad7606-8", .data = &ad7606_8_bus_info },
{ .compatible = "adi,ad7606b", .data = &ad7606b_bus_info },
{ .compatible = "adi,ad7606c-16", .data = &ad7606c_16_bus_info },
{ .compatible = "adi,ad7606c-18", .data = &ad7606c_18_bus_info },
{ .compatible = "adi,ad7607", .data = &ad7607_bus_info },
{ .compatible = "adi,ad7608", .data = &ad7608_bus_info },
{ .compatible = "adi,ad7609", .data = &ad7609_bus_info },
{ .compatible = "adi,ad7616", .data = &ad7616_bus_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad7606_of_match);

914
drivers/iio/adc/ad7779.c Normal file
View File

@@ -0,0 +1,914 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* AD7770, AD7771, AD7779 ADC
*
* Copyright 2023-2024 Analog Devices Inc.
*/
#include <linux/bitfield.h>
#include <linux/bitmap.h>
#include <linux/clk.h>
#include <linux/crc8.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/unaligned.h>
#include <linux/units.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#define AD7779_SPI_READ_CMD BIT(7)
#define AD7779_DISABLE_SD BIT(7)
#define AD7779_REG_CH_DISABLE 0x08
#define AD7779_REG_CH_SYNC_OFFSET(ch) (0x09 + (ch))
#define AD7779_REG_CH_CONFIG(ch) (0x00 + (ch))
#define AD7779_REG_GENERAL_USER_CONFIG_1 0x11
#define AD7779_REG_GENERAL_USER_CONFIG_2 0x12
#define AD7779_REG_GENERAL_USER_CONFIG_3 0x13
#define AD7779_REG_DOUT_FORMAT 0x14
#define AD7779_REG_ADC_MUX_CONFIG 0x15
#define AD7779_REG_GPIO_CONFIG 0x17
#define AD7779_REG_BUFFER_CONFIG_1 0x19
#define AD7779_REG_GLOBAL_MUX_CONFIG 0x16
#define AD7779_REG_BUFFER_CONFIG_2 0x1A
#define AD7779_REG_GPIO_DATA 0x18
#define AD7779_REG_CH_OFFSET_UPPER_BYTE(ch) (0x1C + (ch) * 6)
#define AD7779_REG_CH_OFFSET_LOWER_BYTE(ch) (0x1E + (ch) * 6)
#define AD7779_REG_CH_GAIN_UPPER_BYTE(ch) (0x1F + (ch) * 6)
#define AD7779_REG_CH_OFFSET_MID_BYTE(ch) (0x1D + (ch) * 6)
#define AD7779_REG_CH_GAIN_MID_BYTE(ch) (0x20 + (ch) * 6)
#define AD7779_REG_CH_ERR_REG(ch) (0x4C + (ch))
#define AD7779_REG_CH0_1_SAT_ERR 0x54
#define AD7779_REG_CH_GAIN_LOWER_BYTE(ch) (0x21 + (ch) * 6)
#define AD7779_REG_CH2_3_SAT_ERR 0x55
#define AD7779_REG_CH4_5_SAT_ERR 0x56
#define AD7779_REG_CH6_7_SAT_ERR 0x57
#define AD7779_REG_CHX_ERR_REG_EN 0x58
#define AD7779_REG_GEN_ERR_REG_1 0x59
#define AD7779_REG_GEN_ERR_REG_1_EN 0x5A
#define AD7779_REG_GEN_ERR_REG_2 0x5B
#define AD7779_REG_GEN_ERR_REG_2_EN 0x5C
#define AD7779_REG_STATUS_REG_1 0x5D
#define AD7779_REG_STATUS_REG_2 0x5E
#define AD7779_REG_STATUS_REG_3 0x5F
#define AD7779_REG_SRC_N_MSB 0x60
#define AD7779_REG_SRC_N_LSB 0x61
#define AD7779_REG_SRC_IF_MSB 0x62
#define AD7779_REG_SRC_IF_LSB 0x63
#define AD7779_REG_SRC_UPDATE 0x64
#define AD7779_FILTER_MSK BIT(6)
#define AD7779_MOD_POWERMODE_MSK BIT(6)
#define AD7779_MOD_PDB_REFOUT_MSK BIT(4)
#define AD7779_MOD_SPI_EN_MSK BIT(4)
#define AD7779_USRMOD_INIT_MSK GENMASK(6, 4)
/* AD7779_REG_DOUT_FORMAT */
#define AD7779_DOUT_FORMAT_MSK GENMASK(7, 6)
#define AD7779_DOUT_HEADER_FORMAT BIT(5)
#define AD7779_DCLK_CLK_DIV_MSK GENMASK(3, 1)
#define AD7779_REFMUX_CTRL_MSK GENMASK(7, 6)
#define AD7779_SPI_CRC_EN_MSK BIT(0)
#define AD7779_MAXCLK_LOWPOWER (4096 * HZ_PER_KHZ)
#define AD7779_NUM_CHANNELS 8
#define AD7779_RESET_BUF_SIZE 8
#define AD7779_CHAN_DATA_SIZE 4
#define AD7779_LOWPOWER_DIV 512
#define AD7779_HIGHPOWER_DIV 2048
#define AD7779_SINC3_MAXFREQ (16 * HZ_PER_KHZ)
#define AD7779_SINC5_MAXFREQ (128 * HZ_PER_KHZ)
#define AD7779_DEFAULT_SAMPLING_FREQ (8 * HZ_PER_KHZ)
#define AD7779_DEFAULT_SAMPLING_2LINE (4 * HZ_PER_KHZ)
#define AD7779_DEFAULT_SAMPLING_1LINE (2 * HZ_PER_KHZ)
#define AD7779_SPIMODE_MAX_SAMP_FREQ (16 * HZ_PER_KHZ)
#define GAIN_REL 0x555555
#define AD7779_FREQ_MSB_MSK GENMASK(15, 8)
#define AD7779_FREQ_LSB_MSK GENMASK(7, 0)
#define AD7779_UPPER GENMASK(23, 16)
#define AD7779_MID GENMASK(15, 8)
#define AD7779_LOWER GENMASK(7, 0)
#define AD7779_REG_MSK GENMASK(6, 0)
#define AD7779_CRC8_POLY 0x07
DECLARE_CRC8_TABLE(ad7779_crc8_table);
enum ad7779_filter {
AD7779_SINC3,
AD7779_SINC5,
};
enum ad7779_variant {
ad7770,
ad7771,
ad7779,
};
enum ad7779_power_mode {
AD7779_LOW_POWER,
AD7779_HIGH_POWER,
};
struct ad7779_chip_info {
const char *name;
struct iio_chan_spec const *channels;
};
struct ad7779_state {
struct spi_device *spi;
const struct ad7779_chip_info *chip_info;
struct clk *mclk;
struct iio_trigger *trig;
struct completion completion;
unsigned int sampling_freq;
enum ad7779_filter filter_enabled;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
struct {
u32 chans[8];
aligned_s64 timestamp;
} data __aligned(IIO_DMA_MINALIGN);
u32 spidata_tx[8];
u8 reg_rx_buf[3];
u8 reg_tx_buf[3];
u8 reset_buf[8];
};
static const char * const ad7779_filter_type[] = {
[AD7779_SINC3] = "sinc3",
[AD7779_SINC5] = "sinc5",
};
static const char * const ad7779_power_supplies[] = {
"avdd1", "avdd2", "avdd4",
};
static int ad7779_spi_read(struct ad7779_state *st, u8 reg, u8 *rbuf)
{
int ret;
u8 crc_buf[2];
u8 exp_crc;
struct spi_transfer t = {
.tx_buf = st->reg_tx_buf,
.rx_buf = st->reg_rx_buf,
};
st->reg_tx_buf[0] = AD7779_SPI_READ_CMD | FIELD_GET(AD7779_REG_MSK, reg);
st->reg_tx_buf[1] = 0;
if (reg == AD7779_REG_GEN_ERR_REG_1_EN) {
t.len = 2;
} else {
t.len = 3;
st->reg_tx_buf[2] = crc8(ad7779_crc8_table, st->reg_tx_buf,
t.len - 1, 0);
}
ret = spi_sync_transfer(st->spi, &t, 1);
if (ret)
return ret;
crc_buf[0] = AD7779_SPI_READ_CMD | FIELD_GET(AD7779_REG_MSK, reg);
crc_buf[1] = st->reg_rx_buf[1];
exp_crc = crc8(ad7779_crc8_table, crc_buf, ARRAY_SIZE(crc_buf), 0);
if (reg != AD7779_REG_GEN_ERR_REG_1_EN && exp_crc != st->reg_rx_buf[2]) {
dev_err(&st->spi->dev, "Bad CRC %x, expected %x",
st->reg_rx_buf[2], exp_crc);
return -EINVAL;
}
*rbuf = st->reg_rx_buf[1];
return 0;
}
static int ad7779_spi_write(struct ad7779_state *st, u8 reg, u8 val)
{
u8 length = 3;
st->reg_tx_buf[0] = FIELD_GET(AD7779_REG_MSK, reg);
st->reg_tx_buf[1] = val;
if (reg == AD7779_REG_GEN_ERR_REG_1_EN)
length = 2;
else
st->reg_tx_buf[2] = crc8(ad7779_crc8_table, st->reg_tx_buf,
length - 1, 0);
return spi_write(st->spi, st->reg_tx_buf, length);
}
static int ad7779_spi_write_mask(struct ad7779_state *st, u8 reg, u8 mask,
u8 val)
{
int ret;
u8 regval, data;
ret = ad7779_spi_read(st, reg, &data);
if (ret)
return ret;
regval = (data & ~mask) | (val & mask);
if (regval == data)
return 0;
return ad7779_spi_write(st, reg, regval);
}
static int ad7779_reg_access(struct iio_dev *indio_dev,
unsigned int reg,
unsigned int writeval,
unsigned int *readval)
{
struct ad7779_state *st = iio_priv(indio_dev);
u8 rval;
int ret;
if (readval) {
ret = ad7779_spi_read(st, reg, &rval);
*readval = rval;
return ret;
}
return ad7779_spi_write(st, reg, writeval);
}
static int ad7779_set_sampling_frequency(struct ad7779_state *st,
unsigned int sampling_freq)
{
int ret;
unsigned int dec;
unsigned int frac;
unsigned int div;
unsigned int decimal;
unsigned int freq_khz;
if (st->filter_enabled == AD7779_SINC3 &&
sampling_freq > AD7779_SINC3_MAXFREQ)
return -EINVAL;
if (st->filter_enabled == AD7779_SINC5 &&
sampling_freq > AD7779_SINC5_MAXFREQ)
return -EINVAL;
if (sampling_freq > AD7779_SPIMODE_MAX_SAMP_FREQ)
return -EINVAL;
div = AD7779_HIGHPOWER_DIV;
freq_khz = sampling_freq / HZ_PER_KHZ;
dec = div / freq_khz;
frac = div % freq_khz;
ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB,
FIELD_GET(AD7779_FREQ_MSB_MSK, dec));
if (ret)
return ret;
ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB,
FIELD_GET(AD7779_FREQ_LSB_MSK, dec));
if (ret)
return ret;
if (frac) {
/*
* In order to obtain the first three decimals of the decimation
* the initial number is multiplied with 10^3 prior to the
* division, then the original division result is subtracted and
* the number is divided by 10^3.
*/
decimal = ((mult_frac(div, KILO, freq_khz) - dec * KILO) << 16)
/ KILO;
ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB,
FIELD_GET(AD7779_FREQ_MSB_MSK, decimal));
if (ret)
return ret;
ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB,
FIELD_GET(AD7779_FREQ_LSB_MSK, decimal));
if (ret)
return ret;
} else {
ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB,
FIELD_GET(AD7779_FREQ_MSB_MSK, 0x0));
if (ret)
return ret;
ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB,
FIELD_GET(AD7779_FREQ_LSB_MSK, 0x0));
if (ret)
return ret;
}
ret = ad7779_spi_write(st, AD7779_REG_SRC_UPDATE, BIT(0));
if (ret)
return ret;
/* SRC update settling time */
fsleep(15);
ret = ad7779_spi_write(st, AD7779_REG_SRC_UPDATE, 0x0);
if (ret)
return ret;
/* SRC update settling time */
fsleep(15);
st->sampling_freq = sampling_freq;
return 0;
}
static int ad7779_get_filter(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan)
{
struct ad7779_state *st = iio_priv(indio_dev);
u8 temp;
int ret;
ret = ad7779_spi_read(st, AD7779_REG_GENERAL_USER_CONFIG_2, &temp);
if (ret)
return ret;
return FIELD_GET(AD7779_FILTER_MSK, temp);
}
static int ad7779_set_filter(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
unsigned int mode)
{
struct ad7779_state *st = iio_priv(indio_dev);
int ret;
ret = ad7779_spi_write_mask(st,
AD7779_REG_GENERAL_USER_CONFIG_2,
AD7779_FILTER_MSK,
FIELD_PREP(AD7779_FILTER_MSK, mode));
if (ret)
return ret;
ret = ad7779_set_sampling_frequency(st, st->sampling_freq);
if (ret)
return ret;
st->filter_enabled = mode;
return 0;
}
static int ad7779_get_calibscale(struct ad7779_state *st, int channel)
{
int ret;
u8 calibscale[3];
ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_LOWER_BYTE(channel),
&calibscale[0]);
if (ret)
return ret;
ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_MID_BYTE(channel),
&calibscale[1]);
if (ret)
return ret;
ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_UPPER_BYTE(channel),
&calibscale[2]);
if (ret)
return ret;
return get_unaligned_be24(calibscale);
}
static int ad7779_set_calibscale(struct ad7779_state *st, int channel, int val)
{
int ret;
unsigned int gain;
u8 gain_bytes[3];
/*
* The gain value is relative to 0x555555, which represents a gain of 1
*/
gain = DIV_ROUND_CLOSEST_ULL((u64)val * 5592405LL, MEGA);
put_unaligned_be24(gain, gain_bytes);
ret = ad7779_spi_write(st, AD7779_REG_CH_GAIN_UPPER_BYTE(channel),
gain_bytes[0]);
if (ret)
return ret;
ret = ad7779_spi_write(st, AD7779_REG_CH_GAIN_MID_BYTE(channel),
gain_bytes[1]);
if (ret)
return ret;
return ad7779_spi_write(st, AD7779_REG_CH_GAIN_LOWER_BYTE(channel),
gain_bytes[2]);
}
static int ad7779_get_calibbias(struct ad7779_state *st, int channel)
{
int ret;
u8 calibbias[3];
ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_LOWER_BYTE(channel),
&calibbias[0]);
if (ret)
return ret;
ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_MID_BYTE(channel),
&calibbias[1]);
if (ret)
return ret;
ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_UPPER_BYTE(channel),
&calibbias[2]);
if (ret)
return ret;
return get_unaligned_be24(calibbias);
}
static int ad7779_set_calibbias(struct ad7779_state *st, int channel, int val)
{
int ret;
u8 calibbias[3];
put_unaligned_be24(val, calibbias);
ret = ad7779_spi_write(st, AD7779_REG_CH_OFFSET_UPPER_BYTE(channel),
calibbias[0]);
if (ret)
return ret;
ret = ad7779_spi_write(st, AD7779_REG_CH_OFFSET_MID_BYTE(channel),
calibbias[1]);
if (ret)
return ret;
return ad7779_spi_write(st, AD7779_REG_CH_OFFSET_LOWER_BYTE(channel),
calibbias[2]);
}
static int ad7779_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct ad7779_state *st = iio_priv(indio_dev);
int ret;
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
switch (mask) {
case IIO_CHAN_INFO_CALIBSCALE:
ret = ad7779_get_calibscale(st, chan->channel);
if (ret < 0)
return ret;
*val = ret;
*val2 = GAIN_REL;
return IIO_VAL_FRACTIONAL;
case IIO_CHAN_INFO_CALIBBIAS:
ret = ad7779_get_calibbias(st, chan->channel);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = st->sampling_freq;
if (*val < 0)
return -EINVAL;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
unreachable();
}
static int ad7779_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
{
struct ad7779_state *st = iio_priv(indio_dev);
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
switch (mask) {
case IIO_CHAN_INFO_CALIBSCALE:
return ad7779_set_calibscale(st, chan->channel, val2);
case IIO_CHAN_INFO_CALIBBIAS:
return ad7779_set_calibbias(st, chan->channel, val);
case IIO_CHAN_INFO_SAMP_FREQ:
return ad7779_set_sampling_frequency(st, val);
default:
return -EINVAL;
}
}
unreachable();
}
static int ad7779_buffer_preenable(struct iio_dev *indio_dev)
{
int ret;
struct ad7779_state *st = iio_priv(indio_dev);
ret = ad7779_spi_write_mask(st,
AD7779_REG_GENERAL_USER_CONFIG_3,
AD7779_MOD_SPI_EN_MSK,
FIELD_PREP(AD7779_MOD_SPI_EN_MSK, 1));
if (ret)
return ret;
/*
* DRDY output cannot be disabled at device level therefore we mask
* the irq at host end.
*/
enable_irq(st->spi->irq);
return 0;
}
static int ad7779_buffer_postdisable(struct iio_dev *indio_dev)
{
struct ad7779_state *st = iio_priv(indio_dev);
disable_irq(st->spi->irq);
return ad7779_spi_write(st, AD7779_REG_GENERAL_USER_CONFIG_3,
AD7779_DISABLE_SD);
}
static irqreturn_t ad7779_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7779_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer t = {
.rx_buf = st->data.chans,
.tx_buf = st->spidata_tx,
.len = AD7779_NUM_CHANNELS * AD7779_CHAN_DATA_SIZE,
};
st->spidata_tx[0] = AD7779_SPI_READ_CMD;
ret = spi_sync_transfer(st->spi, &t, 1);
if (ret) {
dev_err(&st->spi->dev, "SPI transfer error in IRQ handler");
goto exit_handler;
}
iio_push_to_buffers_with_timestamp(indio_dev, &st->data, pf->timestamp);
exit_handler:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ad7779_reset(struct iio_dev *indio_dev, struct gpio_desc *reset_gpio)
{
struct ad7779_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer t = {
.tx_buf = st->reset_buf,
.len = 8,
};
if (reset_gpio) {
gpiod_set_value(reset_gpio, 1);
/* Delay for reset to occur is 225 microseconds */
fsleep(230);
ret = 0;
} else {
memset(st->reset_buf, 0xff, sizeof(st->reset_buf));
ret = spi_sync_transfer(st->spi, &t, 1);
if (ret)
return ret;
}
/* Delay for reset to occur is 225 microseconds */
fsleep(230);
return ret;
}
static const struct iio_info ad7779_info = {
.read_raw = ad7779_read_raw,
.write_raw = ad7779_write_raw,
.debugfs_reg_access = &ad7779_reg_access,
};
static const struct iio_enum ad7779_filter_enum = {
.items = ad7779_filter_type,
.num_items = ARRAY_SIZE(ad7779_filter_type),
.get = ad7779_get_filter,
.set = ad7779_set_filter,
};
static const struct iio_chan_spec_ext_info ad7779_ext_filter[] = {
IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ad7779_filter_enum),
IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL,
&ad7779_filter_enum),
{ }
};
#define AD777x_CHAN_S(index, _ext_info) \
{ \
.type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_CALIBSCALE) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
.address = (index), \
.indexed = 1, \
.channel = (index), \
.scan_index = (index), \
.ext_info = (_ext_info), \
.scan_type = { \
.sign = 's', \
.realbits = 24, \
.storagebits = 32, \
.endianness = IIO_BE, \
}, \
}
#define AD777x_CHAN_NO_FILTER_S(index) \
AD777x_CHAN_S(index, NULL)
#define AD777x_CHAN_FILTER_S(index) \
AD777x_CHAN_S(index, ad7779_ext_filter)
static const struct iio_chan_spec ad7779_channels[] = {
AD777x_CHAN_NO_FILTER_S(0),
AD777x_CHAN_NO_FILTER_S(1),
AD777x_CHAN_NO_FILTER_S(2),
AD777x_CHAN_NO_FILTER_S(3),
AD777x_CHAN_NO_FILTER_S(4),
AD777x_CHAN_NO_FILTER_S(5),
AD777x_CHAN_NO_FILTER_S(6),
AD777x_CHAN_NO_FILTER_S(7),
IIO_CHAN_SOFT_TIMESTAMP(8),
};
static const struct iio_chan_spec ad7779_channels_filter[] = {
AD777x_CHAN_FILTER_S(0),
AD777x_CHAN_FILTER_S(1),
AD777x_CHAN_FILTER_S(2),
AD777x_CHAN_FILTER_S(3),
AD777x_CHAN_FILTER_S(4),
AD777x_CHAN_FILTER_S(5),
AD777x_CHAN_FILTER_S(6),
AD777x_CHAN_FILTER_S(7),
IIO_CHAN_SOFT_TIMESTAMP(8),
};
static const struct iio_buffer_setup_ops ad7779_buffer_setup_ops = {
.preenable = ad7779_buffer_preenable,
.postdisable = ad7779_buffer_postdisable,
};
static const struct iio_trigger_ops ad7779_trigger_ops = {
.validate_device = iio_trigger_validate_own_device,
};
static int ad7779_conf(struct ad7779_state *st, struct gpio_desc *start_gpio)
{
int ret;
ret = ad7779_spi_write_mask(st, AD7779_REG_GEN_ERR_REG_1_EN,
AD7779_SPI_CRC_EN_MSK,
FIELD_PREP(AD7779_SPI_CRC_EN_MSK, 1));
if (ret)
return ret;
ret = ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1,
AD7779_USRMOD_INIT_MSK,
FIELD_PREP(AD7779_USRMOD_INIT_MSK, 5));
if (ret)
return ret;
ret = ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT,
AD7779_DCLK_CLK_DIV_MSK,
FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 1));
if (ret)
return ret;
ret = ad7779_spi_write_mask(st, AD7779_REG_ADC_MUX_CONFIG,
AD7779_REFMUX_CTRL_MSK,
FIELD_PREP(AD7779_REFMUX_CTRL_MSK, 1));
if (ret)
return ret;
ret = ad7779_set_sampling_frequency(st, AD7779_DEFAULT_SAMPLING_FREQ);
if (ret)
return ret;
gpiod_set_value(start_gpio, 0);
/* Start setup time */
fsleep(15);
gpiod_set_value(start_gpio, 1);
/* Start setup time */
fsleep(15);
gpiod_set_value(start_gpio, 0);
/* Start setup time */
fsleep(15);
return 0;
}
static int ad7779_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ad7779_state *st;
struct gpio_desc *reset_gpio, *start_gpio;
struct device *dev = &spi->dev;
int ret = -EINVAL;
if (!spi->irq)
return dev_err_probe(dev, ret, "DRDY irq not present\n");
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
ret = devm_regulator_bulk_get_enable(dev,
ARRAY_SIZE(ad7779_power_supplies),
ad7779_power_supplies);
if (ret)
return dev_err_probe(dev, ret,
"failed to get and enable supplies\n");
st->mclk = devm_clk_get_enabled(dev, "mclk");
if (IS_ERR(st->mclk))
return PTR_ERR(st->mclk);
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(reset_gpio))
return PTR_ERR(reset_gpio);
start_gpio = devm_gpiod_get(dev, "start", GPIOD_OUT_HIGH);
if (IS_ERR(start_gpio))
return PTR_ERR(start_gpio);
crc8_populate_msb(ad7779_crc8_table, AD7779_CRC8_POLY);
st->spi = spi;
st->chip_info = spi_get_device_match_data(spi);
if (!st->chip_info)
return -ENODEV;
ret = ad7779_reset(indio_dev, reset_gpio);
if (ret)
return ret;
ret = ad7779_conf(st, start_gpio);
if (ret)
return ret;
indio_dev->name = st->chip_info->name;
indio_dev->info = &ad7779_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = ARRAY_SIZE(ad7779_channels);
st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
iio_device_id(indio_dev));
if (!st->trig)
return -ENOMEM;
st->trig->ops = &ad7779_trigger_ops;
iio_trigger_set_drvdata(st->trig, st);
ret = devm_request_irq(dev, spi->irq, iio_trigger_generic_data_rdy_poll,
IRQF_ONESHOT | IRQF_NO_AUTOEN, indio_dev->name,
st->trig);
if (ret)
return dev_err_probe(dev, ret, "request IRQ %d failed\n",
st->spi->irq);
ret = devm_iio_trigger_register(dev, st->trig);
if (ret)
return ret;
indio_dev->trig = iio_trigger_get(st->trig);
init_completion(&st->completion);
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
&iio_pollfunc_store_time,
&ad7779_trigger_handler,
&ad7779_buffer_setup_ops);
if (ret)
return ret;
ret = ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT,
AD7779_DCLK_CLK_DIV_MSK,
FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 7));
if (ret)
return ret;
return devm_iio_device_register(dev, indio_dev);
}
static int ad7779_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad7779_state *st = iio_priv(indio_dev);
return ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1,
AD7779_MOD_POWERMODE_MSK,
FIELD_PREP(AD7779_MOD_POWERMODE_MSK,
AD7779_LOW_POWER));
}
static int ad7779_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad7779_state *st = iio_priv(indio_dev);
return ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1,
AD7779_MOD_POWERMODE_MSK,
FIELD_PREP(AD7779_MOD_POWERMODE_MSK,
AD7779_HIGH_POWER));
}
static DEFINE_SIMPLE_DEV_PM_OPS(ad7779_pm_ops, ad7779_suspend, ad7779_resume);
static const struct ad7779_chip_info ad7770_chip_info = {
.name = "ad7770",
.channels = ad7779_channels,
};
static const struct ad7779_chip_info ad7771_chip_info = {
.name = "ad7771",
.channels = ad7779_channels_filter,
};
static const struct ad7779_chip_info ad7779_chip_info = {
.name = "ad7779",
.channels = ad7779_channels,
};
static const struct spi_device_id ad7779_id[] = {
{
.name = "ad7770",
.driver_data = (kernel_ulong_t)&ad7770_chip_info,
},
{
.name = "ad7771",
.driver_data = (kernel_ulong_t)&ad7771_chip_info,
},
{
.name = "ad7779",
.driver_data = (kernel_ulong_t)&ad7779_chip_info,
},
{ }
};
MODULE_DEVICE_TABLE(spi, ad7779_id);
static const struct of_device_id ad7779_of_table[] = {
{
.compatible = "adi,ad7770",
.data = &ad7770_chip_info,
},
{
.compatible = "adi,ad7771",
.data = &ad7771_chip_info,
},
{
.compatible = "adi,ad7779",
.data = &ad7779_chip_info,
},
{ }
};
MODULE_DEVICE_TABLE(of, ad7779_of_table);
static struct spi_driver ad7779_driver = {
.driver = {
.name = "ad7779",
.pm = pm_sleep_ptr(&ad7779_pm_ops),
.of_match_table = ad7779_of_table,
},
.probe = ad7779_probe,
.id_table = ad7779_id,
};
module_spi_driver(ad7779_driver);
MODULE_AUTHOR("Ramona Alexandra Nechita <ramona.nechita@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7779 ADC");
MODULE_LICENSE("GPL");

View File

@@ -406,7 +406,7 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
struct ad799x_state *st = iio_priv(indio_dev);
int ret;

View File

@@ -132,7 +132,7 @@ static int hi8435_read_event_config(struct iio_dev *idev,
static int hi8435_write_event_config(struct iio_dev *idev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir, int state)
enum iio_event_direction dir, bool state)
{
struct hi8435_priv *priv = iio_priv(idev);
int ret;

View File

@@ -944,7 +944,7 @@ error_ret:
static int max1363_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state)
enum iio_event_direction dir, bool state)
{
struct max1363_state *st = iio_priv(indio_dev);

View File

@@ -699,7 +699,8 @@ static int pac1921_read_event_config(struct iio_dev *indio_dev,
static int pac1921_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir, int state)
enum iio_event_direction dir,
bool state)
{
struct pac1921_priv *priv = iio_priv(indio_dev);
u8 ovf_bit;
@@ -1170,7 +1171,9 @@ static int pac1921_probe(struct i2c_client *client)
return dev_err_probe(dev, PTR_ERR(priv->regmap),
"Cannot initialize register map\n");
devm_mutex_init(dev, &priv->lock);
ret = devm_mutex_init(dev, &priv->lock);
if (ret)
return ret;
priv->dv_gain = PAC1921_DEFAULT_DV_GAIN;
priv->di_gain = PAC1921_DEFAULT_DI_GAIN;

View File

@@ -1507,7 +1507,7 @@ static int pac1934_probe(struct i2c_client *client)
indio_dev->name = pac1934_chip_config[ret].name;
}
if (acpi_match_device(dev->driver->acpi_match_table, dev))
if (is_acpi_device_node(dev_fwnode(dev)))
ret = pac1934_acpi_parse_channel_config(client, info);
else
/*

View File

@@ -676,7 +676,7 @@ static int palmas_gpadc_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
struct palmas_gpadc *adc = iio_priv(indio_dev);
int adc_chan = chan->channel;

View File

@@ -806,7 +806,7 @@ static int ads1015_disable_event_config(struct ads1015_data *data,
static int ads1015_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state)
enum iio_event_direction dir, bool state)
{
struct ads1015_data *data = iio_priv(indio_dev);
int ret;

View File

@@ -905,7 +905,7 @@ static int ams_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
struct ams *ams = iio_priv(indio_dev);
unsigned int alarm;

View File

@@ -121,7 +121,7 @@ int xadc_read_event_config(struct iio_dev *indio_dev,
int xadc_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state)
enum iio_event_direction dir, bool state)
{
unsigned int alarm = xadc_get_alarm_mask(chan);
struct xadc *xadc = iio_priv(indio_dev);

View File

@@ -25,7 +25,7 @@ int xadc_read_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir);
int xadc_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state);
enum iio_event_direction dir, bool state);
int xadc_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,

View File

@@ -6,9 +6,11 @@
#include <linux/unaligned.h>
#include <linux/bitfield.h>
#include <linux/cleanup.h>
#include <linux/crc8.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
@@ -59,7 +61,7 @@ struct ad74413r_state {
unsigned int num_gpo_gpios;
unsigned int num_comparator_gpios;
u32 sense_resistor_ohms;
int refin_reg_uv;
/*
* Synchronize consecutive operations when doing a one-shot
* conversion and when updating the ADC samples SPI message.
@@ -68,11 +70,9 @@ struct ad74413r_state {
const struct ad74413r_chip_info *chip_info;
struct spi_device *spi;
struct regulator *refin_reg;
struct regmap *regmap;
struct device *dev;
struct iio_trigger *trig;
struct gpio_desc *reset_gpio;
size_t adc_active_channels;
struct spi_message adc_samples_msg;
@@ -407,12 +407,16 @@ static int ad74413r_gpio_set_comp_config(struct gpio_chip *chip,
static int ad74413r_reset(struct ad74413r_state *st)
{
struct gpio_desc *reset_gpio;
int ret;
if (st->reset_gpio) {
gpiod_set_value_cansleep(st->reset_gpio, 1);
reset_gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpio))
return PTR_ERR(reset_gpio);
if (reset_gpio) {
fsleep(50);
gpiod_set_value_cansleep(st->reset_gpio, 0);
gpiod_set_value_cansleep(reset_gpio, 0);
return 0;
}
@@ -660,7 +664,7 @@ static int ad74413r_get_output_voltage_scale(struct ad74413r_state *st,
static int ad74413r_get_output_current_scale(struct ad74413r_state *st,
int *val, int *val2)
{
*val = regulator_get_voltage(st->refin_reg);
*val = st->refin_reg_uv;
*val2 = st->sense_resistor_ohms * AD74413R_DAC_CODE_MAX * 1000;
return IIO_VAL_FRACTIONAL;
@@ -861,19 +865,12 @@ static int ad74413r_get_single_adc_result(struct iio_dev *indio_dev,
unsigned int channel, int *val)
{
struct ad74413r_state *st = iio_priv(indio_dev);
int ret;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
mutex_lock(&st->lock);
ret = _ad74413r_get_single_adc_result(st, channel, val);
mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
return ret;
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
guard(mutex)(&st->lock);
return _ad74413r_get_single_adc_result(st, channel, val);
}
unreachable();
}
static void ad74413r_adc_to_resistance_result(int adc_result, int *val)
@@ -895,7 +892,7 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev,
unsigned int channel;
int ret = -EINVAL;
mutex_lock(&st->lock);
guard(mutex)(&st->lock);
spi_message_init(&st->adc_samples_msg);
st->adc_active_channels = 0;
@@ -903,11 +900,11 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev,
for_each_clear_bit(channel, active_scan_mask, AD74413R_CHANNEL_MAX) {
ret = ad74413r_set_adc_channel_enable(st, channel, false);
if (ret)
goto out;
return ret;
}
if (*active_scan_mask == 0)
goto out;
return ret;
/*
* The read select register is used to select which register's value
@@ -925,7 +922,7 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev,
for_each_set_bit(channel, active_scan_mask, AD74413R_CHANNEL_MAX) {
ret = ad74413r_set_adc_channel_enable(st, channel, true);
if (ret)
goto out;
return ret;
st->adc_active_channels++;
@@ -956,11 +953,7 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev,
xfer->cs_change = 0;
spi_message_add_tail(xfer, &st->adc_samples_msg);
out:
mutex_unlock(&st->lock);
return ret;
return 0;
}
static int ad74413r_buffer_postenable(struct iio_dev *indio_dev)
@@ -1347,11 +1340,6 @@ static int ad74413r_setup_gpios(struct ad74413r_state *st)
return 0;
}
static void ad74413r_regulator_disable(void *regulator)
{
regulator_disable(regulator);
}
static int ad74413r_probe(struct spi_device *spi)
{
struct ad74413r_state *st;
@@ -1370,7 +1358,10 @@ static int ad74413r_probe(struct spi_device *spi)
if (!st->chip_info)
return -EINVAL;
mutex_init(&st->lock);
ret = devm_mutex_init(st->dev, &st->lock);
if (ret)
return ret;
init_completion(&st->adc_data_completion);
st->regmap = devm_regmap_init(st->dev, NULL, st,
@@ -1378,23 +1369,11 @@ static int ad74413r_probe(struct spi_device *spi)
if (IS_ERR(st->regmap))
return PTR_ERR(st->regmap);
st->reset_gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(st->reset_gpio))
return PTR_ERR(st->reset_gpio);
st->refin_reg = devm_regulator_get(st->dev, "refin");
if (IS_ERR(st->refin_reg))
return dev_err_probe(st->dev, PTR_ERR(st->refin_reg),
"Failed to get refin regulator\n");
ret = regulator_enable(st->refin_reg);
if (ret)
return ret;
ret = devm_add_action_or_reset(st->dev, ad74413r_regulator_disable,
st->refin_reg);
if (ret)
return ret;
ret = devm_regulator_get_enable_read_voltage(st->dev, "refin");
if (ret < 0)
return dev_err_probe(st->dev, ret,
"Failed to get refin regulator voltage\n");
st->refin_reg_uv = ret;
st->sense_resistor_ohms = 100000000;
device_property_read_u32(st->dev, "shunt-resistor-micro-ohms",

View File

@@ -232,7 +232,7 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev,
static int ad7150_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir, int state)
enum iio_event_direction dir, bool state)
{
struct ad7150_chip_info *chip = iio_priv(indio_dev);
int ret = 0;

View File

@@ -50,6 +50,8 @@ config BME680
select REGMAP
select BME680_I2C if I2C
select BME680_SPI if SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Bosch Sensortec BME680 sensor with
temperature, pressure, humidity and gas sensing capability.

View File

@@ -2,6 +2,8 @@
#ifndef BME680_H_
#define BME680_H_
#include <linux/regmap.h>
#define BME680_REG_CHIP_ID 0xD0
#define BME680_CHIP_ID_VAL 0x61
#define BME680_REG_SOFT_RESET 0xE0
@@ -25,8 +27,6 @@
#define BME680_OSRS_TEMP_MASK GENMASK(7, 5)
#define BME680_OSRS_PRESS_MASK GENMASK(4, 2)
#define BME680_MODE_MASK GENMASK(1, 0)
#define BME680_MODE_FORCED 1
#define BME680_MODE_SLEEP 0
#define BME680_REG_CONFIG 0x75
#define BME680_FILTER_MASK GENMASK(4, 2)
@@ -42,6 +42,7 @@
#define BME680_RHRANGE_MASK GENMASK(5, 4)
#define BME680_REG_RES_HEAT_VAL 0x00
#define BME680_RSERROR_MASK GENMASK(7, 4)
#define BME680_REG_IDAC_HEAT_0 0x50
#define BME680_REG_RES_HEAT_0 0x5A
#define BME680_REG_GAS_WAIT_0 0x64
#define BME680_ADC_GAS_RES GENMASK(15, 6)
@@ -63,7 +64,11 @@
#define BME680_MEAS_TRIM_MASK GENMASK(24, 4)
#define BME680_STARTUP_TIME_US 5000
/* Datasheet Section 1.1, Table 1 */
#define BME680_STARTUP_TIME_US 2000
#define BME680_NUM_CHANNELS 4
#define BME680_NUM_BULK_READ_REGS 15
/* Calibration Parameters */
#define BME680_T2_LSB_REG 0x8A

View File

@@ -16,8 +16,11 @@
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/unaligned.h>
@@ -95,6 +98,19 @@ struct bme680_calib {
s8 range_sw_err;
};
/* values of CTRL_MEAS register */
enum bme680_op_mode {
BME680_MODE_SLEEP = 0,
BME680_MODE_FORCED = 1,
};
enum bme680_scan {
BME680_TEMP,
BME680_PRESS,
BME680_HUMID,
BME680_GAS,
};
struct bme680_data {
struct regmap *regmap;
struct bme680_calib bme680;
@@ -102,11 +118,17 @@ struct bme680_data {
u8 oversampling_temp;
u8 oversampling_press;
u8 oversampling_humid;
u8 preheat_curr_mA;
u16 heater_dur;
u16 heater_temp;
struct {
s32 chan[4];
aligned_s64 ts;
} scan;
union {
u8 buf[3];
u8 buf[BME680_NUM_BULK_READ_REGS];
unsigned int check;
__be16 be16;
u8 bme680_cal_buf_1[BME680_CALIB_RANGE_1_LEN];
@@ -138,22 +160,66 @@ EXPORT_SYMBOL_NS(bme680_regmap_config, IIO_BME680);
static const struct iio_chan_spec bme680_channels[] = {
{
.type = IIO_TEMP,
/* PROCESSED maintained for ABI backwards compatibility */
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
},
{
.type = IIO_PRESSURE,
/* PROCESSED maintained for ABI backwards compatibility */
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
.scan_index = 1,
.scan_type = {
.sign = 'u',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_CPU,
},
},
{
.type = IIO_HUMIDITYRELATIVE,
/* PROCESSED maintained for ABI backwards compatibility */
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
.scan_index = 2,
.scan_type = {
.sign = 'u',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_CPU,
},
},
{
.type = IIO_RESISTANCE,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.scan_index = 3,
.scan_type = {
.sign = 'u',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_CPU,
},
},
IIO_CHAN_SOFT_TIMESTAMP(4),
{
.type = IIO_CURRENT,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.output = 1,
.scan_index = -1,
},
};
@@ -224,7 +290,7 @@ static int bme680_read_calib(struct bme680_data *data,
calib->res_heat_val = data->bme680_cal_buf_3[RES_HEAT_VAL];
calib->res_heat_range = FIELD_GET(BME680_RHRANGE_MASK,
data->bme680_cal_buf_3[RES_HEAT_RANGE]);
data->bme680_cal_buf_3[RES_HEAT_RANGE]);
calib->range_sw_err = FIELD_GET(BME680_RSERROR_MASK,
data->bme680_cal_buf_3[RANGE_SW_ERR]);
@@ -438,19 +504,19 @@ static u32 bme680_compensate_gas(struct bme680_data *data, u16 gas_res_adc,
u32 calc_gas_res;
/* Look up table for the possible gas range values */
static const u32 lookupTable[16] = {2147483647u, 2147483647u,
2147483647u, 2147483647u, 2147483647u,
2126008810u, 2147483647u, 2130303777u,
2147483647u, 2147483647u, 2143188679u,
2136746228u, 2147483647u, 2126008810u,
2147483647u, 2147483647u};
static const u32 lookup_table[16] = {
2147483647u, 2147483647u, 2147483647u, 2147483647u,
2147483647u, 2126008810u, 2147483647u, 2130303777u,
2147483647u, 2147483647u, 2143188679u, 2136746228u,
2147483647u, 2126008810u, 2147483647u, 2147483647u
};
var1 = ((1340 + (5 * (s64) calib->range_sw_err)) *
((s64) lookupTable[gas_range])) >> 16;
var1 = ((1340LL + (5 * calib->range_sw_err)) *
(lookup_table[gas_range])) >> 16;
var2 = ((gas_res_adc << 15) - 16777216) + var1;
var3 = ((125000 << (15 - gas_range)) * var1) >> 9;
var3 += (var2 >> 1);
calc_gas_res = div64_s64(var3, (s64) var2);
calc_gas_res = div64_s64(var3, (s64)var2);
return calc_gas_res;
}
@@ -468,7 +534,7 @@ static u8 bme680_calc_heater_res(struct bme680_data *data, u16 temp)
if (temp > 400) /* Cap temperature */
temp = 400;
var1 = (((s32) BME680_AMB_TEMP * calib->par_gh3) / 1000) * 256;
var1 = (((s32)BME680_AMB_TEMP * calib->par_gh3) / 1000) * 256;
var2 = (calib->par_gh1 + 784) * (((((calib->par_gh2 + 154009) *
temp * 5) / 100)
+ 3276800) / 10);
@@ -502,23 +568,22 @@ static u8 bme680_calc_heater_dur(u16 dur)
return durval;
}
static int bme680_set_mode(struct bme680_data *data, bool mode)
/* Taken from datasheet, section 5.3.3 */
static u8 bme680_calc_heater_preheat_current(u8 curr)
{
return 8 * curr - 1;
}
static int bme680_set_mode(struct bme680_data *data, enum bme680_op_mode mode)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
if (mode) {
ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
BME680_MODE_MASK, BME680_MODE_FORCED);
if (ret < 0)
dev_err(dev, "failed to set forced mode\n");
} else {
ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
BME680_MODE_MASK, BME680_MODE_SLEEP);
if (ret < 0)
dev_err(dev, "failed to set sleep mode\n");
ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
BME680_MODE_MASK, mode);
if (ret < 0) {
dev_err(dev, "failed to set ctrl_meas register\n");
return ret;
}
return ret;
@@ -546,7 +611,7 @@ static int bme680_wait_for_eoc(struct bme680_data *data)
data->oversampling_humid) * 1936) + (477 * 4) +
(477 * 5) + 1000 + (data->heater_dur * 1000);
usleep_range(wait_eoc_us, wait_eoc_us + 100);
fsleep(wait_eoc_us);
ret = regmap_read(data->regmap, BME680_REG_MEAS_STAT_0, &data->check);
if (ret) {
@@ -571,9 +636,8 @@ static int bme680_chip_config(struct bme680_data *data)
int ret;
u8 osrs;
osrs = FIELD_PREP(
BME680_OSRS_HUMIDITY_MASK,
bme680_oversampling_to_reg(data->oversampling_humid));
osrs = FIELD_PREP(BME680_OSRS_HUMIDITY_MASK,
bme680_oversampling_to_reg(data->oversampling_humid));
/*
* Highly recommended to set oversampling of humidity before
* temperature/pressure oversampling.
@@ -587,8 +651,7 @@ static int bme680_chip_config(struct bme680_data *data)
/* IIR filter settings */
ret = regmap_update_bits(data->regmap, BME680_REG_CONFIG,
BME680_FILTER_MASK,
BME680_FILTER_COEFF_VAL);
BME680_FILTER_MASK, BME680_FILTER_COEFF_VAL);
if (ret < 0) {
dev_err(dev, "failed to write config register\n");
return ret;
@@ -609,14 +672,27 @@ static int bme680_chip_config(struct bme680_data *data)
return 0;
}
static int bme680_preheat_curr_config(struct bme680_data *data, u8 val)
{
struct device *dev = regmap_get_device(data->regmap);
u8 heatr_curr;
int ret;
heatr_curr = bme680_calc_heater_preheat_current(val);
ret = regmap_write(data->regmap, BME680_REG_IDAC_HEAT_0, heatr_curr);
if (ret < 0)
dev_err(dev, "failed to write idac_heat_0 register\n");
return ret;
}
static int bme680_gas_config(struct bme680_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
u8 heatr_res, heatr_dur;
/* Go to sleep */
ret = bme680_set_mode(data, false);
ret = bme680_set_mode(data, BME680_MODE_SLEEP);
if (ret < 0)
return ret;
@@ -638,6 +714,10 @@ static int bme680_gas_config(struct bme680_data *data)
return ret;
}
ret = bme680_preheat_curr_config(data, data->preheat_curr_mA);
if (ret)
return ret;
/* Enable the gas sensor and select heater profile set-point 0 */
ret = regmap_update_bits(data->regmap, BME680_REG_CTRL_GAS_1,
BME680_RUN_GAS_MASK | BME680_NB_CONV_MASK,
@@ -649,23 +729,20 @@ static int bme680_gas_config(struct bme680_data *data)
return ret;
}
static int bme680_read_temp(struct bme680_data *data, int *val)
static int bme680_read_temp(struct bme680_data *data, s16 *comp_temp)
{
int ret;
u32 adc_temp;
s16 comp_temp;
ret = bme680_read_temp_adc(data, &adc_temp);
if (ret)
return ret;
comp_temp = bme680_compensate_temp(data, adc_temp);
*val = comp_temp * 10; /* Centidegrees to millidegrees */
return IIO_VAL_INT;
*comp_temp = bme680_compensate_temp(data, adc_temp);
return 0;
}
static int bme680_read_press(struct bme680_data *data,
int *val, int *val2)
static int bme680_read_press(struct bme680_data *data, u32 *comp_press)
{
int ret;
u32 adc_press;
@@ -679,16 +756,14 @@ static int bme680_read_press(struct bme680_data *data,
if (ret)
return ret;
*val = bme680_compensate_press(data, adc_press, t_fine);
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
*comp_press = bme680_compensate_press(data, adc_press, t_fine);
return 0;
}
static int bme680_read_humid(struct bme680_data *data,
int *val, int *val2)
static int bme680_read_humid(struct bme680_data *data, u32 *comp_humidity)
{
int ret;
u32 adc_humidity, comp_humidity;
u32 adc_humidity;
s32 t_fine;
ret = bme680_get_t_fine(data, &t_fine);
@@ -699,15 +774,11 @@ static int bme680_read_humid(struct bme680_data *data,
if (ret)
return ret;
comp_humidity = bme680_compensate_humid(data, adc_humidity, t_fine);
*val = comp_humidity;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
*comp_humidity = bme680_compensate_humid(data, adc_humidity, t_fine);
return 0;
}
static int bme680_read_gas(struct bme680_data *data,
int *val)
static int bme680_read_gas(struct bme680_data *data, int *comp_gas_res)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
@@ -742,9 +813,8 @@ static int bme680_read_gas(struct bme680_data *data,
}
gas_range = FIELD_GET(BME680_GAS_RANGE_MASK, gas_regs_val);
*val = bme680_compensate_gas(data, adc_gas_res, gas_range);
return IIO_VAL_INT;
*comp_gas_res = bme680_compensate_gas(data, adc_gas_res, gas_range);
return 0;
}
static int bme680_read_raw(struct iio_dev *indio_dev,
@@ -752,12 +822,12 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct bme680_data *data = iio_priv(indio_dev);
int ret;
int chan_val, ret;
s16 temp_chan_val;
guard(mutex)(&data->lock);
/* set forced mode to trigger measurement */
ret = bme680_set_mode(data, true);
ret = bme680_set_mode(data, BME680_MODE_FORCED);
if (ret < 0)
return ret;
@@ -769,13 +839,77 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_TEMP:
return bme680_read_temp(data, val);
ret = bme680_read_temp(data, &temp_chan_val);
if (ret)
return ret;
*val = temp_chan_val * 10;
return IIO_VAL_INT;
case IIO_PRESSURE:
return bme680_read_press(data, val, val2);
ret = bme680_read_press(data, &chan_val);
if (ret)
return ret;
*val = chan_val;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
case IIO_HUMIDITYRELATIVE:
return bme680_read_humid(data, val, val2);
ret = bme680_read_humid(data, &chan_val);
if (ret)
return ret;
*val = chan_val;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
case IIO_RESISTANCE:
return bme680_read_gas(data, val);
ret = bme680_read_gas(data, &chan_val);
if (ret)
return ret;
*val = chan_val;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_TEMP:
ret = bme680_read_temp(data, (s16 *)&chan_val);
if (ret)
return ret;
*val = chan_val;
return IIO_VAL_INT;
case IIO_PRESSURE:
ret = bme680_read_press(data, &chan_val);
if (ret)
return ret;
*val = chan_val;
return IIO_VAL_INT;
case IIO_HUMIDITYRELATIVE:
ret = bme680_read_humid(data, &chan_val);
if (ret)
return ret;
*val = chan_val;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_TEMP:
*val = 10;
return IIO_VAL_INT;
case IIO_PRESSURE:
*val = 1;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
case IIO_HUMIDITYRELATIVE:
*val = 1;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
@@ -836,6 +970,15 @@ static int bme680_write_raw(struct iio_dev *indio_dev,
return bme680_chip_config(data);
}
case IIO_CHAN_INFO_PROCESSED:
{
switch (chan->type) {
case IIO_CURRENT:
return bme680_preheat_curr_config(data, (u8)val);
default:
return -EINVAL;
}
}
default:
return -EINVAL;
}
@@ -861,6 +1004,86 @@ static const struct iio_info bme680_info = {
.attrs = &bme680_attribute_group,
};
static const unsigned long bme680_avail_scan_masks[] = {
BIT(BME680_GAS) | BIT(BME680_HUMID) | BIT(BME680_PRESS) | BIT(BME680_TEMP),
0
};
static irqreturn_t bme680_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bme680_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
u32 adc_temp, adc_press, adc_humid;
u16 adc_gas_res, gas_regs_val;
u8 gas_range;
s32 t_fine;
int ret;
guard(mutex)(&data->lock);
ret = bme680_set_mode(data, BME680_MODE_FORCED);
if (ret < 0)
goto out;
ret = bme680_wait_for_eoc(data);
if (ret)
goto out;
ret = regmap_bulk_read(data->regmap, BME680_REG_MEAS_STAT_0,
data->buf, sizeof(data->buf));
if (ret) {
dev_err(dev, "failed to burst read sensor data\n");
goto out;
}
if (data->buf[0] & BME680_GAS_MEAS_BIT) {
dev_err(dev, "gas measurement incomplete\n");
goto out;
}
/* Temperature calculations */
adc_temp = FIELD_GET(BME680_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[5]));
if (adc_temp == BME680_MEAS_SKIPPED) {
dev_err(dev, "reading temperature skipped\n");
goto out;
}
data->scan.chan[0] = bme680_compensate_temp(data, adc_temp);
t_fine = bme680_calc_t_fine(data, adc_temp);
/* Pressure calculations */
adc_press = FIELD_GET(BME680_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[2]));
if (adc_press == BME680_MEAS_SKIPPED) {
dev_err(dev, "reading pressure skipped\n");
goto out;
}
data->scan.chan[1] = bme680_compensate_press(data, adc_press, t_fine);
/* Humidity calculations */
adc_humid = get_unaligned_be16(&data->buf[8]);
if (adc_humid == BME680_MEAS_SKIPPED) {
dev_err(dev, "reading humidity skipped\n");
goto out;
}
data->scan.chan[2] = bme680_compensate_humid(data, adc_humid, t_fine);
/* Gas calculations */
gas_regs_val = get_unaligned_be16(&data->buf[13]);
adc_gas_res = FIELD_GET(BME680_ADC_GAS_RES, gas_regs_val);
if ((gas_regs_val & BME680_GAS_STAB_BIT) == 0) {
dev_err(dev, "heater failed to reach the target temperature\n");
goto out;
}
gas_range = FIELD_GET(BME680_GAS_RANGE_MASK, gas_regs_val);
data->scan.chan[3] = bme680_compensate_gas(data, adc_gas_res, gas_range);
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
int bme680_core_probe(struct device *dev, struct regmap *regmap,
const char *name)
{
@@ -879,6 +1102,7 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
indio_dev->name = name;
indio_dev->channels = bme680_channels;
indio_dev->num_channels = ARRAY_SIZE(bme680_channels);
indio_dev->available_scan_masks = bme680_avail_scan_masks;
indio_dev->info = &bme680_info;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -888,13 +1112,13 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
data->oversampling_temp = 8; /* 8X oversampling rate */
data->heater_temp = 320; /* degree Celsius */
data->heater_dur = 150; /* milliseconds */
data->preheat_curr_mA = 0;
ret = regmap_write(regmap, BME680_REG_SOFT_RESET,
BME680_CMD_SOFTRESET);
ret = regmap_write(regmap, BME680_REG_SOFT_RESET, BME680_CMD_SOFTRESET);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to reset chip\n");
usleep_range(BME680_STARTUP_TIME_US, BME680_STARTUP_TIME_US + 1000);
fsleep(BME680_STARTUP_TIME_US);
ret = regmap_read(regmap, BME680_REG_CHIP_ID, &data->check);
if (ret < 0)
@@ -922,6 +1146,14 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
return dev_err_probe(dev, ret,
"failed to set gas config data\n");
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
bme680_trigger_handler,
NULL);
if (ret)
return dev_err_probe(dev, ret,
"iio triggered buffer setup failed\n");
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(bme680_core_probe, IIO_BME680);

View File

@@ -6,9 +6,28 @@
menu "Digital to analog converters"
config AD3552R_HS
tristate "Analog Devices AD3552R DAC High Speed driver"
select AD3552R_LIB
select IIO_BACKEND
help
Say yes here to build support for Analog Devices AD3552R
Digital to Analog Converter High Speed driver.
The driver requires the assistance of an IP core to operate,
since data is streamed into target device via DMA, sent over a
QSPI + DDR (Double Data Rate) bus.
To compile this driver as a module, choose M here: the
module will be called ad3552r-hs.
config AD3552R_LIB
tristate
config AD3552R
tristate "Analog Devices AD3552R DAC driver"
depends on SPI_MASTER
select AD3552R_LIB
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help

View File

@@ -4,6 +4,8 @@
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD3552R_HS) += ad3552r-hs.o
obj-$(CONFIG_AD3552R_LIB) += ad3552r-common.o
obj-$(CONFIG_AD3552R) += ad3552r.o
obj-$(CONFIG_AD5360) += ad5360.o
obj-$(CONFIG_AD5380) += ad5380.o

View File

@@ -0,0 +1,249 @@
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright (c) 2010-2024 Analog Devices Inc.
// Copyright (c) 2024 Baylibre, SAS
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include "ad3552r.h"
const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2] = {
[AD3552R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 },
[AD3552R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 },
[AD3552R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 },
[AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 },
[AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = { -10000, 10000 }
};
EXPORT_SYMBOL_NS_GPL(ad3552r_ch_ranges, IIO_AD3552R);
const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2] = {
[AD3542R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 },
[AD3542R_CH_OUTPUT_RANGE_0__3V] = { 0, 3000 },
[AD3542R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 },
[AD3542R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 },
[AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = { -2500, 7500 },
[AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 }
};
EXPORT_SYMBOL_NS_GPL(ad3542r_ch_ranges, IIO_AD3552R);
/* Gain * AD3552R_GAIN_SCALE */
static const s32 gains_scaling_table[] = {
[AD3552R_CH_GAIN_SCALING_1] = 1000,
[AD3552R_CH_GAIN_SCALING_0_5] = 500,
[AD3552R_CH_GAIN_SCALING_0_25] = 250,
[AD3552R_CH_GAIN_SCALING_0_125] = 125
};
u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs)
{
return FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1) |
FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, p) |
FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, n) |
FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, abs(goffs)) |
FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, goffs < 0);
}
EXPORT_SYMBOL_NS_GPL(ad3552r_calc_custom_gain, IIO_AD3552R);
static void ad3552r_get_custom_range(struct ad3552r_ch_data *ch_data,
s32 *v_min, s32 *v_max)
{
s64 vref, tmp, common, offset, gn, gp;
/*
* From datasheet formula (In Volts):
* Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03]
* Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03]
* Calculus are converted to milivolts
*/
vref = 2500;
/* 2.5 * 1.03 * 1000 (To mV) */
common = 2575 * ch_data->rfb;
offset = ch_data->gain_offset;
gn = gains_scaling_table[ch_data->n];
tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common;
tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
*v_max = vref + tmp;
gp = gains_scaling_table[ch_data->p];
tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common;
tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
*v_min = vref - tmp;
}
void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data,
const struct ad3552r_model_data *model_data)
{
s32 idx, v_max, v_min, span, rem;
s64 tmp;
if (ch_data->range_override) {
ad3552r_get_custom_range(ch_data, &v_min, &v_max);
} else {
/* Normal range */
idx = ch_data->range;
v_min = model_data->ranges_table[idx][0];
v_max = model_data->ranges_table[idx][1];
}
/*
* From datasheet formula:
* Vout = Span * (D / 65536) + Vmin
* Converted to scale and offset:
* Scale = Span / 65536
* Offset = 65536 * Vmin / Span
*
* Reminders are in micros in order to be printed as
* IIO_VAL_INT_PLUS_MICRO
*/
span = v_max - v_min;
ch_data->scale_int = div_s64_rem(span, 65536, &rem);
/* Do operations in microvolts */
ch_data->scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000, 65536);
ch_data->offset_int = div_s64_rem(v_min * 65536, span, &rem);
tmp = (s64)rem * 1000000;
ch_data->offset_dec = div_s64(tmp, span);
}
EXPORT_SYMBOL_NS_GPL(ad3552r_calc_gain_and_offset, IIO_AD3552R);
int ad3552r_get_ref_voltage(struct device *dev, u32 *val)
{
int voltage;
int delta = 100000;
voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
if (voltage < 0 && voltage != -ENODEV)
return dev_err_probe(dev, voltage,
"Error getting vref voltage\n");
if (voltage == -ENODEV) {
if (device_property_read_bool(dev, "adi,vref-out-en"))
*val = AD3552R_INTERNAL_VREF_PIN_2P5V;
else
*val = AD3552R_INTERNAL_VREF_PIN_FLOATING;
return 0;
}
if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
dev_warn(dev, "vref-supply must be 2.5V");
return -EINVAL;
}
*val = AD3552R_EXTERNAL_VREF_PIN_INPUT;
return 0;
}
EXPORT_SYMBOL_NS_GPL(ad3552r_get_ref_voltage, IIO_AD3552R);
int ad3552r_get_drive_strength(struct device *dev, u32 *val)
{
int err;
u32 drive_strength;
err = device_property_read_u32(dev, "adi,sdo-drive-strength",
&drive_strength);
if (err)
return err;
if (drive_strength > 3) {
dev_err_probe(dev, -EINVAL,
"adi,sdo-drive-strength must be less than 4\n");
return -EINVAL;
}
*val = drive_strength;
return 0;
}
EXPORT_SYMBOL_NS_GPL(ad3552r_get_drive_strength, IIO_AD3552R);
int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs)
{
int err;
u32 val;
struct fwnode_handle *gain_child __free(fwnode_handle) =
fwnode_get_named_child_node(child,
"custom-output-range-config");
if (!gain_child)
return dev_err_probe(dev, -EINVAL,
"custom-output-range-config mandatory\n");
err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
if (err)
return dev_err_probe(dev, err,
"adi,gain-scaling-p mandatory\n");
*gs_p = val;
err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
if (err)
return dev_err_probe(dev, err,
"adi,gain-scaling-n property mandatory\n");
*gs_n = val;
err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
if (err)
return dev_err_probe(dev, err,
"adi,rfb-ohms mandatory\n");
*rfb = val;
err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val);
if (err)
return dev_err_probe(dev, err,
"adi,gain-offset mandatory\n");
*goffs = val;
return 0;
}
EXPORT_SYMBOL_NS_GPL(ad3552r_get_custom_gain, IIO_AD3552R);
static int ad3552r_find_range(const struct ad3552r_model_data *model_info,
s32 *vals)
{
int i;
for (i = 0; i < model_info->num_ranges; i++)
if (vals[0] == model_info->ranges_table[i][0] * 1000 &&
vals[1] == model_info->ranges_table[i][1] * 1000)
return i;
return -EINVAL;
}
int ad3552r_get_output_range(struct device *dev,
const struct ad3552r_model_data *model_info,
struct fwnode_handle *child, u32 *val)
{
int ret;
s32 vals[2];
/* This property is optional, so returning -ENOENT if missing */
if (!fwnode_property_present(child, "adi,output-range-microvolt"))
return -ENOENT;
ret = fwnode_property_read_u32_array(child,
"adi,output-range-microvolt",
vals, 2);
if (ret)
return dev_err_probe(dev, ret,
"invalid adi,output-range-microvolt\n");
ret = ad3552r_find_range(model_info, vals);
if (ret < 0)
return dev_err_probe(dev, ret,
"invalid adi,output-range-microvolt value\n");
*val = ret;
return 0;
}
EXPORT_SYMBOL_NS_GPL(ad3552r_get_output_range, IIO_AD3552R);
MODULE_DESCRIPTION("ad3552r common functions");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,529 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Analog Devices AD3552R
* Digital to Analog converter driver, High Speed version
*
* Copyright 2024 Analog Devices Inc.
*/
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/backend.h>
#include <linux/iio/buffer.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/units.h>
#include "ad3552r.h"
#include "ad3552r-hs.h"
struct ad3552r_hs_state {
const struct ad3552r_model_data *model_data;
struct gpio_desc *reset_gpio;
struct device *dev;
struct iio_backend *back;
bool single_channel;
struct ad3552r_ch_data ch_data[AD3552R_MAX_CH];
struct ad3552r_hs_platform_data *data;
};
static int ad3552r_qspi_update_reg_bits(struct ad3552r_hs_state *st,
u32 reg, u32 mask, u32 val,
size_t xfer_size)
{
u32 rval;
int ret;
ret = st->data->bus_reg_read(st->back, reg, &rval, xfer_size);
if (ret)
return ret;
rval = (rval & ~mask) | val;
return st->data->bus_reg_write(st->back, reg, rval, xfer_size);
}
static int ad3552r_hs_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct ad3552r_hs_state *st = iio_priv(indio_dev);
int ret;
int ch = chan->channel;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
/*
* Using 4 lanes (QSPI), then using 2 as DDR mode is
* considered always on (considering buffering mode always).
*/
*val = DIV_ROUND_CLOSEST(st->data->bus_sample_data_clock_hz *
4 * 2, chan->scan_type.realbits);
return IIO_VAL_INT;
case IIO_CHAN_INFO_RAW:
ret = st->data->bus_reg_read(st->back,
AD3552R_REG_ADDR_CH_DAC_16B(chan->channel),
val, 2);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = st->ch_data[ch].scale_int;
*val2 = st->ch_data[ch].scale_dec;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OFFSET:
*val = st->ch_data[ch].offset_int;
*val2 = st->ch_data[ch].offset_dec;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static int ad3552r_hs_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct ad3552r_hs_state *st = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
return st->data->bus_reg_write(st->back,
AD3552R_REG_ADDR_CH_DAC_16B(chan->channel),
val, 2);
}
unreachable();
default:
return -EINVAL;
}
}
static int ad3552r_hs_buffer_postenable(struct iio_dev *indio_dev)
{
struct ad3552r_hs_state *st = iio_priv(indio_dev);
struct iio_backend_data_fmt fmt = {
.type = IIO_BACKEND_DATA_UNSIGNED
};
int loop_len, val, ret;
switch (*indio_dev->active_scan_mask) {
case AD3552R_CH0_ACTIVE:
st->single_channel = true;
loop_len = 2;
val = AD3552R_REG_ADDR_CH_DAC_16B(0);
break;
case AD3552R_CH1_ACTIVE:
st->single_channel = true;
loop_len = 2;
val = AD3552R_REG_ADDR_CH_DAC_16B(1);
break;
case AD3552R_CH0_ACTIVE | AD3552R_CH1_ACTIVE:
st->single_channel = false;
loop_len = 4;
val = AD3552R_REG_ADDR_CH_DAC_16B(1);
break;
default:
return -EINVAL;
}
ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_STREAM_MODE,
loop_len, 1);
if (ret)
return ret;
/* Inform DAC chip to switch into DDR mode */
ret = ad3552r_qspi_update_reg_bits(st,
AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
AD3552R_MASK_SPI_CONFIG_DDR,
AD3552R_MASK_SPI_CONFIG_DDR, 1);
if (ret)
return ret;
/* Inform DAC IP to go for DDR mode from now on */
ret = iio_backend_ddr_enable(st->back);
if (ret) {
dev_err(st->dev, "could not set DDR mode, not streaming");
goto exit_err;
}
ret = iio_backend_data_transfer_addr(st->back, val);
if (ret)
goto exit_err;
ret = iio_backend_data_format_set(st->back, 0, &fmt);
if (ret)
goto exit_err;
ret = iio_backend_data_stream_enable(st->back);
if (ret)
goto exit_err;
return 0;
exit_err:
ad3552r_qspi_update_reg_bits(st,
AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
AD3552R_MASK_SPI_CONFIG_DDR,
0, 1);
iio_backend_ddr_disable(st->back);
return ret;
}
static int ad3552r_hs_buffer_predisable(struct iio_dev *indio_dev)
{
struct ad3552r_hs_state *st = iio_priv(indio_dev);
int ret;
ret = iio_backend_data_stream_disable(st->back);
if (ret)
return ret;
/* Inform DAC to set in SDR mode */
ret = ad3552r_qspi_update_reg_bits(st,
AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
AD3552R_MASK_SPI_CONFIG_DDR,
0, 1);
if (ret)
return ret;
ret = iio_backend_ddr_disable(st->back);
if (ret)
return ret;
return 0;
}
static inline int ad3552r_hs_set_output_range(struct ad3552r_hs_state *st,
int ch, unsigned int mode)
{
int val;
if (ch == 0)
val = FIELD_PREP(AD3552R_MASK_CH0_RANGE, mode);
else
val = FIELD_PREP(AD3552R_MASK_CH1_RANGE, mode);
return ad3552r_qspi_update_reg_bits(st,
AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE,
AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch),
val, 1);
}
static int ad3552r_hs_reset(struct ad3552r_hs_state *st)
{
int ret;
st->reset_gpio = devm_gpiod_get_optional(st->dev,
"reset", GPIOD_OUT_HIGH);
if (IS_ERR(st->reset_gpio))
return PTR_ERR(st->reset_gpio);
if (st->reset_gpio) {
fsleep(10);
gpiod_set_value_cansleep(st->reset_gpio, 0);
} else {
ret = ad3552r_qspi_update_reg_bits(st,
AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
AD3552R_MASK_SOFTWARE_RESET,
AD3552R_MASK_SOFTWARE_RESET, 1);
if (ret)
return ret;
}
msleep(100);
return 0;
}
static int ad3552r_hs_scratch_pad_test(struct ad3552r_hs_state *st)
{
int ret, val;
ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
AD3552R_SCRATCH_PAD_TEST_VAL1, 1);
if (ret)
return ret;
ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
&val, 1);
if (ret)
return ret;
if (val != AD3552R_SCRATCH_PAD_TEST_VAL1)
return dev_err_probe(st->dev, -EIO,
"SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n",
AD3552R_SCRATCH_PAD_TEST_VAL1, val);
ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
AD3552R_SCRATCH_PAD_TEST_VAL2, 1);
if (ret)
return ret;
ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
&val, 1);
if (ret)
return ret;
if (val != AD3552R_SCRATCH_PAD_TEST_VAL2)
return dev_err_probe(st->dev, -EIO,
"SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n",
AD3552R_SCRATCH_PAD_TEST_VAL2, val);
return 0;
}
static int ad3552r_hs_setup_custom_gain(struct ad3552r_hs_state *st,
int ch, u16 gain, u16 offset)
{
int ret;
ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_OFFSET(ch),
offset, 1);
if (ret)
return ret;
return st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_GAIN(ch),
gain, 1);
}
static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
{
u16 id;
u16 gain = 0, offset = 0;
u32 ch, val, range;
int ret;
ret = ad3552r_hs_reset(st);
if (ret)
return ret;
ret = iio_backend_ddr_disable(st->back);
if (ret)
return ret;
ret = ad3552r_hs_scratch_pad_test(st);
if (ret)
return ret;
ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_L,
&val, 1);
if (ret)
return ret;
id = val;
ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_H,
&val, 1);
if (ret)
return ret;
id |= val << 8;
if (id != st->model_data->chip_id)
dev_info(st->dev, "Chip ID error. Expected 0x%x, Read 0x%x\n",
AD3552R_ID, id);
ret = st->data->bus_reg_write(st->back,
AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
0, 1);
if (ret)
return ret;
ret = st->data->bus_reg_write(st->back,
AD3552R_REG_ADDR_TRANSFER_REGISTER,
FIELD_PREP(AD3552R_MASK_MULTI_IO_MODE,
AD3552R_QUAD_SPI) |
AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE, 1);
if (ret)
return ret;
ret = iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL);
if (ret)
return ret;
ret = iio_backend_data_source_set(st->back, 1, IIO_BACKEND_EXTERNAL);
if (ret)
return ret;
ret = ad3552r_get_ref_voltage(st->dev, &val);
if (ret < 0)
return ret;
val = ret;
ret = ad3552r_qspi_update_reg_bits(st,
AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
AD3552R_MASK_REFERENCE_VOLTAGE_SEL,
val, 1);
if (ret)
return ret;
ret = ad3552r_get_drive_strength(st->dev, &val);
if (!ret) {
ret = ad3552r_qspi_update_reg_bits(st,
AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
AD3552R_MASK_SDO_DRIVE_STRENGTH,
val, 1);
if (ret)
return ret;
}
device_for_each_child_node_scoped(st->dev, child) {
ret = fwnode_property_read_u32(child, "reg", &ch);
if (ret)
return dev_err_probe(st->dev, ret,
"reg property missing\n");
ret = ad3552r_get_output_range(st->dev, st->model_data, child,
&range);
if (ret && ret != -ENOENT)
return ret;
if (ret == -ENOENT) {
ret = ad3552r_get_custom_gain(st->dev, child,
&st->ch_data[ch].p,
&st->ch_data[ch].n,
&st->ch_data[ch].rfb,
&st->ch_data[ch].gain_offset);
if (ret)
return ret;
gain = ad3552r_calc_custom_gain(st->ch_data[ch].p,
st->ch_data[ch].n,
st->ch_data[ch].gain_offset);
offset = abs(st->ch_data[ch].gain_offset);
st->ch_data[ch].range_override = 1;
ret = ad3552r_hs_setup_custom_gain(st, ch, gain,
offset);
if (ret)
return ret;
} else {
st->ch_data[ch].range = range;
ret = ad3552r_hs_set_output_range(st, ch, range);
if (ret)
return ret;
}
ad3552r_calc_gain_and_offset(&st->ch_data[ch], st->model_data);
}
return 0;
}
static const struct iio_buffer_setup_ops ad3552r_hs_buffer_setup_ops = {
.postenable = ad3552r_hs_buffer_postenable,
.predisable = ad3552r_hs_buffer_predisable,
};
#define AD3552R_CHANNEL(ch) { \
.type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.output = 1, \
.indexed = 1, \
.channel = (ch), \
.scan_index = (ch), \
.scan_type = { \
.sign = 'u', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_BE, \
} \
}
static const struct iio_chan_spec ad3552r_hs_channels[] = {
AD3552R_CHANNEL(0),
AD3552R_CHANNEL(1),
};
static const struct iio_info ad3552r_hs_info = {
.read_raw = &ad3552r_hs_read_raw,
.write_raw = &ad3552r_hs_write_raw,
};
static int ad3552r_hs_probe(struct platform_device *pdev)
{
struct ad3552r_hs_state *st;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->dev = &pdev->dev;
st->data = dev_get_platdata(st->dev);
if (!st->data)
return dev_err_probe(st->dev, -ENODEV, "No platform data !");
st->back = devm_iio_backend_get(&pdev->dev, NULL);
if (IS_ERR(st->back))
return PTR_ERR(st->back);
ret = devm_iio_backend_enable(&pdev->dev, st->back);
if (ret)
return ret;
st->model_data = device_get_match_data(&pdev->dev);
if (!st->model_data)
return -ENODEV;
indio_dev->name = "ad3552r";
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->setup_ops = &ad3552r_hs_buffer_setup_ops;
indio_dev->channels = ad3552r_hs_channels;
indio_dev->num_channels = ARRAY_SIZE(ad3552r_hs_channels);
indio_dev->info = &ad3552r_hs_info;
ret = devm_iio_backend_request_buffer(&pdev->dev, st->back, indio_dev);
if (ret)
return ret;
ret = ad3552r_hs_setup(st);
if (ret)
return ret;
return devm_iio_device_register(&pdev->dev, indio_dev);
}
static const struct ad3552r_model_data ad3552r_model_data = {
.model_name = "ad3552r",
.chip_id = AD3552R_ID,
.num_hw_channels = 2,
.ranges_table = ad3552r_ch_ranges,
.num_ranges = ARRAY_SIZE(ad3552r_ch_ranges),
};
static const struct of_device_id ad3552r_hs_of_id[] = {
{ .compatible = "adi,ad3552r", .data = &ad3552r_model_data },
{ }
};
MODULE_DEVICE_TABLE(of, ad3552r_hs_of_id);
static struct platform_driver ad3552r_hs_driver = {
.driver = {
.name = "ad3552r-hs",
.of_match_table = ad3552r_hs_of_id,
},
.probe = ad3552r_hs_probe,
};
module_platform_driver(ad3552r_hs_driver);
MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>");
MODULE_AUTHOR("Angelo Dureghello <adueghello@baylibre.com>");
MODULE_DESCRIPTION("AD3552R Driver - High Speed version");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(IIO_BACKEND);
MODULE_IMPORT_NS(IIO_AD3552R);

View File

@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2024 Analog Devices Inc.
* Copyright (c) 2024 Baylibre, SAS
*/
#ifndef __LINUX_PLATFORM_DATA_AD3552R_HS_H__
#define __LINUX_PLATFORM_DATA_AD3552R_HS_H__
struct iio_backend;
struct ad3552r_hs_platform_data {
int (*bus_reg_read)(struct iio_backend *back, u32 reg, u32 *val,
size_t data_size);
int (*bus_reg_write)(struct iio_backend *back, u32 reg, u32 val,
size_t data_size);
u32 bus_sample_data_clock_hz;
};
#endif /* __LINUX_PLATFORM_DATA_AD3552R_HS_H__ */

View File

@@ -6,271 +6,15 @@
* Copyright 2021 Analog Devices Inc.
*/
#include <linux/unaligned.h>
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
/* Register addresses */
/* Primary address space */
#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00
#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0))
#define AD3552R_MASK_ADDR_ASCENSION BIT(5)
#define AD3552R_MASK_SDO_ACTIVE BIT(4)
#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01
#define AD3552R_MASK_SINGLE_INST BIT(7)
#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3)
#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02
#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n))
#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2)
#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0)
#define AD3552R_REG_ADDR_CHIP_TYPE 0x03
#define AD3552R_MASK_CLASS GENMASK(7, 0)
#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04
#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05
#define AD3552R_REG_ADDR_CHIP_GRADE 0x06
#define AD3552R_MASK_GRADE GENMASK(7, 4)
#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0)
#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A
#define AD3552R_REG_ADDR_SPI_REVISION 0x0B
#define AD3552R_REG_ADDR_VENDOR_L 0x0C
#define AD3552R_REG_ADDR_VENDOR_H 0x0D
#define AD3552R_REG_ADDR_STREAM_MODE 0x0E
#define AD3552R_MASK_LENGTH GENMASK(7, 0)
#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F
#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6)
#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2)
#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10
#define AD3552R_MASK_CRC_ENABLE (GENMASK(7, 6) |\
GENMASK(1, 0))
#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5)
#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11
#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7)
#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5)
#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3)
#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2)
#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1)
#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0)
#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14
#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6)
#define AD3552R_MASK_MEM_CRC_EN BIT(4)
#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2)
#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1)
#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0)
#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15
#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6)
#define AD3552R_MASK_SAMPLE_HOLD_DIFFERENTIAL_USER_EN BIT(5)
#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3)
#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2)
#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0)
#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16
#define AD3552R_MASK_REF_RANGE_ALARM BIT(6)
#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5)
#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4)
#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3)
#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2)
#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1)
#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0)
#define AD3552R_REG_ADDR_ERR_STATUS 0x17
#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6)
#define AD3552R_MASK_DUAL_SPI_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5)
#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4)
#define AD3552R_MASK_RESET_STATUS BIT(0)
#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18
#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch))
#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch)
#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19
#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) ((ch) ? GENMASK(7, 4) :\
GENMASK(3, 0))
#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2)
#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0)
#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2)
#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7)
#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5)
#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3)
#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2)
#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(0)
/*
* Secondary region
* For multibyte registers specify the highest address because the access is
* done in descending order
*/
#define AD3552R_SECONDARY_REGION_START 0x28
#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28
#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - ch) * 2)
#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E
#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F
#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31
#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32
#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - ch) * 2)
/* 3 bytes registers */
#define AD3552R_REG_START_24B 0x37
#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37
#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - ch) * 3)
#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40
#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41
#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44
#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45
#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - ch) * 3)
/* Useful defines */
#define AD3552R_MAX_CH 2
#define AD3552R_MASK_CH(ch) BIT(ch)
#define AD3552R_MASK_ALL_CH GENMASK(1, 0)
#define AD3552R_MAX_REG_SIZE 3
#define AD3552R_READ_BIT BIT(7)
#define AD3552R_ADDR_MASK GENMASK(6, 0)
#define AD3552R_MASK_DAC_12B 0xFFF0
#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8
#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34
#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2
#define AD3552R_GAIN_SCALE 1000
#define AD3552R_LDAC_PULSE_US 100
enum ad3552r_ch_vref_select {
/* Internal source with Vref I/O floating */
AD3552R_INTERNAL_VREF_PIN_FLOATING,
/* Internal source with Vref I/O at 2.5V */
AD3552R_INTERNAL_VREF_PIN_2P5V,
/* External source with Vref I/O as input */
AD3552R_EXTERNAL_VREF_PIN_INPUT
};
enum ad3552r_id {
AD3541R_ID = 0x400b,
AD3542R_ID = 0x4009,
AD3551R_ID = 0x400a,
AD3552R_ID = 0x4008,
};
enum ad3552r_ch_output_range {
/* Range from 0 V to 2.5 V. Requires Rfb1x connection */
AD3552R_CH_OUTPUT_RANGE_0__2P5V,
/* Range from 0 V to 5 V. Requires Rfb1x connection */
AD3552R_CH_OUTPUT_RANGE_0__5V,
/* Range from 0 V to 10 V. Requires Rfb2x connection */
AD3552R_CH_OUTPUT_RANGE_0__10V,
/* Range from -5 V to 5 V. Requires Rfb2x connection */
AD3552R_CH_OUTPUT_RANGE_NEG_5__5V,
/* Range from -10 V to 10 V. Requires Rfb4x connection */
AD3552R_CH_OUTPUT_RANGE_NEG_10__10V,
};
static const s32 ad3552r_ch_ranges[][2] = {
[AD3552R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500},
[AD3552R_CH_OUTPUT_RANGE_0__5V] = {0, 5000},
[AD3552R_CH_OUTPUT_RANGE_0__10V] = {0, 10000},
[AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000},
[AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = {-10000, 10000}
};
enum ad3542r_ch_output_range {
/* Range from 0 V to 2.5 V. Requires Rfb1x connection */
AD3542R_CH_OUTPUT_RANGE_0__2P5V,
/* Range from 0 V to 3 V. Requires Rfb1x connection */
AD3542R_CH_OUTPUT_RANGE_0__3V,
/* Range from 0 V to 5 V. Requires Rfb1x connection */
AD3542R_CH_OUTPUT_RANGE_0__5V,
/* Range from 0 V to 10 V. Requires Rfb2x connection */
AD3542R_CH_OUTPUT_RANGE_0__10V,
/* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */
AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V,
/* Range from -5 V to 5 V. Requires Rfb2x connection */
AD3542R_CH_OUTPUT_RANGE_NEG_5__5V,
};
static const s32 ad3542r_ch_ranges[][2] = {
[AD3542R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500},
[AD3542R_CH_OUTPUT_RANGE_0__3V] = {0, 3000},
[AD3542R_CH_OUTPUT_RANGE_0__5V] = {0, 5000},
[AD3542R_CH_OUTPUT_RANGE_0__10V] = {0, 10000},
[AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = {-2500, 7500},
[AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000}
};
enum ad3552r_ch_gain_scaling {
/* Gain scaling of 1 */
AD3552R_CH_GAIN_SCALING_1,
/* Gain scaling of 0.5 */
AD3552R_CH_GAIN_SCALING_0_5,
/* Gain scaling of 0.25 */
AD3552R_CH_GAIN_SCALING_0_25,
/* Gain scaling of 0.125 */
AD3552R_CH_GAIN_SCALING_0_125,
};
/* Gain * AD3552R_GAIN_SCALE */
static const s32 gains_scaling_table[] = {
[AD3552R_CH_GAIN_SCALING_1] = 1000,
[AD3552R_CH_GAIN_SCALING_0_5] = 500,
[AD3552R_CH_GAIN_SCALING_0_25] = 250,
[AD3552R_CH_GAIN_SCALING_0_125] = 125
};
enum ad3552r_dev_attributes {
/* - Direct register values */
/* From 0-3 */
AD3552R_SDO_DRIVE_STRENGTH,
/*
* 0 -> Internal Vref, vref_io pin floating (default)
* 1 -> Internal Vref, vref_io driven by internal vref
* 2 or 3 -> External Vref
*/
AD3552R_VREF_SELECT,
/* Read registers in ascending order if set. Else descending */
AD3552R_ADDR_ASCENSION,
};
enum ad3552r_ch_attributes {
/* DAC powerdown */
AD3552R_CH_DAC_POWERDOWN,
/* DAC amplifier powerdown */
AD3552R_CH_AMPLIFIER_POWERDOWN,
/* Select the output range. Select from enum ad3552r_ch_output_range */
AD3552R_CH_OUTPUT_RANGE_SEL,
/*
* Over-rider the range selector in order to manually set the output
* voltage range
*/
AD3552R_CH_RANGE_OVERRIDE,
/* Manually set the offset voltage */
AD3552R_CH_GAIN_OFFSET,
/* Sets the polarity of the offset. */
AD3552R_CH_GAIN_OFFSET_POLARITY,
/* PDAC gain scaling */
AD3552R_CH_GAIN_SCALING_P,
/* NDAC gain scaling */
AD3552R_CH_GAIN_SCALING_N,
/* Rfb value */
AD3552R_CH_RFB,
/* Channel select. When set allow Input -> DAC and Mask -> DAC */
AD3552R_CH_SELECT,
};
struct ad3552r_ch_data {
s32 scale_int;
s32 scale_dec;
s32 offset_int;
s32 offset_dec;
s16 gain_offset;
u16 rfb;
u8 n;
u8 p;
u8 range;
bool range_override;
};
struct ad3552r_model_data {
const char *model_name;
enum ad3552r_id chip_id;
unsigned int num_hw_channels;
const s32 (*ranges_table)[2];
int num_ranges;
bool requires_output_range;
};
#include "ad3552r.h"
struct ad3552r_desc {
const struct ad3552r_model_data *model_data;
@@ -285,45 +29,6 @@ struct ad3552r_desc {
unsigned int num_ch;
};
static const u16 addr_mask_map[][2] = {
[AD3552R_ADDR_ASCENSION] = {
AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
AD3552R_MASK_ADDR_ASCENSION
},
[AD3552R_SDO_DRIVE_STRENGTH] = {
AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
AD3552R_MASK_SDO_DRIVE_STRENGTH
},
[AD3552R_VREF_SELECT] = {
AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
AD3552R_MASK_REFERENCE_VOLTAGE_SEL
},
};
/* 0 -> reg addr, 1->ch0 mask, 2->ch1 mask */
static const u16 addr_mask_map_ch[][3] = {
[AD3552R_CH_DAC_POWERDOWN] = {
AD3552R_REG_ADDR_POWERDOWN_CONFIG,
AD3552R_MASK_CH_DAC_POWERDOWN(0),
AD3552R_MASK_CH_DAC_POWERDOWN(1)
},
[AD3552R_CH_AMPLIFIER_POWERDOWN] = {
AD3552R_REG_ADDR_POWERDOWN_CONFIG,
AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0),
AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1)
},
[AD3552R_CH_OUTPUT_RANGE_SEL] = {
AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE,
AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0),
AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1)
},
[AD3552R_CH_SELECT] = {
AD3552R_REG_ADDR_CH_SELECT_16B,
AD3552R_MASK_CH(0),
AD3552R_MASK_CH(1)
}
};
static u8 _ad3552r_reg_len(u8 addr)
{
switch (addr) {
@@ -399,11 +104,6 @@ static int ad3552r_read_reg(struct ad3552r_desc *dac, u8 addr, u16 *val)
return 0;
}
static u16 ad3552r_field_prep(u16 val, u16 mask)
{
return (val << __ffs(mask)) & mask;
}
/* Update field of a register, shift val if needed */
static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask,
u16 val)
@@ -416,21 +116,11 @@ static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask,
return ret;
reg &= ~mask;
reg |= ad3552r_field_prep(val, mask);
reg |= val;
return ad3552r_write_reg(dac, addr, reg);
}
static int ad3552r_set_ch_value(struct ad3552r_desc *dac,
enum ad3552r_ch_attributes attr,
u8 ch,
u16 val)
{
/* Update register related to attributes in chip */
return ad3552r_update_reg_field(dac, addr_mask_map_ch[attr][0],
addr_mask_map_ch[attr][ch + 1], val);
}
#define AD3552R_CH_DAC(_idx) ((struct iio_chan_spec) { \
.type = IIO_VOLTAGE, \
.output = true, \
@@ -510,8 +200,14 @@ static int ad3552r_write_raw(struct iio_dev *indio_dev,
val);
break;
case IIO_CHAN_INFO_ENABLE:
err = ad3552r_set_ch_value(dac, AD3552R_CH_DAC_POWERDOWN,
chan->channel, !val);
if (chan->channel == 0)
val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(0), !val);
else
val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(1), !val);
err = ad3552r_update_reg_field(dac, AD3552R_REG_ADDR_POWERDOWN_CONFIG,
AD3552R_MASK_CH_DAC_POWERDOWN(chan->channel),
val);
break;
default:
err = -EINVAL;
@@ -715,83 +411,9 @@ static int ad3552r_reset(struct ad3552r_desc *dac)
}
return ad3552r_update_reg_field(dac,
addr_mask_map[AD3552R_ADDR_ASCENSION][0],
addr_mask_map[AD3552R_ADDR_ASCENSION][1],
val);
}
static void ad3552r_get_custom_range(struct ad3552r_desc *dac, s32 i, s32 *v_min,
s32 *v_max)
{
s64 vref, tmp, common, offset, gn, gp;
/*
* From datasheet formula (In Volts):
* Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03]
* Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03]
* Calculus are converted to milivolts
*/
vref = 2500;
/* 2.5 * 1.03 * 1000 (To mV) */
common = 2575 * dac->ch_data[i].rfb;
offset = dac->ch_data[i].gain_offset;
gn = gains_scaling_table[dac->ch_data[i].n];
tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common;
tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
*v_max = vref + tmp;
gp = gains_scaling_table[dac->ch_data[i].p];
tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common;
tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
*v_min = vref - tmp;
}
static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch)
{
s32 idx, v_max, v_min, span, rem;
s64 tmp;
if (dac->ch_data[ch].range_override) {
ad3552r_get_custom_range(dac, ch, &v_min, &v_max);
} else {
/* Normal range */
idx = dac->ch_data[ch].range;
v_min = dac->model_data->ranges_table[idx][0];
v_max = dac->model_data->ranges_table[idx][1];
}
/*
* From datasheet formula:
* Vout = Span * (D / 65536) + Vmin
* Converted to scale and offset:
* Scale = Span / 65536
* Offset = 65536 * Vmin / Span
*
* Reminders are in micros in order to be printed as
* IIO_VAL_INT_PLUS_MICRO
*/
span = v_max - v_min;
dac->ch_data[ch].scale_int = div_s64_rem(span, 65536, &rem);
/* Do operations in microvolts */
dac->ch_data[ch].scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000,
65536);
dac->ch_data[ch].offset_int = div_s64_rem(v_min * 65536, span, &rem);
tmp = (s64)rem * 1000000;
dac->ch_data[ch].offset_dec = div_s64(tmp, span);
}
static int ad3552r_find_range(const struct ad3552r_model_data *model_data,
s32 *vals)
{
int i;
for (i = 0; i < model_data->num_ranges; i++)
if (vals[0] == model_data->ranges_table[i][0] * 1000 &&
vals[1] == model_data->ranges_table[i][1] * 1000)
return i;
return -EINVAL;
AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
AD3552R_MASK_ADDR_ASCENSION,
FIELD_PREP(AD3552R_MASK_ADDR_ASCENSION, val));
}
static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
@@ -799,57 +421,30 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
u32 ch)
{
struct device *dev = &dac->spi->dev;
u32 val;
int err;
u8 addr;
u16 reg = 0, offset;
u16 reg;
struct fwnode_handle *gain_child __free(fwnode_handle)
= fwnode_get_named_child_node(child,
"custom-output-range-config");
if (!gain_child)
return dev_err_probe(dev, -EINVAL,
"mandatory custom-output-range-config property missing\n");
err = ad3552r_get_custom_gain(dev, child,
&dac->ch_data[ch].p,
&dac->ch_data[ch].n,
&dac->ch_data[ch].rfb,
&dac->ch_data[ch].gain_offset);
if (err)
return err;
dac->ch_data[ch].range_override = 1;
reg |= ad3552r_field_prep(1, AD3552R_MASK_CH_RANGE_OVERRIDE);
err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
if (err)
return dev_err_probe(dev, err,
"mandatory adi,gain-scaling-p property missing\n");
reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_P);
dac->ch_data[ch].p = val;
err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
if (err)
return dev_err_probe(dev, err,
"mandatory adi,gain-scaling-n property missing\n");
reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_N);
dac->ch_data[ch].n = val;
err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
if (err)
return dev_err_probe(dev, err,
"mandatory adi,rfb-ohms property missing\n");
dac->ch_data[ch].rfb = val;
err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val);
if (err)
return dev_err_probe(dev, err,
"mandatory adi,gain-offset property missing\n");
dac->ch_data[ch].gain_offset = val;
offset = abs((s32)val);
reg |= ad3552r_field_prep((offset >> 8), AD3552R_MASK_CH_OFFSET_BIT_8);
reg |= ad3552r_field_prep((s32)val < 0, AD3552R_MASK_CH_OFFSET_POLARITY);
addr = AD3552R_REG_ADDR_CH_GAIN(ch);
err = ad3552r_write_reg(dac, addr,
offset & AD3552R_MASK_CH_OFFSET_BITS_0_7);
abs((s32)dac->ch_data[ch].gain_offset) &
AD3552R_MASK_CH_OFFSET_BITS_0_7);
if (err)
return dev_err_probe(dev, err, "Error writing register\n");
reg = ad3552r_calc_custom_gain(dac->ch_data[ch].p, dac->ch_data[ch].n,
dac->ch_data[ch].gain_offset);
err = ad3552r_write_reg(dac, addr, reg);
if (err)
return dev_err_probe(dev, err, "Error writing register\n");
@@ -860,49 +455,31 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
static int ad3552r_configure_device(struct ad3552r_desc *dac)
{
struct device *dev = &dac->spi->dev;
int err, cnt = 0, voltage, delta = 100000;
u32 vals[2], val, ch;
int err, cnt = 0;
u32 val, ch;
dac->gpio_ldac = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH);
if (IS_ERR(dac->gpio_ldac))
return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac),
"Error getting gpio ldac");
voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
if (voltage < 0 && voltage != -ENODEV)
return dev_err_probe(dev, voltage, "Error getting vref voltage\n");
if (voltage == -ENODEV) {
if (device_property_read_bool(dev, "adi,vref-out-en"))
val = AD3552R_INTERNAL_VREF_PIN_2P5V;
else
val = AD3552R_INTERNAL_VREF_PIN_FLOATING;
} else {
if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
dev_warn(dev, "vref-supply must be 2.5V");
return -EINVAL;
}
val = AD3552R_EXTERNAL_VREF_PIN_INPUT;
}
err = ad3552r_get_ref_voltage(dev, &val);
if (err < 0)
return err;
err = ad3552r_update_reg_field(dac,
addr_mask_map[AD3552R_VREF_SELECT][0],
addr_mask_map[AD3552R_VREF_SELECT][1],
val);
AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
AD3552R_MASK_REFERENCE_VOLTAGE_SEL,
FIELD_PREP(AD3552R_MASK_REFERENCE_VOLTAGE_SEL, val));
if (err)
return err;
err = device_property_read_u32(dev, "adi,sdo-drive-strength", &val);
err = ad3552r_get_drive_strength(dev, &val);
if (!err) {
if (val > 3) {
dev_err(dev, "adi,sdo-drive-strength must be less than 4\n");
return -EINVAL;
}
err = ad3552r_update_reg_field(dac,
addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][0],
addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][1],
val);
AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
AD3552R_MASK_SDO_DRIVE_STRENGTH,
FIELD_PREP(AD3552R_MASK_SDO_DRIVE_STRENGTH, val));
if (err)
return err;
}
@@ -923,24 +500,21 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
"reg must be less than %d\n",
dac->model_data->num_hw_channels);
if (fwnode_property_present(child, "adi,output-range-microvolt")) {
err = fwnode_property_read_u32_array(child,
"adi,output-range-microvolt",
vals,
2);
if (err)
return dev_err_probe(dev, err,
"adi,output-range-microvolt property could not be parsed\n");
err = ad3552r_get_output_range(dev, dac->model_data,
child, &val);
if (err && err != -ENOENT)
return err;
err = ad3552r_find_range(dac->model_data, vals);
if (err < 0)
return dev_err_probe(dev, err,
"Invalid adi,output-range-microvolt value\n");
if (!err) {
if (ch == 0)
val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), val);
else
val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1), val);
val = err;
err = ad3552r_set_ch_value(dac,
AD3552R_CH_OUTPUT_RANGE_SEL,
ch, val);
err = ad3552r_update_reg_field(dac,
AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE,
AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch),
val);
if (err)
return err;
@@ -955,10 +529,17 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
return err;
}
ad3552r_calc_gain_and_offset(dac, ch);
ad3552r_calc_gain_and_offset(&dac->ch_data[ch], dac->model_data);
dac->enabled_ch |= BIT(ch);
err = ad3552r_set_ch_value(dac, AD3552R_CH_SELECT, ch, 1);
if (ch == 0)
val = FIELD_PREP(AD3552R_MASK_CH(0), 1);
else
val = FIELD_PREP(AD3552R_MASK_CH(1), 1);
err = ad3552r_update_reg_field(dac,
AD3552R_REG_ADDR_CH_SELECT_16B,
AD3552R_MASK_CH(ch), val);
if (err < 0)
return err;
@@ -970,8 +551,15 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
/* Disable unused channels */
for_each_clear_bit(ch, &dac->enabled_ch,
dac->model_data->num_hw_channels) {
err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN,
ch, 1);
if (ch == 0)
val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0), 1);
else
val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1), 1);
err = ad3552r_update_reg_field(dac,
AD3552R_REG_ADDR_POWERDOWN_CONFIG,
AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch),
val);
if (err)
return err;
}
@@ -1140,3 +728,4 @@ module_spi_driver(ad3552r_driver);
MODULE_AUTHOR("Mihail Chindris <mihail.chindris@analog.com>");
MODULE_DESCRIPTION("Analog Device AD3552R DAC");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(IIO_AD3552R);

228
drivers/iio/dac/ad3552r.h Normal file
View File

@@ -0,0 +1,228 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* AD3552R Digital <-> Analog converters common header
*
* Copyright 2021-2024 Analog Devices Inc.
* Author: Angelo Dureghello <adureghello@baylibre.com>
*/
#ifndef __DRIVERS_IIO_DAC_AD3552R_H__
#define __DRIVERS_IIO_DAC_AD3552R_H__
/* Register addresses */
/* Primary address space */
#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00
#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0))
#define AD3552R_MASK_ADDR_ASCENSION BIT(5)
#define AD3552R_MASK_SDO_ACTIVE BIT(4)
#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01
#define AD3552R_MASK_SINGLE_INST BIT(7)
#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3)
#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02
#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n))
#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2)
#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0)
#define AD3552R_REG_ADDR_CHIP_TYPE 0x03
#define AD3552R_MASK_CLASS GENMASK(7, 0)
#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04
#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05
#define AD3552R_REG_ADDR_CHIP_GRADE 0x06
#define AD3552R_MASK_GRADE GENMASK(7, 4)
#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0)
#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A
#define AD3552R_REG_ADDR_SPI_REVISION 0x0B
#define AD3552R_REG_ADDR_VENDOR_L 0x0C
#define AD3552R_REG_ADDR_VENDOR_H 0x0D
#define AD3552R_REG_ADDR_STREAM_MODE 0x0E
#define AD3552R_MASK_LENGTH GENMASK(7, 0)
#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F
#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6)
#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2)
#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10
#define AD3552R_MASK_CRC_ENABLE \
(GENMASK(7, 6) | GENMASK(1, 0))
#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5)
#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11
#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7)
#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5)
#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3)
#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2)
#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1)
#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0)
#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14
#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6)
#define AD3552R_MASK_MEM_CRC_EN BIT(4)
#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2)
#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1)
#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0)
#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15
#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6)
#define AD3552R_MASK_SAMPLE_HOLD_DIFF_USER_EN BIT(5)
#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3)
#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2)
#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0)
#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16
#define AD3552R_MASK_REF_RANGE_ALARM BIT(6)
#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5)
#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4)
#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3)
#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2)
#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1)
#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0)
#define AD3552R_REG_ADDR_ERR_STATUS 0x17
#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6)
#define AD3552R_MASK_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5)
#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4)
#define AD3552R_MASK_RESET_STATUS BIT(0)
#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18
#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch))
#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch)
#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19
#define AD3552R_MASK_CH0_RANGE GENMASK(2, 0)
#define AD3552R_MASK_CH1_RANGE GENMASK(6, 4)
#define AD3552R_MASK_CH_OUTPUT_RANGE GENMASK(7, 0)
#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) \
((ch) ? GENMASK(7, 4) : GENMASK(3, 0))
#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2)
#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0)
#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2)
#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7)
#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5)
#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3)
#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2)
#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(8)
/*
* Secondary region
* For multibyte registers specify the highest address because the access is
* done in descending order
*/
#define AD3552R_SECONDARY_REGION_START 0x28
#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28
#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - (ch)) * 2)
#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E
#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F
#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31
#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32
#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - (ch)) * 2)
/* 3 bytes registers */
#define AD3552R_REG_START_24B 0x37
#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37
#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - (ch)) * 3)
#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40
#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41
#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44
#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45
#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - (ch)) * 3)
#define AD3552R_MAX_CH 2
#define AD3552R_MASK_CH(ch) BIT(ch)
#define AD3552R_MASK_ALL_CH GENMASK(1, 0)
#define AD3552R_MAX_REG_SIZE 3
#define AD3552R_READ_BIT BIT(7)
#define AD3552R_ADDR_MASK GENMASK(6, 0)
#define AD3552R_MASK_DAC_12B GENMASK(15, 4)
#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8
#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34
#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2
#define AD3552R_GAIN_SCALE 1000
#define AD3552R_LDAC_PULSE_US 100
#define AD3552R_CH0_ACTIVE BIT(0)
#define AD3552R_CH1_ACTIVE BIT(1)
#define AD3552R_MAX_RANGES 5
#define AD3542R_MAX_RANGES 6
#define AD3552R_QUAD_SPI 2
extern const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2];
extern const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2];
enum ad3552r_id {
AD3541R_ID = 0x400b,
AD3542R_ID = 0x4009,
AD3551R_ID = 0x400a,
AD3552R_ID = 0x4008,
};
struct ad3552r_model_data {
const char *model_name;
enum ad3552r_id chip_id;
unsigned int num_hw_channels;
const s32 (*ranges_table)[2];
int num_ranges;
bool requires_output_range;
};
struct ad3552r_ch_data {
s32 scale_int;
s32 scale_dec;
s32 offset_int;
s32 offset_dec;
s16 gain_offset;
u16 rfb;
u8 n;
u8 p;
u8 range;
bool range_override;
};
enum ad3552r_ch_gain_scaling {
/* Gain scaling of 1 */
AD3552R_CH_GAIN_SCALING_1,
/* Gain scaling of 0.5 */
AD3552R_CH_GAIN_SCALING_0_5,
/* Gain scaling of 0.25 */
AD3552R_CH_GAIN_SCALING_0_25,
/* Gain scaling of 0.125 */
AD3552R_CH_GAIN_SCALING_0_125,
};
enum ad3552r_ch_vref_select {
/* Internal source with Vref I/O floating */
AD3552R_INTERNAL_VREF_PIN_FLOATING,
/* Internal source with Vref I/O at 2.5V */
AD3552R_INTERNAL_VREF_PIN_2P5V,
/* External source with Vref I/O as input */
AD3552R_EXTERNAL_VREF_PIN_INPUT
};
enum ad3542r_ch_output_range {
/* Range from 0 V to 2.5 V. Requires Rfb1x connection */
AD3542R_CH_OUTPUT_RANGE_0__2P5V,
/* Range from 0 V to 3 V. Requires Rfb1x connection */
AD3542R_CH_OUTPUT_RANGE_0__3V,
/* Range from 0 V to 5 V. Requires Rfb1x connection */
AD3542R_CH_OUTPUT_RANGE_0__5V,
/* Range from 0 V to 10 V. Requires Rfb2x connection */
AD3542R_CH_OUTPUT_RANGE_0__10V,
/* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */
AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V,
/* Range from -5 V to 5 V. Requires Rfb2x connection */
AD3542R_CH_OUTPUT_RANGE_NEG_5__5V,
};
enum ad3552r_ch_output_range {
/* Range from 0 V to 2.5 V. Requires Rfb1x connection */
AD3552R_CH_OUTPUT_RANGE_0__2P5V,
/* Range from 0 V to 5 V. Requires Rfb1x connection */
AD3552R_CH_OUTPUT_RANGE_0__5V,
/* Range from 0 V to 10 V. Requires Rfb2x connection */
AD3552R_CH_OUTPUT_RANGE_0__10V,
/* Range from -5 V to 5 V. Requires Rfb2x connection */
AD3552R_CH_OUTPUT_RANGE_NEG_5__5V,
/* Range from -10 V to 10 V. Requires Rfb4x connection */
AD3552R_CH_OUTPUT_RANGE_NEG_10__10V,
};
int ad3552r_get_output_range(struct device *dev,
const struct ad3552r_model_data *model_info,
struct fwnode_handle *child, u32 *val);
int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs);
u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs);
int ad3552r_get_ref_voltage(struct device *dev, u32 *val);
int ad3552r_get_drive_strength(struct device *dev, u32 *val);
void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data,
const struct ad3552r_model_data *model_data);
#endif /* __DRIVERS_IIO_DAC_AD3552R_H__ */

View File

@@ -47,7 +47,6 @@ struct ad5380_chip_info {
* struct ad5380_state - driver instance specific data
* @regmap: regmap instance used by the device
* @chip_info: chip model specific constants, available modes etc
* @vref_reg: vref supply regulator
* @vref: actual reference voltage used in uA
* @pwr_down: whether the chip is currently in power down mode
* @lock: lock to protect the data buffer during regmap ops
@@ -55,7 +54,6 @@ struct ad5380_chip_info {
struct ad5380_state {
struct regmap *regmap;
const struct ad5380_chip_info *chip_info;
struct regulator *vref_reg;
int vref;
bool pwr_down;
struct mutex lock;
@@ -341,14 +339,14 @@ static const struct ad5380_chip_info ad5380_chip_info_tbl[] = {
},
};
static int ad5380_alloc_channels(struct iio_dev *indio_dev)
static int ad5380_alloc_channels(struct device *dev, struct iio_dev *indio_dev)
{
struct ad5380_state *st = iio_priv(indio_dev);
struct iio_chan_spec *channels;
unsigned int i;
channels = kcalloc(st->chip_info->num_channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
channels = devm_kcalloc(dev, st->chip_info->num_channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
if (!channels)
return -ENOMEM;
@@ -379,7 +377,6 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap,
}
st = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
st->chip_info = &ad5380_chip_info_tbl[type];
st->regmap = regmap;
@@ -391,68 +388,32 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap,
mutex_init(&st->lock);
ret = ad5380_alloc_channels(indio_dev);
if (ret) {
dev_err(dev, "Failed to allocate channel spec: %d\n", ret);
return ret;
}
ret = ad5380_alloc_channels(dev, indio_dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to allocate channel spec\n");
if (st->chip_info->int_vref == 2500)
ctrl |= AD5380_CTRL_INT_VREF_2V5;
st->vref_reg = devm_regulator_get(dev, "vref");
if (!IS_ERR(st->vref_reg)) {
ret = regulator_enable(st->vref_reg);
if (ret) {
dev_err(dev, "Failed to enable vref regulators: %d\n",
ret);
goto error_free_reg;
}
ret = regulator_get_voltage(st->vref_reg);
if (ret < 0)
goto error_disable_reg;
st->vref = ret / 1000;
} else {
ret = devm_regulator_get_enable_read_voltage(dev, "vref");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(dev, ret, "Failed to get vref voltage\n");
if (ret == -ENODEV) {
st->vref = st->chip_info->int_vref;
ctrl |= AD5380_CTRL_INT_VREF_EN;
} else {
st->vref = ret / 1000;
}
ret = regmap_write(st->regmap, AD5380_REG_SF_CTRL, ctrl);
if (ret) {
dev_err(dev, "Failed to write to device: %d\n", ret);
goto error_disable_reg;
}
if (ret)
return dev_err_probe(dev, ret, "Failed to write to device\n");
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(dev, "Failed to register iio device: %d\n", ret);
goto error_disable_reg;
}
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to register iio device\n");
return 0;
error_disable_reg:
if (!IS_ERR(st->vref_reg))
regulator_disable(st->vref_reg);
error_free_reg:
kfree(indio_dev->channels);
return ret;
}
static void ad5380_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5380_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
kfree(indio_dev->channels);
if (!IS_ERR(st->vref_reg))
regulator_disable(st->vref_reg);
}
static bool ad5380_reg_false(struct device *dev, unsigned int reg)
@@ -486,11 +447,6 @@ static int ad5380_spi_probe(struct spi_device *spi)
return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name);
}
static void ad5380_spi_remove(struct spi_device *spi)
{
ad5380_remove(&spi->dev);
}
static const struct spi_device_id ad5380_spi_ids[] = {
{ "ad5380-3", ID_AD5380_3 },
{ "ad5380-5", ID_AD5380_5 },
@@ -517,7 +473,6 @@ static struct spi_driver ad5380_spi_driver = {
.name = "ad5380",
},
.probe = ad5380_spi_probe,
.remove = ad5380_spi_remove,
.id_table = ad5380_spi_ids,
};
@@ -559,11 +514,6 @@ static int ad5380_i2c_probe(struct i2c_client *i2c)
return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name);
}
static void ad5380_i2c_remove(struct i2c_client *i2c)
{
ad5380_remove(&i2c->dev);
}
static const struct i2c_device_id ad5380_i2c_ids[] = {
{ "ad5380-3", ID_AD5380_3 },
{ "ad5380-5", ID_AD5380_5 },
@@ -590,7 +540,6 @@ static struct i2c_driver ad5380_i2c_driver = {
.name = "ad5380",
},
.probe = ad5380_i2c_probe,
.remove = ad5380_i2c_remove,
.id_table = ad5380_i2c_ids,
};

View File

@@ -384,7 +384,7 @@ static int ad5421_write_raw(struct iio_dev *indio_dev,
static int ad5421_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state)
enum iio_event_direction dir, bool state)
{
struct ad5421_state *st = iio_priv(indio_dev);
unsigned int mask;

View File

@@ -32,7 +32,6 @@
* struct ad5446_state - driver instance specific data
* @dev: this device
* @chip_info: chip model specific constants, available modes etc
* @reg: supply regulator
* @vref_mv: actual reference voltage used
* @cached_val: store/retrieve values during power down
* @pwr_down_mode: power down mode (1k, 100k or tristate)
@@ -43,7 +42,6 @@
struct ad5446_state {
struct device *dev;
const struct ad5446_chip_info *chip_info;
struct regulator *reg;
unsigned short vref_mv;
unsigned cached_val;
unsigned pwr_down_mode;
@@ -226,32 +224,15 @@ static int ad5446_probe(struct device *dev, const char *name,
{
struct ad5446_state *st;
struct iio_dev *indio_dev;
struct regulator *reg;
int ret, voltage_uv = 0;
reg = devm_regulator_get(dev, "vcc");
if (!IS_ERR(reg)) {
ret = regulator_enable(reg);
if (ret)
return ret;
ret = regulator_get_voltage(reg);
if (ret < 0)
goto error_disable_reg;
voltage_uv = ret;
}
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
}
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->chip_info = chip_info;
dev_set_drvdata(dev, indio_dev);
st->reg = reg;
st->dev = dev;
indio_dev->name = name;
@@ -264,33 +245,19 @@ static int ad5446_probe(struct device *dev, const char *name,
st->pwr_down_mode = MODE_PWRDWN_1k;
if (st->chip_info->int_vref_mv)
st->vref_mv = st->chip_info->int_vref_mv;
else if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else
dev_warn(dev, "reference voltage unspecified\n");
ret = devm_regulator_get_enable_read_voltage(dev, "vcc");
if (ret < 0 && ret != -ENODEV)
return ret;
if (ret == -ENODEV) {
if (chip_info->int_vref_mv)
st->vref_mv = chip_info->int_vref_mv;
else
dev_warn(dev, "reference voltage unspecified\n");
} else {
st->vref_mv = ret / 1000;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
return ret;
}
static void ad5446_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5446_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return devm_iio_device_register(dev, indio_dev);
}
#if IS_ENABLED(CONFIG_SPI_MASTER)
@@ -491,18 +458,12 @@ static int ad5446_spi_probe(struct spi_device *spi)
&ad5446_spi_chip_info[id->driver_data]);
}
static void ad5446_spi_remove(struct spi_device *spi)
{
ad5446_remove(&spi->dev);
}
static struct spi_driver ad5446_spi_driver = {
.driver = {
.name = "ad5446",
.of_match_table = ad5446_of_ids,
},
.probe = ad5446_spi_probe,
.remove = ad5446_spi_remove,
.id_table = ad5446_spi_ids,
};
@@ -575,11 +536,6 @@ static int ad5446_i2c_probe(struct i2c_client *i2c)
&ad5446_i2c_chip_info[id->driver_data]);
}
static void ad5446_i2c_remove(struct i2c_client *i2c)
{
ad5446_remove(&i2c->dev);
}
static const struct i2c_device_id ad5446_i2c_ids[] = {
{"ad5301", ID_AD5602},
{"ad5311", ID_AD5612},
@@ -596,7 +552,6 @@ static struct i2c_driver ad5446_i2c_driver = {
.name = "ad5446",
},
.probe = ad5446_i2c_probe,
.remove = ad5446_i2c_remove,
.id_table = ad5446_i2c_ids,
};

View File

@@ -273,35 +273,26 @@ static int ad5504_probe(struct spi_device *spi)
const struct ad5504_platform_data *pdata = dev_get_platdata(&spi->dev);
struct iio_dev *indio_dev;
struct ad5504_state *st;
struct regulator *reg;
int ret, voltage_uv = 0;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(reg)) {
ret = regulator_enable(reg);
if (ret)
return ret;
ret = regulator_get_voltage(reg);
if (ret < 0)
goto error_disable_reg;
st = iio_priv(indio_dev);
voltage_uv = ret;
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc");
if (ret < 0 && ret != -ENODEV)
return ret;
if (ret == -ENODEV) {
if (pdata->vref_mv)
st->vref_mv = pdata->vref_mv;
else
dev_warn(&spi->dev, "reference voltage unspecified\n");
} else {
st->vref_mv = ret / 1000;
}
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else if (pdata)
st->vref_mv = pdata->vref_mv;
else
dev_warn(&spi->dev, "reference voltage unspecified\n");
st->reg = reg;
st->spi = spi;
indio_dev->name = spi_get_device_id(st->spi)->name;
indio_dev->info = &ad5504_info;
@@ -320,31 +311,10 @@ static int ad5504_probe(struct spi_device *spi)
spi_get_device_id(st->spi)->name,
indio_dev);
if (ret)
goto error_disable_reg;
return ret;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
return ret;
}
static void ad5504_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad5504_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad5504_id[] = {
@@ -359,7 +329,6 @@ static struct spi_driver ad5504_driver = {
.name = "ad5504",
},
.probe = ad5504_probe,
.remove = ad5504_remove,
.id_table = ad5504_id,
};
module_spi_driver(ad5504_driver);

View File

@@ -54,7 +54,6 @@ struct ad5624r_chip_info {
struct ad5624r_state {
struct spi_device *us;
const struct ad5624r_chip_info *chip_info;
struct regulator *reg;
unsigned short vref_mv;
unsigned pwr_down_mask;
unsigned pwr_down_mode;

View File

@@ -223,50 +223,26 @@ static int ad5624r_probe(struct spi_device *spi)
{
struct ad5624r_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
bool external_vref;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg = devm_regulator_get_optional(&spi->dev, "vref");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
goto error_disable_reg;
voltage_uv = ret;
} else {
if (PTR_ERR(st->reg) != -ENODEV)
return PTR_ERR(st->reg);
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
if (ret == -ENODEV)
/* Backwards compatibility. This naming is not correct */
st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc");
if (ret < 0 && ret != -ENODEV)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
goto error_disable_reg;
external_vref = ret != -ENODEV;
st->vref_mv = external_vref ? ret / 1000 : st->chip_info->int_vref_mv;
voltage_uv = ret;
}
}
spi_set_drvdata(spi, indio_dev);
st->chip_info =
&ad5624r_chip_info_tbl[spi_get_device_id(spi)->driver_data];
if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else
st->vref_mv = st->chip_info->int_vref_mv;
st->us = spi;
indio_dev->name = spi_get_device_id(spi)->name;
@@ -276,31 +252,11 @@ static int ad5624r_probe(struct spi_device *spi)
indio_dev->num_channels = AD5624R_DAC_CHANNELS;
ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0,
!!voltage_uv, 16);
external_vref, 16);
if (ret)
goto error_disable_reg;
return ret;
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
}
static void ad5624r_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad5624r_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad5624r_id[] = {
@@ -319,7 +275,6 @@ static struct spi_driver ad5624r_driver = {
.name = "ad5624r",
},
.probe = ad5624r_probe,
.remove = ad5624r_remove,
.id_table = ad5624r_id,
};
module_spi_driver(ad5624r_driver);

View File

@@ -53,7 +53,6 @@ enum ad5761_supported_device_ids {
/**
* struct ad5761_state - driver instance specific data
* @spi: spi_device
* @vref_reg: reference voltage regulator
* @use_intref: true when the internal voltage reference is used
* @vref: actual voltage reference in mVolts
* @range: output range mode used
@@ -62,7 +61,6 @@ enum ad5761_supported_device_ids {
*/
struct ad5761_state {
struct spi_device *spi;
struct regulator *vref_reg;
struct mutex lock;
bool use_intref;
@@ -287,63 +285,6 @@ static const struct ad5761_chip_info ad5761_chip_infos[] = {
},
};
static int ad5761_get_vref(struct ad5761_state *st,
const struct ad5761_chip_info *chip_info)
{
int ret;
st->vref_reg = devm_regulator_get_optional(&st->spi->dev, "vref");
if (PTR_ERR(st->vref_reg) == -ENODEV) {
/* Use Internal regulator */
if (!chip_info->int_vref) {
dev_err(&st->spi->dev,
"Voltage reference not found\n");
return -EIO;
}
st->use_intref = true;
st->vref = chip_info->int_vref;
return 0;
}
if (IS_ERR(st->vref_reg)) {
dev_err(&st->spi->dev,
"Error getting voltage reference regulator\n");
return PTR_ERR(st->vref_reg);
}
ret = regulator_enable(st->vref_reg);
if (ret) {
dev_err(&st->spi->dev,
"Failed to enable voltage reference\n");
return ret;
}
ret = regulator_get_voltage(st->vref_reg);
if (ret < 0) {
dev_err(&st->spi->dev,
"Failed to get voltage reference value\n");
goto disable_regulator_vref;
}
if (ret < 2000000 || ret > 3000000) {
dev_warn(&st->spi->dev,
"Invalid external voltage ref. value %d uV\n", ret);
ret = -EIO;
goto disable_regulator_vref;
}
st->vref = ret / 1000;
st->use_intref = false;
return 0;
disable_regulator_vref:
regulator_disable(st->vref_reg);
st->vref_reg = NULL;
return ret;
}
static int ad5761_probe(struct spi_device *spi)
{
struct iio_dev *iio_dev;
@@ -361,11 +302,28 @@ static int ad5761_probe(struct spi_device *spi)
st = iio_priv(iio_dev);
st->spi = spi;
spi_set_drvdata(spi, iio_dev);
ret = ad5761_get_vref(st, chip_info);
if (ret)
return ret;
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(&spi->dev, ret,
"Failed to get voltage reference value\n");
if (ret == -ENODEV) {
/* Use Internal regulator */
if (!chip_info->int_vref)
return dev_err_probe(&spi->dev, -EIO,
"Voltage reference not found\n");
st->use_intref = true;
st->vref = chip_info->int_vref;
} else {
if (ret < 2000000 || ret > 3000000)
return dev_err_probe(&spi->dev, -EIO,
"Invalid external voltage ref. value %d uV\n",
ret);
st->use_intref = false;
st->vref = ret / 1000;
}
if (pdata)
voltage_range = pdata->voltage_range;
@@ -374,35 +332,15 @@ static int ad5761_probe(struct spi_device *spi)
ret = ad5761_spi_set_range(st, voltage_range);
if (ret)
goto disable_regulator_err;
return ret;
iio_dev->info = &ad5761_info;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->channels = &chip_info->channel;
iio_dev->num_channels = 1;
iio_dev->name = spi_get_device_id(st->spi)->name;
ret = iio_device_register(iio_dev);
if (ret)
goto disable_regulator_err;
return 0;
disable_regulator_err:
if (!IS_ERR_OR_NULL(st->vref_reg))
regulator_disable(st->vref_reg);
return ret;
}
static void ad5761_remove(struct spi_device *spi)
{
struct iio_dev *iio_dev = spi_get_drvdata(spi);
struct ad5761_state *st = iio_priv(iio_dev);
iio_device_unregister(iio_dev);
if (!IS_ERR_OR_NULL(st->vref_reg))
regulator_disable(st->vref_reg);
return devm_iio_device_register(&spi->dev, iio_dev);
}
static const struct spi_device_id ad5761_id[] = {
@@ -419,7 +357,6 @@ static struct spi_driver ad5761_driver = {
.name = "ad5761",
},
.probe = ad5761_probe,
.remove = ad5761_remove,
.id_table = ad5761_id,
};
module_spi_driver(ad5761_driver);

View File

@@ -122,7 +122,6 @@ struct ad5770r_out_range {
* struct ad5770r_state - driver instance specific data
* @spi: spi_device
* @regmap: regmap
* @vref_reg: fixed regulator for reference configuration
* @gpio_reset: gpio descriptor
* @output_mode: array contains channels output ranges
* @vref: reference value
@@ -134,7 +133,6 @@ struct ad5770r_out_range {
struct ad5770r_state {
struct spi_device *spi;
struct regmap *regmap;
struct regulator *vref_reg;
struct gpio_desc *gpio_reset;
struct ad5770r_out_range output_mode[AD5770R_MAX_CHANNELS];
int vref;
@@ -591,13 +589,6 @@ static int ad5770r_init(struct ad5770r_state *st)
return ret;
}
static void ad5770r_disable_regulator(void *data)
{
struct ad5770r_state *st = data;
regulator_disable(st->vref_reg);
}
static int ad5770r_probe(struct spi_device *spi)
{
struct ad5770r_state *st;
@@ -622,34 +613,12 @@ static int ad5770r_probe(struct spi_device *spi)
}
st->regmap = regmap;
st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref");
if (!IS_ERR(st->vref_reg)) {
ret = regulator_enable(st->vref_reg);
if (ret) {
dev_err(&spi->dev,
"Failed to enable vref regulators: %d\n", ret);
return ret;
}
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(&spi->dev, ret, "Failed to get vref voltage\n");
ret = devm_add_action_or_reset(&spi->dev,
ad5770r_disable_regulator,
st);
if (ret < 0)
return ret;
ret = regulator_get_voltage(st->vref_reg);
if (ret < 0)
return ret;
st->vref = ret / 1000;
} else {
if (PTR_ERR(st->vref_reg) == -ENODEV) {
st->vref = AD5770R_LOW_VREF_mV;
st->internal_ref = true;
} else {
return PTR_ERR(st->vref_reg);
}
}
st->internal_ref = ret == -ENODEV;
st->vref = st->internal_ref ? AD5770R_LOW_VREF_mV : ret / 1000;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad5770r_info;

View File

@@ -9,6 +9,7 @@
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
@@ -61,11 +62,14 @@
/**
* struct ad5791_chip_info - chip specific information
* @name: name of the dac chip
* @channel: channel specification
* @get_lin_comp: function pointer to the device specific function
*/
struct ad5791_chip_info {
int (*get_lin_comp) (unsigned int span);
const char *name;
const struct iio_chan_spec channel;
int (*get_lin_comp)(unsigned int span);
};
/**
@@ -73,6 +77,9 @@ struct ad5791_chip_info {
* @spi: spi_device
* @reg_vdd: positive supply regulator
* @reg_vss: negative supply regulator
* @gpio_reset: reset gpio
* @gpio_clear: clear gpio
* @gpio_ldac: load dac gpio
* @chip_info: chip model specific constants
* @vref_mv: actual reference voltage used
* @vref_neg_mv: voltage of the negative supply
@@ -85,6 +92,9 @@ struct ad5791_state {
struct spi_device *spi;
struct regulator *reg_vdd;
struct regulator *reg_vss;
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_clear;
struct gpio_desc *gpio_ldac;
const struct ad5791_chip_info *chip_info;
unsigned short vref_mv;
unsigned int vref_neg_mv;
@@ -98,13 +108,6 @@ struct ad5791_state {
} data[3] __aligned(IIO_DMA_MINALIGN);
};
enum ad5791_supported_device_ids {
ID_AD5760,
ID_AD5780,
ID_AD5781,
ID_AD5791,
};
static int ad5791_spi_write(struct ad5791_state *st, u8 addr, u32 val)
{
st->data[0].d32 = cpu_to_be32(AD5791_CMD_WRITE |
@@ -228,20 +231,6 @@ static int ad5780_get_lin_comp(unsigned int span)
else
return AD5780_LINCOMP_10_20;
}
static const struct ad5791_chip_info ad5791_chip_info_tbl[] = {
[ID_AD5760] = {
.get_lin_comp = ad5780_get_lin_comp,
},
[ID_AD5780] = {
.get_lin_comp = ad5780_get_lin_comp,
},
[ID_AD5781] = {
.get_lin_comp = ad5791_get_lin_comp,
},
[ID_AD5791] = {
.get_lin_comp = ad5791_get_lin_comp,
},
};
static int ad5791_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
@@ -289,30 +278,34 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = {
{ },
};
#define AD5791_CHAN(bits, _shift) { \
.type = IIO_VOLTAGE, \
.output = 1, \
.indexed = 1, \
.address = AD5791_ADDR_DAC0, \
.channel = 0, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 24, \
.shift = (_shift), \
}, \
.ext_info = ad5791_ext_info, \
#define AD5791_DEFINE_CHIP_INFO(_name, bits, _shift, _lin_comp) \
static const struct ad5791_chip_info _name##_chip_info = { \
.name = #_name, \
.get_lin_comp = &(_lin_comp), \
.channel = { \
.type = IIO_VOLTAGE, \
.output = 1, \
.indexed = 1, \
.address = AD5791_ADDR_DAC0, \
.channel = 0, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 24, \
.shift = (_shift), \
}, \
.ext_info = ad5791_ext_info, \
}, \
}
static const struct iio_chan_spec ad5791_channels[] = {
[ID_AD5760] = AD5791_CHAN(16, 4),
[ID_AD5780] = AD5791_CHAN(18, 2),
[ID_AD5781] = AD5791_CHAN(18, 2),
[ID_AD5791] = AD5791_CHAN(20, 0)
};
AD5791_DEFINE_CHIP_INFO(ad5760, 16, 4, ad5780_get_lin_comp);
AD5791_DEFINE_CHIP_INFO(ad5780, 18, 2, ad5780_get_lin_comp);
AD5791_DEFINE_CHIP_INFO(ad5781, 18, 2, ad5791_get_lin_comp);
AD5791_DEFINE_CHIP_INFO(ad5790, 20, 0, ad5791_get_lin_comp);
AD5791_DEFINE_CHIP_INFO(ad5791, 20, 0, ad5791_get_lin_comp);
static int ad5791_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
@@ -351,31 +344,21 @@ static int ad5791_probe(struct spi_device *spi)
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg_vdd = devm_regulator_get(&spi->dev, "vdd");
if (!IS_ERR(st->reg_vdd)) {
ret = regulator_enable(st->reg_vdd);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg_vdd);
if (ret < 0)
goto error_disable_reg_pos;
st->gpio_reset = devm_gpiod_get_optional(&spi->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(st->gpio_reset))
return PTR_ERR(st->gpio_reset);
pos_voltage_uv = ret;
}
st->gpio_clear = devm_gpiod_get_optional(&spi->dev, "clear",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_clear))
return PTR_ERR(st->gpio_clear);
st->reg_vss = devm_regulator_get(&spi->dev, "vss");
if (!IS_ERR(st->reg_vss)) {
ret = regulator_enable(st->reg_vss);
if (ret)
goto error_disable_reg_pos;
ret = regulator_get_voltage(st->reg_vss);
if (ret < 0)
goto error_disable_reg_neg;
neg_voltage_uv = ret;
}
st->gpio_ldac = devm_gpiod_get_optional(&spi->dev, "ldac",
GPIOD_OUT_HIGH);
if (IS_ERR(st->gpio_ldac))
return PTR_ERR(st->gpio_ldac);
st->pwr_down = true;
st->spi = spi;
@@ -386,7 +369,17 @@ static int ad5791_probe(struct spi_device *spi)
use_rbuf_gain2 = device_property_read_bool(&spi->dev,
"adi,rbuf-gain2-en");
if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) {
pos_voltage_uv = devm_regulator_get_enable_read_voltage(&spi->dev, "vdd");
if (pos_voltage_uv < 0 && pos_voltage_uv != -ENODEV)
return dev_err_probe(&spi->dev, pos_voltage_uv,
"failed to get vdd voltage\n");
neg_voltage_uv = devm_regulator_get_enable_read_voltage(&spi->dev, "vss");
if (neg_voltage_uv < 0 && neg_voltage_uv != -ENODEV)
return dev_err_probe(&spi->dev, neg_voltage_uv,
"failed to get vss voltage\n");
if (neg_voltage_uv >= 0 && pos_voltage_uv >= 0) {
st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000;
st->vref_neg_mv = neg_voltage_uv / 1000;
} else if (pdata) {
@@ -396,13 +389,18 @@ static int ad5791_probe(struct spi_device *spi)
dev_warn(&spi->dev, "reference voltage unspecified\n");
}
ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET);
if (ret)
goto error_disable_reg_neg;
st->chip_info = &ad5791_chip_info_tbl[spi_get_device_id(spi)
->driver_data];
if (st->gpio_reset) {
fsleep(20);
gpiod_set_value_cansleep(st->gpio_reset, 0);
} else {
ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET);
if (ret)
return dev_err_probe(&spi->dev, ret, "fail to reset\n");
}
st->chip_info = spi_get_device_match_data(spi);
if (!st->chip_info)
return dev_err_probe(&spi->dev, -EINVAL, "no chip info\n");
st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv))
| (use_rbuf_gain2 ? 0 : AD5791_CTRL_RBUF) |
@@ -411,59 +409,42 @@ static int ad5791_probe(struct spi_device *spi)
ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl |
AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
if (ret)
goto error_disable_reg_neg;
return dev_err_probe(&spi->dev, ret, "fail to write ctrl register\n");
spi_set_drvdata(spi, indio_dev);
indio_dev->info = &ad5791_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels
= &ad5791_channels[spi_get_device_id(spi)->driver_data];
indio_dev->channels = &st->chip_info->channel;
indio_dev->num_channels = 1;
indio_dev->name = spi_get_device_id(st->spi)->name;
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg_neg;
return 0;
error_disable_reg_neg:
if (!IS_ERR(st->reg_vss))
regulator_disable(st->reg_vss);
error_disable_reg_pos:
if (!IS_ERR(st->reg_vdd))
regulator_disable(st->reg_vdd);
return ret;
indio_dev->name = st->chip_info->name;
return devm_iio_device_register(&spi->dev, indio_dev);
}
static void ad5791_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad5791_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg_vdd))
regulator_disable(st->reg_vdd);
if (!IS_ERR(st->reg_vss))
regulator_disable(st->reg_vss);
}
static const struct of_device_id ad5791_of_match[] = {
{ .compatible = "adi,ad5760", .data = &ad5760_chip_info },
{ .compatible = "adi,ad5780", .data = &ad5780_chip_info },
{ .compatible = "adi,ad5781", .data = &ad5781_chip_info },
{ .compatible = "adi,ad5790", .data = &ad5790_chip_info },
{ .compatible = "adi,ad5791", .data = &ad5791_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad5791_of_match);
static const struct spi_device_id ad5791_id[] = {
{"ad5760", ID_AD5760},
{"ad5780", ID_AD5780},
{"ad5781", ID_AD5781},
{"ad5790", ID_AD5791},
{"ad5791", ID_AD5791},
{}
{ "ad5760", (kernel_ulong_t)&ad5760_chip_info },
{ "ad5780", (kernel_ulong_t)&ad5780_chip_info },
{ "ad5781", (kernel_ulong_t)&ad5781_chip_info },
{ "ad5790", (kernel_ulong_t)&ad5790_chip_info },
{ "ad5791", (kernel_ulong_t)&ad5791_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad5791_id);
static struct spi_driver ad5791_driver = {
.driver = {
.name = "ad5791",
.of_match_table = ad5791_of_match,
},
.probe = ad5791_probe,
.remove = ad5791_remove,
.id_table = ad5791_id,
};
module_spi_driver(ad5791_driver);

View File

@@ -573,7 +573,7 @@ static int ad8460_read_event_value(struct iio_dev *indio_dev,
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)
enum iio_event_direction dir, bool val)
{
struct ad8460_state *state = iio_priv(indio_dev);
int fault;
@@ -924,17 +924,24 @@ static int ad8460_probe(struct spi_device *spi)
}
static const struct of_device_id ad8460_of_match[] = {
{ .compatible = "adi, ad8460" },
{ .compatible = "adi,ad8460" },
{ }
};
MODULE_DEVICE_TABLE(of, ad8460_of_match);
static const struct spi_device_id ad8460_spi_match[] = {
{ .name = "ad8460" },
{ }
};
MODULE_DEVICE_TABLE(spi, ad8460_spi_match);
static struct spi_driver ad8460_driver = {
.driver = {
.name = "ad8460",
.of_match_table = ad8460_of_match,
},
.probe = ad8460_probe,
.id_table = ad8460_spi_match,
};
module_spi_driver(ad8460_driver);

View File

@@ -29,6 +29,8 @@
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include "ad3552r-hs.h"
/*
* Register definitions:
* https://wiki.analog.com/resources/fpga/docs/axi_dac_ip#register_map
@@ -46,9 +48,28 @@
#define AXI_DAC_CNTRL_1_REG 0x0044
#define AXI_DAC_CNTRL_1_SYNC BIT(0)
#define AXI_DAC_CNTRL_2_REG 0x0048
#define AXI_DAC_CNTRL_2_SDR_DDR_N BIT(16)
#define AXI_DAC_CNTRL_2_SYMB_8B BIT(14)
#define ADI_DAC_CNTRL_2_R1_MODE BIT(5)
#define AXI_DAC_CNTRL_2_UNSIGNED_DATA BIT(4)
#define AXI_DAC_STATUS_1_REG 0x0054
#define AXI_DAC_STATUS_2_REG 0x0058
#define AXI_DAC_DRP_STATUS_REG 0x0074
#define AXI_DAC_DRP_STATUS_DRP_LOCKED BIT(17)
#define AXI_DAC_CUSTOM_RD_REG 0x0080
#define AXI_DAC_CUSTOM_WR_REG 0x0084
#define AXI_DAC_CUSTOM_WR_DATA_8 GENMASK(23, 16)
#define AXI_DAC_CUSTOM_WR_DATA_16 GENMASK(23, 8)
#define AXI_DAC_UI_STATUS_REG 0x0088
#define AXI_DAC_UI_STATUS_IF_BUSY BIT(4)
#define AXI_DAC_CUSTOM_CTRL_REG 0x008C
#define AXI_DAC_CUSTOM_CTRL_ADDRESS GENMASK(31, 24)
#define AXI_DAC_CUSTOM_CTRL_SYNCED_TRANSFER BIT(2)
#define AXI_DAC_CUSTOM_CTRL_STREAM BIT(1)
#define AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA BIT(0)
#define AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE (AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA | \
AXI_DAC_CUSTOM_CTRL_STREAM)
/* DAC Channel controls */
#define AXI_DAC_CHAN_CNTRL_1_REG(c) (0x0400 + (c) * 0x40)
@@ -63,12 +84,22 @@
#define AXI_DAC_CHAN_CNTRL_7_REG(c) (0x0418 + (c) * 0x40)
#define AXI_DAC_CHAN_CNTRL_7_DATA_SEL GENMASK(3, 0)
#define AXI_DAC_RD_ADDR(x) (BIT(7) | (x))
/* 360 degrees in rad */
#define AXI_DAC_2_PI_MEGA 6283190
enum {
AXI_DAC_DATA_INTERNAL_TONE,
AXI_DAC_DATA_DMA = 2,
AXI_DAC_DATA_INTERNAL_RAMP_16BIT = 11,
};
struct axi_dac_info {
unsigned int version;
const struct iio_backend_info *backend_info;
bool has_dac_clk;
bool has_child_nodes;
};
struct axi_dac_state {
@@ -79,9 +110,11 @@ struct axi_dac_state {
* data/variables.
*/
struct mutex lock;
const struct axi_dac_info *info;
u64 dac_clk;
u32 reg_config;
bool int_tone;
int dac_clk_rate;
};
static int axi_dac_enable(struct iio_backend *back)
@@ -471,6 +504,11 @@ static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan,
AXI_DAC_CHAN_CNTRL_7_REG(chan),
AXI_DAC_CHAN_CNTRL_7_DATA_SEL,
AXI_DAC_DATA_DMA);
case IIO_BACKEND_INTERNAL_RAMP_16BIT:
return regmap_update_bits(st->regmap,
AXI_DAC_CHAN_CNTRL_7_REG(chan),
AXI_DAC_CHAN_CNTRL_7_DATA_SEL,
AXI_DAC_DATA_INTERNAL_RAMP_16BIT);
default:
return -EINVAL;
}
@@ -528,6 +566,184 @@ static int axi_dac_reg_access(struct iio_backend *back, unsigned int reg,
return regmap_write(st->regmap, reg, writeval);
}
static int axi_dac_ddr_enable(struct iio_backend *back)
{
struct axi_dac_state *st = iio_backend_get_priv(back);
return regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
AXI_DAC_CNTRL_2_SDR_DDR_N);
}
static int axi_dac_ddr_disable(struct iio_backend *back)
{
struct axi_dac_state *st = iio_backend_get_priv(back);
return regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
AXI_DAC_CNTRL_2_SDR_DDR_N);
}
static int axi_dac_data_stream_enable(struct iio_backend *back)
{
struct axi_dac_state *st = iio_backend_get_priv(back);
return regmap_set_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE);
}
static int axi_dac_data_stream_disable(struct iio_backend *back)
{
struct axi_dac_state *st = iio_backend_get_priv(back);
return regmap_clear_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE);
}
static int axi_dac_data_transfer_addr(struct iio_backend *back, u32 address)
{
struct axi_dac_state *st = iio_backend_get_priv(back);
if (address > FIELD_MAX(AXI_DAC_CUSTOM_CTRL_ADDRESS))
return -EINVAL;
/*
* Sample register address, when the DAC is configured, or stream
* start address when the FSM is in stream state.
*/
return regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
AXI_DAC_CUSTOM_CTRL_ADDRESS,
FIELD_PREP(AXI_DAC_CUSTOM_CTRL_ADDRESS,
address));
}
static int axi_dac_data_format_set(struct iio_backend *back, unsigned int ch,
const struct iio_backend_data_fmt *data)
{
struct axi_dac_state *st = iio_backend_get_priv(back);
switch (data->type) {
case IIO_BACKEND_DATA_UNSIGNED:
return regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
AXI_DAC_CNTRL_2_UNSIGNED_DATA);
default:
return -EINVAL;
}
}
static int __axi_dac_bus_reg_write(struct iio_backend *back, u32 reg,
u32 val, size_t data_size)
{
struct axi_dac_state *st = iio_backend_get_priv(back);
int ret;
u32 ival;
/*
* Both AXI_DAC_CNTRL_2_REG and AXI_DAC_CUSTOM_WR_REG need to know
* the data size. So keeping data size control here only,
* since data size is mandatory for the current transfer.
* DDR state handled separately by specific backend calls,
* generally all raw register writes are SDR.
*/
if (data_size == sizeof(u16))
ival = FIELD_PREP(AXI_DAC_CUSTOM_WR_DATA_16, val);
else
ival = FIELD_PREP(AXI_DAC_CUSTOM_WR_DATA_8, val);
ret = regmap_write(st->regmap, AXI_DAC_CUSTOM_WR_REG, ival);
if (ret)
return ret;
if (data_size == sizeof(u8))
ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
AXI_DAC_CNTRL_2_SYMB_8B);
else
ret = regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
AXI_DAC_CNTRL_2_SYMB_8B);
if (ret)
return ret;
ret = regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
AXI_DAC_CUSTOM_CTRL_ADDRESS,
FIELD_PREP(AXI_DAC_CUSTOM_CTRL_ADDRESS, reg));
if (ret)
return ret;
ret = regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA,
AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA);
if (ret)
return ret;
ret = regmap_read_poll_timeout(st->regmap,
AXI_DAC_UI_STATUS_REG, ival,
FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, ival) == 0,
10, 100 * KILO);
if (ret == -ETIMEDOUT)
dev_err(st->dev, "AXI read timeout\n");
/* Cleaning always AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA */
return regmap_clear_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA);
}
static int axi_dac_bus_reg_write(struct iio_backend *back, u32 reg,
u32 val, size_t data_size)
{
struct axi_dac_state *st = iio_backend_get_priv(back);
guard(mutex)(&st->lock);
return __axi_dac_bus_reg_write(back, reg, val, data_size);
}
static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val,
size_t data_size)
{
struct axi_dac_state *st = iio_backend_get_priv(back);
int ret;
guard(mutex)(&st->lock);
/*
* SPI, we write with read flag, then we read just at the AXI
* io address space to get data read.
*/
ret = __axi_dac_bus_reg_write(back, AXI_DAC_RD_ADDR(reg), 0,
data_size);
if (ret)
return ret;
return regmap_read(st->regmap, AXI_DAC_CUSTOM_RD_REG, val);
}
static void axi_dac_child_remove(void *data)
{
platform_device_unregister(data);
}
static int axi_dac_create_platform_device(struct axi_dac_state *st,
struct fwnode_handle *child)
{
struct ad3552r_hs_platform_data pdata = {
.bus_reg_read = axi_dac_bus_reg_read,
.bus_reg_write = axi_dac_bus_reg_write,
.bus_sample_data_clock_hz = st->dac_clk_rate,
};
struct platform_device_info pi = {
.parent = st->dev,
.name = fwnode_get_name(child),
.id = PLATFORM_DEVID_AUTO,
.fwnode = child,
.data = &pdata,
.size_data = sizeof(pdata),
};
struct platform_device *pdev;
pdev = platform_device_register_full(&pi);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
return devm_add_action_or_reset(st->dev, axi_dac_child_remove, pdev);
}
static const struct iio_backend_ops axi_dac_generic_ops = {
.enable = axi_dac_enable,
.disable = axi_dac_disable,
@@ -541,11 +757,30 @@ static const struct iio_backend_ops axi_dac_generic_ops = {
.debugfs_reg_access = iio_backend_debugfs_ptr(axi_dac_reg_access),
};
static const struct iio_backend_ops axi_ad3552r_ops = {
.enable = axi_dac_enable,
.disable = axi_dac_disable,
.request_buffer = axi_dac_request_buffer,
.free_buffer = axi_dac_free_buffer,
.data_source_set = axi_dac_data_source_set,
.ddr_enable = axi_dac_ddr_enable,
.ddr_disable = axi_dac_ddr_disable,
.data_stream_enable = axi_dac_data_stream_enable,
.data_stream_disable = axi_dac_data_stream_disable,
.data_format_set = axi_dac_data_format_set,
.data_transfer_addr = axi_dac_data_transfer_addr,
};
static const struct iio_backend_info axi_dac_generic = {
.name = "axi-dac",
.ops = &axi_dac_generic_ops,
};
static const struct iio_backend_info axi_ad3552r = {
.name = "axi-ad3552r",
.ops = &axi_ad3552r_ops,
};
static const struct regmap_config axi_dac_regmap_config = {
.val_bits = 32,
.reg_bits = 32,
@@ -555,7 +790,6 @@ static const struct regmap_config axi_dac_regmap_config = {
static int axi_dac_probe(struct platform_device *pdev)
{
const unsigned int *expected_ver;
struct axi_dac_state *st;
void __iomem *base;
unsigned int ver;
@@ -566,14 +800,29 @@ static int axi_dac_probe(struct platform_device *pdev)
if (!st)
return -ENOMEM;
expected_ver = device_get_match_data(&pdev->dev);
if (!expected_ver)
st->info = device_get_match_data(&pdev->dev);
if (!st->info)
return -ENODEV;
clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk");
if (IS_ERR(clk)) {
/* Backward compat., old fdt versions without clock-names. */
clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk))
return dev_err_probe(&pdev->dev, PTR_ERR(clk),
"failed to get clock\n");
}
clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk))
return dev_err_probe(&pdev->dev, PTR_ERR(clk),
"failed to get clock\n");
if (st->info->has_dac_clk) {
struct clk *dac_clk;
dac_clk = devm_clk_get_enabled(&pdev->dev, "dac_clk");
if (IS_ERR(dac_clk))
return dev_err_probe(&pdev->dev, PTR_ERR(dac_clk),
"failed to get dac_clk clock\n");
/* We only care about the streaming mode rate */
st->dac_clk_rate = clk_get_rate(dac_clk) / 2;
}
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
@@ -598,12 +847,13 @@ static int axi_dac_probe(struct platform_device *pdev)
if (ret)
return ret;
if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) {
if (ADI_AXI_PCORE_VER_MAJOR(ver) !=
ADI_AXI_PCORE_VER_MAJOR(st->info->version)) {
dev_err(&pdev->dev,
"Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n",
ADI_AXI_PCORE_VER_MAJOR(*expected_ver),
ADI_AXI_PCORE_VER_MINOR(*expected_ver),
ADI_AXI_PCORE_VER_PATCH(*expected_ver),
ADI_AXI_PCORE_VER_MAJOR(st->info->version),
ADI_AXI_PCORE_VER_MINOR(st->info->version),
ADI_AXI_PCORE_VER_PATCH(st->info->version),
ADI_AXI_PCORE_VER_MAJOR(ver),
ADI_AXI_PCORE_VER_MINOR(ver),
ADI_AXI_PCORE_VER_PATCH(ver));
@@ -629,11 +879,34 @@ static int axi_dac_probe(struct platform_device *pdev)
return ret;
mutex_init(&st->lock);
ret = devm_iio_backend_register(&pdev->dev, &axi_dac_generic, st);
ret = devm_iio_backend_register(&pdev->dev, st->info->backend_info, st);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"failed to register iio backend\n");
device_for_each_child_node_scoped(&pdev->dev, child) {
int val;
if (!st->info->has_child_nodes)
return dev_err_probe(&pdev->dev, -EINVAL,
"invalid fdt axi-dac compatible.");
/* Processing only reg 0 node */
ret = fwnode_property_read_u32(child, "reg", &val);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"invalid reg property.");
if (val != 0)
return dev_err_probe(&pdev->dev, -EINVAL,
"invalid node address.");
ret = axi_dac_create_platform_device(st, child);
if (ret)
return dev_err_probe(&pdev->dev, -EINVAL,
"cannot create device.");
}
dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n",
ADI_AXI_PCORE_VER_MAJOR(ver),
ADI_AXI_PCORE_VER_MINOR(ver),
@@ -642,10 +915,21 @@ static int axi_dac_probe(struct platform_device *pdev)
return 0;
}
static unsigned int axi_dac_9_1_b_info = ADI_AXI_PCORE_VER(9, 1, 'b');
static const struct axi_dac_info dac_generic = {
.version = ADI_AXI_PCORE_VER(9, 1, 'b'),
.backend_info = &axi_dac_generic,
};
static const struct axi_dac_info dac_ad3552r = {
.version = ADI_AXI_PCORE_VER(9, 1, 'b'),
.backend_info = &axi_ad3552r,
.has_dac_clk = true,
.has_child_nodes = true,
};
static const struct of_device_id axi_dac_of_match[] = {
{ .compatible = "adi,axi-dac-9.1.b", .data = &axi_dac_9_1_b_info },
{ .compatible = "adi,axi-dac-9.1.b", .data = &dac_generic },
{ .compatible = "adi,axi-ad3552r", .data = &dac_ad3552r },
{}
};
MODULE_DEVICE_TABLE(of, axi_dac_of_match);

View File

@@ -60,7 +60,7 @@ int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state);
bool state);
int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,

View File

@@ -53,7 +53,7 @@ int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
struct iio_dummy_state *st = iio_priv(indio_dev);
@@ -183,36 +183,34 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
switch (st->regs->reg_data) {
case 0:
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
IIO_EV_DIR_RISING,
IIO_EV_TYPE_THRESH, 0, 0, 0),
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
st->event_timestamp);
break;
case 1:
if (st->activity_running > st->event_val)
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_ACTIVITY, 0,
IIO_MOD_RUNNING,
IIO_EV_DIR_RISING,
IIO_EV_TYPE_THRESH,
0, 0, 0),
IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0,
IIO_MOD_RUNNING,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
st->event_timestamp);
break;
case 2:
if (st->activity_walking < st->event_val)
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_ACTIVITY, 0,
IIO_MOD_WALKING,
IIO_EV_DIR_FALLING,
IIO_EV_TYPE_THRESH,
0, 0, 0),
IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0,
IIO_MOD_WALKING,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
st->event_timestamp);
break;
case 3:
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
IIO_EV_DIR_NONE,
IIO_EV_TYPE_CHANGE, 0, 0, 0),
IIO_UNMOD_EVENT_CODE(IIO_STEPS, 0,
IIO_EV_TYPE_CHANGE,
IIO_EV_DIR_NONE),
st->event_timestamp);
break;
default:

View File

@@ -27,7 +27,7 @@ config ADIS16136
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for the Analog Devices ADIS16133, ADIS16135,
ADIS16136 gyroscope devices.
ADIS16136, ADIS16137 gyroscope devices.
config ADIS16260
tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver"

View File

@@ -8,7 +8,6 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
@@ -444,7 +443,7 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
static int bmg160_get_bw(struct bmg160_data *data, int *val)
{
struct device *dev = regmap_get_device(data->regmap);
struct device *dev = regmap_get_device(data->regmap);
int i;
unsigned int bw_bits;
int ret;
@@ -749,7 +748,7 @@ static int bmg160_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
bool state)
{
struct bmg160_data *data = iio_priv(indio_dev);
int ret;
@@ -1055,17 +1054,6 @@ static const struct iio_buffer_setup_ops bmg160_buffer_setup_ops = {
.postdisable = bmg160_buffer_postdisable,
};
static const char *bmg160_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return NULL;
return dev_name(dev);
}
int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name)
{
@@ -1098,9 +1086,6 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
mutex_init(&data->mutex);
if (ACPI_HANDLE(dev))
name = bmg160_match_acpi_device(dev);
indio_dev->channels = bmg160_channels;
indio_dev->num_channels = ARRAY_SIZE(bmg160_channels);
indio_dev->name = name;

View File

@@ -17,7 +17,7 @@ static int bmg160_i2c_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct regmap *regmap;
const char *name = NULL;
const char *name;
regmap = devm_regmap_init_i2c(client, &bmg160_regmap_i2c_conf);
if (IS_ERR(regmap)) {
@@ -28,6 +28,8 @@ static int bmg160_i2c_probe(struct i2c_client *client)
if (id)
name = id->name;
else
name = iio_get_acpi_device_name(&client->dev);
return bmg160_core_probe(&client->dev, regmap, client->irq, name);
}
@@ -39,8 +41,6 @@ static void bmg160_i2c_remove(struct i2c_client *client)
static const struct acpi_device_id bmg160_acpi_match[] = {
{"BMG0160", 0},
{"BMI055B", 0},
{"BMI088B", 0},
{},
};

View File

@@ -97,6 +97,20 @@ config KMX61
source "drivers/iio/imu/inv_icm42600/Kconfig"
source "drivers/iio/imu/inv_mpu6050/Kconfig"
config SMI240
tristate "Bosch Sensor SMI240 Inertial Measurement Unit"
depends on SPI
select REGMAP_SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
If you say yes here you get support for SMI240 IMU on SPI with
accelerometer and gyroscope.
This driver can also be built as a module. If so, the module will be
called smi240.
source "drivers/iio/imu/st_lsm6dsx/Kconfig"
source "drivers/iio/imu/st_lsm9ds0/Kconfig"

View File

@@ -28,5 +28,7 @@ obj-y += inv_mpu6050/
obj-$(CONFIG_KMX61) += kmx61.o
obj-$(CONFIG_SMI240) += smi240.o
obj-y += st_lsm6dsx/
obj-y += st_lsm9ds0/

View File

@@ -6,6 +6,7 @@
config BMI270
tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config BMI270_I2C
tristate "Bosch BMI270 I2C driver"

View File

@@ -10,10 +10,29 @@ struct device;
struct bmi270_data {
struct device *dev;
struct regmap *regmap;
const struct bmi270_chip_info *chip_info;
/*
* Where IIO_DMA_MINALIGN may be larger than 8 bytes, align to
* that to ensure a DMA safe buffer.
*/
struct {
__le16 channels[6];
aligned_s64 timestamp;
} data __aligned(IIO_DMA_MINALIGN);
};
struct bmi270_chip_info {
const char *name;
int chip_id;
const char *fw_name;
};
extern const struct regmap_config bmi270_regmap_config;
extern const struct bmi270_chip_info bmi260_chip_info;
extern const struct bmi270_chip_info bmi270_chip_info;
int bmi270_core_probe(struct device *dev, struct regmap *regmap);
int bmi270_core_probe(struct device *dev, struct regmap *regmap,
const struct bmi270_chip_info *chip_info);
#endif /* BMI270_H_ */

View File

@@ -7,10 +7,18 @@
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include "bmi270.h"
#define BMI270_CHIP_ID_REG 0x00
/* Checked to prevent sending incompatible firmware to BMI160 devices */
#define BMI160_CHIP_ID_VAL 0xD1
#define BMI260_CHIP_ID_VAL 0x27
#define BMI270_CHIP_ID_VAL 0x24
#define BMI270_CHIP_ID_MSK GENMASK(7, 0)
@@ -31,6 +39,9 @@
#define BMI270_ACC_CONF_BWP_NORMAL_MODE 0x02
#define BMI270_ACC_CONF_FILTER_PERF_MSK BIT(7)
#define BMI270_ACC_CONF_RANGE_REG 0x41
#define BMI270_ACC_CONF_RANGE_MSK GENMASK(1, 0)
#define BMI270_GYR_CONF_REG 0x42
#define BMI270_GYR_CONF_ODR_MSK GENMASK(3, 0)
#define BMI270_GYR_CONF_ODR_200HZ 0x09
@@ -39,6 +50,9 @@
#define BMI270_GYR_CONF_NOISE_PERF_MSK BIT(6)
#define BMI270_GYR_CONF_FILTER_PERF_MSK BIT(7)
#define BMI270_GYR_CONF_RANGE_REG 0x43
#define BMI270_GYR_CONF_RANGE_MSK GENMASK(2, 0)
#define BMI270_INIT_CTRL_REG 0x59
#define BMI270_INIT_CTRL_LOAD_DONE_MSK BIT(0)
@@ -55,6 +69,7 @@
#define BMI270_PWR_CTRL_ACCEL_EN_MSK BIT(2)
#define BMI270_PWR_CTRL_TEMP_EN_MSK BIT(3)
#define BMI260_INIT_DATA_FILE "bmi260-init-data.fw"
#define BMI270_INIT_DATA_FILE "bmi270-init-data.fw"
enum bmi270_scan {
@@ -64,8 +79,312 @@ enum bmi270_scan {
BMI270_SCAN_GYRO_X,
BMI270_SCAN_GYRO_Y,
BMI270_SCAN_GYRO_Z,
BMI270_SCAN_TIMESTAMP,
};
static const unsigned long bmi270_avail_scan_masks[] = {
(BIT(BMI270_SCAN_ACCEL_X) |
BIT(BMI270_SCAN_ACCEL_Y) |
BIT(BMI270_SCAN_ACCEL_Z) |
BIT(BMI270_SCAN_GYRO_X) |
BIT(BMI270_SCAN_GYRO_Y) |
BIT(BMI270_SCAN_GYRO_Z)),
0
};
const struct bmi270_chip_info bmi260_chip_info = {
.name = "bmi260",
.chip_id = BMI260_CHIP_ID_VAL,
.fw_name = BMI260_INIT_DATA_FILE,
};
EXPORT_SYMBOL_NS_GPL(bmi260_chip_info, IIO_BMI270);
const struct bmi270_chip_info bmi270_chip_info = {
.name = "bmi270",
.chip_id = BMI270_CHIP_ID_VAL,
.fw_name = BMI270_INIT_DATA_FILE,
};
EXPORT_SYMBOL_NS_GPL(bmi270_chip_info, IIO_BMI270);
enum bmi270_sensor_type {
BMI270_ACCEL = 0,
BMI270_GYRO,
};
struct bmi270_scale {
int scale;
int uscale;
};
struct bmi270_odr {
int odr;
int uodr;
};
static const struct bmi270_scale bmi270_accel_scale[] = {
{ 0, 598 },
{ 0, 1197 },
{ 0, 2394 },
{ 0, 4788 },
};
static const struct bmi270_scale bmi270_gyro_scale[] = {
{ 0, 1065 },
{ 0, 532 },
{ 0, 266 },
{ 0, 133 },
{ 0, 66 },
};
struct bmi270_scale_item {
const struct bmi270_scale *tbl;
int num;
};
static const struct bmi270_scale_item bmi270_scale_table[] = {
[BMI270_ACCEL] = {
.tbl = bmi270_accel_scale,
.num = ARRAY_SIZE(bmi270_accel_scale),
},
[BMI270_GYRO] = {
.tbl = bmi270_gyro_scale,
.num = ARRAY_SIZE(bmi270_gyro_scale),
},
};
static const struct bmi270_odr bmi270_accel_odr[] = {
{ 0, 781250 },
{ 1, 562500 },
{ 3, 125000 },
{ 6, 250000 },
{ 12, 500000 },
{ 25, 0 },
{ 50, 0 },
{ 100, 0 },
{ 200, 0 },
{ 400, 0 },
{ 800, 0 },
{ 1600, 0 },
};
static const u8 bmi270_accel_odr_vals[] = {
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0A,
0x0B,
0x0C,
};
static const struct bmi270_odr bmi270_gyro_odr[] = {
{ 25, 0 },
{ 50, 0 },
{ 100, 0 },
{ 200, 0 },
{ 400, 0 },
{ 800, 0 },
{ 1600, 0 },
{ 3200, 0 },
};
static const u8 bmi270_gyro_odr_vals[] = {
0x06,
0x07,
0x08,
0x09,
0x0A,
0x0B,
0x0C,
0x0D,
};
struct bmi270_odr_item {
const struct bmi270_odr *tbl;
const u8 *vals;
int num;
};
static const struct bmi270_odr_item bmi270_odr_table[] = {
[BMI270_ACCEL] = {
.tbl = bmi270_accel_odr,
.vals = bmi270_accel_odr_vals,
.num = ARRAY_SIZE(bmi270_accel_odr),
},
[BMI270_GYRO] = {
.tbl = bmi270_gyro_odr,
.vals = bmi270_gyro_odr_vals,
.num = ARRAY_SIZE(bmi270_gyro_odr),
},
};
static int bmi270_set_scale(struct bmi270_data *data, int chan_type, int uscale)
{
int i;
int reg, mask;
struct bmi270_scale_item bmi270_scale_item;
switch (chan_type) {
case IIO_ACCEL:
reg = BMI270_ACC_CONF_RANGE_REG;
mask = BMI270_ACC_CONF_RANGE_MSK;
bmi270_scale_item = bmi270_scale_table[BMI270_ACCEL];
break;
case IIO_ANGL_VEL:
reg = BMI270_GYR_CONF_RANGE_REG;
mask = BMI270_GYR_CONF_RANGE_MSK;
bmi270_scale_item = bmi270_scale_table[BMI270_GYRO];
break;
default:
return -EINVAL;
}
for (i = 0; i < bmi270_scale_item.num; i++) {
if (bmi270_scale_item.tbl[i].uscale != uscale)
continue;
return regmap_update_bits(data->regmap, reg, mask, i);
}
return -EINVAL;
}
static int bmi270_get_scale(struct bmi270_data *bmi270_device, int chan_type,
int *uscale)
{
int ret;
unsigned int val;
struct bmi270_scale_item bmi270_scale_item;
switch (chan_type) {
case IIO_ACCEL:
ret = regmap_read(bmi270_device->regmap,
BMI270_ACC_CONF_RANGE_REG, &val);
if (ret)
return ret;
val = FIELD_GET(BMI270_ACC_CONF_RANGE_MSK, val);
bmi270_scale_item = bmi270_scale_table[BMI270_ACCEL];
break;
case IIO_ANGL_VEL:
ret = regmap_read(bmi270_device->regmap,
BMI270_GYR_CONF_RANGE_REG, &val);
if (ret)
return ret;
val = FIELD_GET(BMI270_GYR_CONF_RANGE_MSK, val);
bmi270_scale_item = bmi270_scale_table[BMI270_GYRO];
break;
default:
return -EINVAL;
}
if (val >= bmi270_scale_item.num)
return -EINVAL;
*uscale = bmi270_scale_item.tbl[val].uscale;
return 0;
}
static int bmi270_set_odr(struct bmi270_data *data, int chan_type, int odr,
int uodr)
{
int i;
int reg, mask;
struct bmi270_odr_item bmi270_odr_item;
switch (chan_type) {
case IIO_ACCEL:
reg = BMI270_ACC_CONF_REG;
mask = BMI270_ACC_CONF_ODR_MSK;
bmi270_odr_item = bmi270_odr_table[BMI270_ACCEL];
break;
case IIO_ANGL_VEL:
reg = BMI270_GYR_CONF_REG;
mask = BMI270_GYR_CONF_ODR_MSK;
bmi270_odr_item = bmi270_odr_table[BMI270_GYRO];
break;
default:
return -EINVAL;
}
for (i = 0; i < bmi270_odr_item.num; i++) {
if (bmi270_odr_item.tbl[i].odr != odr ||
bmi270_odr_item.tbl[i].uodr != uodr)
continue;
return regmap_update_bits(data->regmap, reg, mask,
bmi270_odr_item.vals[i]);
}
return -EINVAL;
}
static int bmi270_get_odr(struct bmi270_data *data, int chan_type, int *odr,
int *uodr)
{
int i, val, ret;
struct bmi270_odr_item bmi270_odr_item;
switch (chan_type) {
case IIO_ACCEL:
ret = regmap_read(data->regmap, BMI270_ACC_CONF_REG, &val);
if (ret)
return ret;
val = FIELD_GET(BMI270_ACC_CONF_ODR_MSK, val);
bmi270_odr_item = bmi270_odr_table[BMI270_ACCEL];
break;
case IIO_ANGL_VEL:
ret = regmap_read(data->regmap, BMI270_GYR_CONF_REG, &val);
if (ret)
return ret;
val = FIELD_GET(BMI270_GYR_CONF_ODR_MSK, val);
bmi270_odr_item = bmi270_odr_table[BMI270_GYRO];
break;
default:
return -EINVAL;
}
for (i = 0; i < bmi270_odr_item.num; i++) {
if (val != bmi270_odr_item.vals[i])
continue;
*odr = bmi270_odr_item.tbl[i].odr;
*uodr = bmi270_odr_item.tbl[i].uodr;
return 0;
}
return -EINVAL;
}
static irqreturn_t bmi270_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmi270_data *bmi270_device = iio_priv(indio_dev);
int ret;
ret = regmap_bulk_read(bmi270_device->regmap, BMI270_ACCEL_X_REG,
&bmi270_device->data.channels,
sizeof(bmi270_device->data.channels));
if (ret)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, &bmi270_device->data,
pf->timestamp);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int bmi270_get_data(struct bmi270_data *bmi270_device,
int chan_type, int axis, int *val)
{
@@ -107,6 +426,68 @@ static int bmi270_read_raw(struct iio_dev *indio_dev,
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
ret = bmi270_get_scale(bmi270_device, chan->type, val2);
return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = bmi270_get_odr(bmi270_device, chan->type, val, val2);
return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static int bmi270_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct bmi270_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
return bmi270_set_scale(data, chan->type, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
return bmi270_set_odr(data, chan->type, val, val2);
default:
return -EINVAL;
}
}
static int bmi270_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
*type = IIO_VAL_INT_PLUS_MICRO;
switch (chan->type) {
case IIO_ANGL_VEL:
*vals = (const int *)bmi270_gyro_scale;
*length = ARRAY_SIZE(bmi270_gyro_scale) * 2;
return IIO_AVAIL_LIST;
case IIO_ACCEL:
*vals = (const int *)bmi270_accel_scale;
*length = ARRAY_SIZE(bmi270_accel_scale) * 2;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
*type = IIO_VAL_INT_PLUS_MICRO;
switch (chan->type) {
case IIO_ANGL_VEL:
*vals = (const int *)bmi270_gyro_odr;
*length = ARRAY_SIZE(bmi270_gyro_odr) * 2;
return IIO_AVAIL_LIST;
case IIO_ACCEL:
*vals = (const int *)bmi270_accel_odr;
*length = ARRAY_SIZE(bmi270_accel_odr) * 2;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
@@ -114,6 +495,8 @@ static int bmi270_read_raw(struct iio_dev *indio_dev,
static const struct iio_info bmi270_info = {
.read_raw = bmi270_read_raw,
.write_raw = bmi270_write_raw,
.read_avail = bmi270_read_avail,
};
#define BMI270_ACCEL_CHANNEL(_axis) { \
@@ -122,7 +505,17 @@ static const struct iio_info bmi270_info = {
.channel2 = IIO_MOD_##_axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_FREQUENCY), \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.info_mask_shared_by_type_available = \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = BMI270_SCAN_ACCEL_##_axis, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_LE, \
}, \
}
#define BMI270_ANG_VEL_CHANNEL(_axis) { \
@@ -131,7 +524,17 @@ static const struct iio_info bmi270_info = {
.channel2 = IIO_MOD_##_axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_FREQUENCY), \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.info_mask_shared_by_type_available = \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = BMI270_SCAN_GYRO_##_axis, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_LE, \
}, \
}
static const struct iio_chan_spec bmi270_channels[] = {
@@ -141,6 +544,7 @@ static const struct iio_chan_spec bmi270_channels[] = {
BMI270_ANG_VEL_CHANNEL(X),
BMI270_ANG_VEL_CHANNEL(Y),
BMI270_ANG_VEL_CHANNEL(Z),
IIO_CHAN_SOFT_TIMESTAMP(BMI270_SCAN_TIMESTAMP),
};
static int bmi270_validate_chip_id(struct bmi270_data *bmi270_device)
@@ -154,8 +558,21 @@ static int bmi270_validate_chip_id(struct bmi270_data *bmi270_device)
if (ret)
return dev_err_probe(dev, ret, "Failed to read chip id");
if (chip_id != BMI270_CHIP_ID_VAL)
dev_info(dev, "Unknown chip id 0x%x", chip_id);
/*
* Some manufacturers use "BMI0160" for both the BMI160 and
* BMI260. If the device is actually a BMI160, the bmi160
* driver should handle it and this driver should not.
*/
if (chip_id == BMI160_CHIP_ID_VAL)
return -ENODEV;
if (chip_id != bmi270_device->chip_info->chip_id)
dev_info(dev, "Unexpected chip id 0x%x", chip_id);
if (chip_id == bmi260_chip_info.chip_id)
bmi270_device->chip_info = &bmi260_chip_info;
else if (chip_id == bmi270_chip_info.chip_id)
bmi270_device->chip_info = &bmi270_chip_info;
return 0;
}
@@ -187,7 +604,8 @@ static int bmi270_write_calibration_data(struct bmi270_data *bmi270_device)
return dev_err_probe(dev, ret,
"Failed to prepare device to load init data");
ret = request_firmware(&init_data, BMI270_INIT_DATA_FILE, dev);
ret = request_firmware(&init_data,
bmi270_device->chip_info->fw_name, dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to load init data file");
@@ -274,7 +692,8 @@ static int bmi270_chip_init(struct bmi270_data *bmi270_device)
return bmi270_configure_imu(bmi270_device);
}
int bmi270_core_probe(struct device *dev, struct regmap *regmap)
int bmi270_core_probe(struct device *dev, struct regmap *regmap,
const struct bmi270_chip_info *chip_info)
{
int ret;
struct bmi270_data *bmi270_device;
@@ -287,6 +706,7 @@ int bmi270_core_probe(struct device *dev, struct regmap *regmap)
bmi270_device = iio_priv(indio_dev);
bmi270_device->dev = dev;
bmi270_device->regmap = regmap;
bmi270_device->chip_info = chip_info;
ret = bmi270_chip_init(bmi270_device);
if (ret)
@@ -294,10 +714,17 @@ int bmi270_core_probe(struct device *dev, struct regmap *regmap)
indio_dev->channels = bmi270_channels;
indio_dev->num_channels = ARRAY_SIZE(bmi270_channels);
indio_dev->name = "bmi270";
indio_dev->name = chip_info->name;
indio_dev->available_scan_masks = bmi270_avail_scan_masks;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmi270_info;
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
bmi270_trigger_handler, NULL);
if (ret)
return ret;
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(bmi270_core_probe, IIO_BMI270);

View File

@@ -17,28 +17,42 @@ static int bmi270_i2c_probe(struct i2c_client *client)
{
struct regmap *regmap;
struct device *dev = &client->dev;
const struct bmi270_chip_info *chip_info;
chip_info = i2c_get_match_data(client);
if (!chip_info)
return -ENODEV;
regmap = devm_regmap_init_i2c(client, &bmi270_i2c_regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to init i2c regmap");
return bmi270_core_probe(dev, regmap);
return bmi270_core_probe(dev, regmap, chip_info);
}
static const struct i2c_device_id bmi270_i2c_id[] = {
{ "bmi270", 0 },
{ "bmi260", (kernel_ulong_t)&bmi260_chip_info },
{ "bmi270", (kernel_ulong_t)&bmi270_chip_info },
{ }
};
static const struct acpi_device_id bmi270_acpi_match[] = {
/* GPD Win Mini, Aya Neo AIR Pro, OXP Mini Pro, etc. */
{ "BMI0160", (kernel_ulong_t)&bmi260_chip_info },
{ }
};
static const struct of_device_id bmi270_of_match[] = {
{ .compatible = "bosch,bmi270" },
{ .compatible = "bosch,bmi260", .data = &bmi260_chip_info },
{ .compatible = "bosch,bmi270", .data = &bmi270_chip_info },
{ }
};
static struct i2c_driver bmi270_i2c_driver = {
.driver = {
.name = "bmi270_i2c",
.acpi_match_table = bmi270_acpi_match,
.of_match_table = bmi270_of_match,
},
.probe = bmi270_i2c_probe,

View File

@@ -49,6 +49,11 @@ static int bmi270_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
struct device *dev = &spi->dev;
const struct bmi270_chip_info *chip_info;
chip_info = spi_get_device_match_data(spi);
if (!chip_info)
return -ENODEV;
regmap = devm_regmap_init(dev, &bmi270_regmap_bus, dev,
&bmi270_spi_regmap_config);
@@ -56,16 +61,18 @@ static int bmi270_spi_probe(struct spi_device *spi)
return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to init i2c regmap");
return bmi270_core_probe(dev, regmap);
return bmi270_core_probe(dev, regmap, chip_info);
}
static const struct spi_device_id bmi270_spi_id[] = {
{ "bmi270" },
{ "bmi260", (kernel_ulong_t)&bmi260_chip_info },
{ "bmi270", (kernel_ulong_t)&bmi270_chip_info },
{ }
};
static const struct of_device_id bmi270_of_match[] = {
{ .compatible = "bosch,bmi270" },
{ .compatible = "bosch,bmi260", .data = &bmi260_chip_info },
{ .compatible = "bosch,bmi270", .data = &bmi270_chip_info },
{ }
};

Some files were not shown because too many files have changed in this diff Show More