Merge tag 'iio-for-6.11a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-testing

Jonathan writes:

IIO: 1st set of new device support, cleanups etc for 6.11

Lots of new device support and 3 entirely new drivers.

Early pull request this cycle to allow for clean picking up of fixes
that are dependencies for some queued patch sets.

Device support
==============

adi,ad3552r
- Add AD3541R and AD3551R - single output variants of already supported
  DACs.

adi,ad7192
- Add support for ad7194 24-bit ADC with integrated PGA.

adi,ad7380
- New ADC driver built up in a number of steps. Supports
  - 2 channel differential ADCs: AD7380, AD7381
  - 4 channel differential ADCs: AD7380-4, AD7381-4
  - 2 channel pseudo-differential ADCs: AD7383, AD7384
  - 4 channel pseudo-differential ADCs: AD7383-4, AD7384-4

adi,adis16475
- Support ADS16501 variant - ID and some different scale factors from
  parts already supported.
- Driver refactoring then enables support for 6 more IMUs:
  - ADIS16575-[2,3]
  - ADIS16576-[2,3]
  - ADIS16577-[2,3]

adi,adsi16480
- Driver refactoring and feature additions leading to support for 6 more
  IMUs - with new delta angle and delta velocity feature:
  - ADIS16545-[1,2,3]
  - ADIS16547-[1,2,3]

bosch,bmi160
- Support for the bmi120 IMU: ID only. Also relax ID checking to warn
  only on mismatch allowing use of fallback compatibles for new devices.

sciosense,ens160
- New driver for this metal oxide multi-gas sensor for indoor
  air quality monitoring.

sensortek,stk3110
- Support for stk3311a and stk3311s34 light sensor variants. Relax ID
  checking to warn only on a mismatch allowing use of fallback compatibles
  for new devices.

vishay,veml6040
- New driver for this RGBW light sensor. Note that whilst the register
  interface is very different, the dt-binding similar enough that it is
  shared with the existing vishay,veml6075 binding

x-powers,axp20x
- Add support for axp192, very similar to another supported PMIC ADC variant
  but with a few more GPIO channels.

Dt-binding only
===============

ti,ads1015
- Add binding (no driver support yet) for ti,tla2021

New features
============
core
- Variable scan type support.  We have papered over this for a long time
  so good to finally resolve it.
  Some devices will change their data output format (typically resolution)
  dependent on settings such as oversampling.  A new callback is added
  to enable this. First used in the ad7380 driver.
- Harden the core against missing callback functions.

dt-binding:
- Add a single-channel property that can be used in per channel nodes
  instead of reg to indicate which device channel.  This is important
  in devices with a mixture of differential and single ended channels
  as reg already just acted as an index for the differential channels
  making things inconsistent if it had more meaning for single ended
  channels.

adi,ad7380
- Use spi_optimize_message() to reduce reading message setup overhead.
- Add oversampling support using the new core functionality to allow
  a device support multiple scan types.

invense,icm42600
- Support for low-power accelerometer modes.  When a given sampling
  frequency is only supported at one power mode, use that. Otherwise
  default to low power at the cost of some noise unless overridden
  via a new sysfs attribute.

silicon-labs,si70720
- Add control of the heater.

Cleanups and minor fixes
========================

core
- Cleanup use of sizeof(struct xxxx) in favor of sizeof(*variable)

Makefile
- Resort the iio/adc/Makefile which has drifted away from alphabetical
  order.

gts library
- Fix sorting of lists with a zero in the middle. Doesn't happen with
  upstream drivers, but good to harden this code.  Add a related unit test.

multiple drivers
- Add missing MODULE_DESCRIPTION()
- Drop some unused structure fields.
- Drop some entirely unused structure definitions.
- Stop pointless initialization of i2c_device_id::driver_data to 0 in drivers
  where it isn't used.
- Use spi_get_device_match_data() to replace open-coded equivalent.

adi,ad3552r
- Fix dt gain parameter names to reflect what the driver does. Note
  discussion in patch to justify fixing it in the binding not the
  driver.
- Tidy up some naming.

adi,ad7192
- Use read_avail() callback to handle the low pass filter.
- Add an aincom supply for pseudo differential operation.

adi,ad7606
- Use iio_device_claim_direct_scoped() to simplify error paths.

adi,ad7944
- Drop an unused function parameter.

adi,adrf6780
- Drop unused header.

adi,ad9467
- Use a DMA safe buffer for SPI transfers.
- Stop using tabs to pad structure field names. It was creating a lot
  of noise.

adi,axi-adc
- Prevent races between enable and disable calls.
- Ensure the DRP (dynamic reconfiguration port) is locked. Not used
  in most real designs, but better safe than sorry.
- Limit build to COMPILE_TEST or platforms for which the IP exists.

adi,axi-dac
- Limit build to COMPILE_TEST or platforms for which the IP exists.

ams,iaq
- Use __packed instead of ___attribute__((__packed__))

bosch,bmp280
- White space cleanup.
- Use BME280 prefix for registers that do not exist on the BMP280.
- Add parameter names to callback function definitions.
- Rename measure function to better reflect what it does which is wait
  for a measurement to happen.
- Drop a redundant error check.
- Improve error messages
- Make error checks consistent as if (ret)
- Use unsigned types for inherently unsigned data.
- Refactor reading functions to not rely on a hidden t_fine variable.
- Make use of cleanup.h

freescale,mma7660
- Add mount matrix support.

invense,icm42600
- Enable the regmap cache to reduce bus accesses.

amlogic,meson-saradc
- Add dt-binding support for power-domains.

ti,adc161s626
- Use iio_device_claim_direct_scoped() to simplify error handling.

* tag 'iio-for-6.11a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (107 commits)
  iio: imu: inv_icm42600: add support of accel low-power mode
  iio: document inv_icm42600 driver private sysfs attributes
  MAINTAINERS: Add ScioSense ENS160
  iio: chemical: ens160: add power management support
  iio: chemical: ens160: add triggered buffer support
  iio: chemical: add driver for ENS160 sensor
  dt-bindings: iio: chemical: add ENS160 sensor
  dt-bindings: vendor-prefixes: add ScioSense
  iio: temperature: mcp9600: add threshold events support
  dt-bindings: iio: light: add VEML6040 RGBW-LS
  iio: light: driver for Vishay VEML6040
  dt-bindings: iio: adc: amlogic,meson-saradc: add optional power-domains
  iio: dac: adi-axi-dac: add platform dependencies
  iio: adc: adi-axi-adc: add platform dependencies
  iio: imu: inv_icm42600: add register caching in the regmap
  iio: adc: mcp3564: drop redundant open-coded spi_get_device_match_data()
  iio: dac: max5522: simplify with spi_get_device_match_data()
  iio: addac: ad74413r: simplify with spi_get_device_match_data()
  iio: adc: ti-tsc2046: simplify with spi_get_device_match_data()
  iio: adc: ti-ads131e08: simplify with spi_get_device_match_data()
  ...
This commit is contained in:
Greg Kroah-Hartman
2024-06-16 12:03:31 +02:00
177 changed files with 6068 additions and 1152 deletions
@@ -0,0 +1,18 @@
What: /sys/bus/iio/devices/iio:deviceX/in_accel_power_mode
KernelVersion: 6.11
Contact: linux-iio@vger.kernel.org
Description:
Accelerometer power mode. Setting this attribute will set the
requested power mode to use if the ODR support it. If ODR
support only 1 mode, power mode will be enforced.
Reading this attribute will return the current accelerometer
power mode if the sensor is on, or the requested value if the
sensor is off. The value between real and requested value can
be different for ODR supporting only 1 mode.
What: /sys/bus/iio/devices/iio:deviceX/in_accel_power_mode_available
KernelVersion: 6.11
Contact: linux-iio@vger.kernel.org
Description:
List of available accelerometer power modes that can be set in
in_accel_power_mode attribute.
@@ -38,6 +38,14 @@ properties:
The first value specifies the positive input pin, the second
specifies the negative input pin.
single-channel:
$ref: /schemas/types.yaml#/definitions/uint32
description:
When devices combine single-ended and differential channels, allow the
channel for a single element to be specified, independent of reg (as for
differential channels). If this and diff-channels are not present reg
shall be used instead.
settling-time-us:
description:
Time between enabling the channel and first stable readings.
@@ -50,4 +58,15 @@ properties:
device design and can interact with other characteristics such as
settling time.
anyOf:
- oneOf:
- required:
- reg
- diff-channels
- required:
- reg
- single-channel
- required:
- reg
additionalProperties: true
@@ -21,8 +21,15 @@ properties:
- adi,ad7190
- adi,ad7192
- adi,ad7193
- adi,ad7194
- adi,ad7195
"#address-cells":
const: 1
"#size-cells":
const: 0
reg:
maxItems: 1
@@ -41,6 +48,11 @@ properties:
interrupts:
maxItems: 1
aincom-supply:
description: |
AINCOM voltage supply. Analog inputs AINx are referenced to this input
when configured for pseudo-differential operation.
dvdd-supply:
description: DVdd voltage supply
@@ -84,6 +96,42 @@ properties:
description: see Documentation/devicetree/bindings/iio/adc/adc.yaml
type: boolean
patternProperties:
"^channel@[0-9a-f]+$":
type: object
$ref: adc.yaml
unevaluatedProperties: false
properties:
reg:
description: The channel index.
minimum: 0
maximum: 271
diff-channels:
description:
Both inputs can be connected to pins AIN1 to AIN16 by choosing the
appropriate value from 1 to 16.
items:
minimum: 1
maximum: 16
single-channel:
description:
Positive input can be connected to pins AIN1 to AIN16 by choosing the
appropriate value from 1 to 16. Negative input is connected to AINCOM.
items:
minimum: 1
maximum: 16
oneOf:
- required:
- reg
- diff-channels
- required:
- reg
- single-channel
required:
- compatible
- reg
@@ -98,6 +146,17 @@ required:
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
- if:
properties:
compatible:
enum:
- adi,ad7190
- adi,ad7192
- adi,ad7193
- adi,ad7195
then:
patternProperties:
"^channel@[0-9a-f]+$": false
unevaluatedProperties: false
@@ -117,6 +176,7 @@ examples:
clock-names = "mclk";
interrupts = <25 0x2>;
interrupt-parent = <&gpio>;
aincom-supply = <&aincom>;
dvdd-supply = <&dvdd>;
avdd-supply = <&avdd>;
vref-supply = <&vref>;
@@ -127,3 +187,38 @@ examples:
adi,burnout-currents-enable;
};
};
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,ad7194";
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
spi-cpha;
clocks = <&ad7192_mclk>;
clock-names = "mclk";
interrupts = <25 0x2>;
interrupt-parent = <&gpio>;
aincom-supply = <&aincom>;
dvdd-supply = <&dvdd>;
avdd-supply = <&avdd>;
vref-supply = <&vref>;
channel@0 {
reg = <0>;
diff-channels = <1 6>;
};
channel@1 {
reg = <1>;
single-channel = <1>;
};
};
};
@@ -0,0 +1,148 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/adi,ad7380.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices Simultaneous Sampling Analog to Digital Converters
maintainers:
- Michael Hennerich <Michael.Hennerich@analog.com>
- Nuno Sá <nuno.sa@analog.com>
description: |
* https://www.analog.com/en/products/ad7380.html
* https://www.analog.com/en/products/ad7381.html
* https://www.analog.com/en/products/ad7383.html
* https://www.analog.com/en/products/ad7384.html
* https://www.analog.com/en/products/ad7380-4.html
* https://www.analog.com/en/products/ad7381-4.html
* https://www.analog.com/en/products/ad7383-4.html
* https://www.analog.com/en/products/ad7384-4.html
$ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
enum:
- adi,ad7380
- adi,ad7381
- adi,ad7383
- adi,ad7384
- adi,ad7380-4
- adi,ad7381-4
- adi,ad7383-4
- adi,ad7384-4
reg:
maxItems: 1
spi-max-frequency:
maximum: 80000000
spi-cpol: true
spi-cpha: true
vcc-supply:
description: A 3V to 3.6V supply that powers the chip.
vlogic-supply:
description:
A 1.65V to 3.6V supply for the logic pins.
refio-supply:
description:
A 2.5V to 3.3V supply for the external reference voltage. When omitted,
the internal 2.5V reference is used.
aina-supply:
description:
The common mode voltage supply for the AINA- pin on pseudo-differential
chips.
ainb-supply:
description:
The common mode voltage supply for the AINB- pin on pseudo-differential
chips.
ainc-supply:
description:
The common mode voltage supply for the AINC- pin on pseudo-differential
chips.
aind-supply:
description:
The common mode voltage supply for the AIND- pin on pseudo-differential
chips.
interrupts:
description:
When the device is using 1-wire mode, this property is used to optionally
specify the ALERT interrupt.
maxItems: 1
required:
- compatible
- reg
- vcc-supply
- vlogic-supply
unevaluatedProperties: false
allOf:
# pseudo-differential chips require common mode voltage supplies,
# true differential chips don't use them
- if:
properties:
compatible:
enum:
- adi,ad7383
- adi,ad7384
- adi,ad7383-4
- adi,ad7384-4
then:
required:
- aina-supply
- ainb-supply
else:
properties:
aina-supply: false
ainb-supply: false
- if:
properties:
compatible:
enum:
- adi,ad7383-4
- adi,ad7384-4
then:
required:
- ainc-supply
- aind-supply
else:
properties:
ainc-supply: false
aind-supply: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,ad7380";
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>;
refio-supply = <&supply_2_5V>;
};
};
@@ -66,6 +66,9 @@ properties:
nvmem-cell-names:
const: temperature_calib
power-domains:
maxItems: 1
allOf:
- if:
properties:
@@ -18,6 +18,7 @@ properties:
enum:
- ti,ads1015
- ti,ads1115
- ti,tla2021
- ti,tla2024
reg:
@@ -0,0 +1,70 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/chemical/sciosense,ens160.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ScioSense ENS160 multi-gas sensor
maintainers:
- Gustavo Silva <gustavograzs@gmail.com>
description: |
Digital Multi-Gas Sensor for Monitoring Indoor Air Quality.
Datasheet:
https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
properties:
compatible:
enum:
- sciosense,ens160
reg:
maxItems: 1
interrupts:
maxItems: 1
vdd-supply: true
vddio-supply: true
required:
- compatible
- reg
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
gas-sensor@52 {
compatible = "sciosense,ens160";
reg = <0x52>;
interrupt-parent = <&gpio0>;
interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
};
};
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
gas-sensor@0 {
compatible = "sciosense,ens160";
reg = <0>;
spi-max-frequency = <10000000>;
interrupt-parent = <&gpio>;
interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
};
};
...
@@ -13,13 +13,17 @@ maintainers:
description: |
Bindings for the Analog Devices AD3552R DAC device and similar.
Datasheet can be found here:
https://www.analog.com/media/en/technical-documentation/data-sheets/ad3541r.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad3542r.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad3551r.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad3552r.pdf
properties:
compatible:
enum:
- adi,ad3541r
- adi,ad3542r
- adi,ad3551r
- adi,ad3552r
reg:
@@ -92,13 +96,13 @@ patternProperties:
maximum: 511
minimum: -511
adi,gain-scaling-p-inv-log2:
description: GainP = 1 / ( 2 ^ adi,gain-scaling-p-inv-log2)
adi,gain-scaling-p:
description: GainP = 1 / ( 2 ^ adi,gain-scaling-p)
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
adi,gain-scaling-n-inv-log2:
description: GainN = 1 / ( 2 ^ adi,gain-scaling-n-inv-log2)
adi,gain-scaling-n:
description: GainN = 1 / ( 2 ^ adi,gain-scaling-n)
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
@@ -107,8 +111,8 @@ patternProperties:
required:
- adi,gain-offset
- adi,gain-scaling-p-inv-log2
- adi,gain-scaling-n-inv-log2
- adi,gain-scaling-p
- adi,gain-scaling-n
- adi,rfb-ohms
required:
@@ -128,7 +132,9 @@ allOf:
properties:
compatible:
contains:
const: adi,ad3542r
enum:
- adi,ad3541r
- adi,ad3542r
then:
patternProperties:
"^channel@([0-1])$":
@@ -158,7 +164,9 @@ allOf:
properties:
compatible:
contains:
const: adi,ad3552r
enum:
- adi,ad3551r
- adi,ad3552r
then:
patternProperties:
"^channel@([0-1])$":
@@ -182,6 +190,21 @@ allOf:
- const: -10000000
- const: 10000000
- if:
properties:
compatible:
contains:
enum:
- adi,ad3541r
- adi,ad3551r
then:
properties:
channel@1: false
channel@0:
properties:
reg:
const: 0
required:
- compatible
- reg
@@ -208,8 +231,8 @@ examples:
reg = <1>;
custom-output-range-config {
adi,gain-offset = <5>;
adi,gain-scaling-p-inv-log2 = <1>;
adi,gain-scaling-n-inv-log2 = <2>;
adi,gain-scaling-p = <1>;
adi,gain-scaling-n = <2>;
adi,rfb-ohms = <1>;
};
};
@@ -30,12 +30,19 @@ properties:
- adi,adis16467-2
- adi,adis16467-3
- adi,adis16500
- adi,adis16501
- adi,adis16505-1
- adi,adis16505-2
- adi,adis16505-3
- adi,adis16507-1
- adi,adis16507-2
- adi,adis16507-3
- adi,adis16575-2
- adi,adis16575-3
- adi,adis16576-2
- adi,adis16576-3
- adi,adis16577-2
- adi,adis16577-3
reg:
maxItems: 1
@@ -90,12 +97,19 @@ allOf:
contains:
enum:
- adi,adis16500
- adi,adis16501
- adi,adis16505-1
- adi,adis16505-2
- adi,adis16505-3
- adi,adis16507-1
- adi,adis16507-2
- adi,adis16507-3
- adi,adis16575-2
- adi,adis16575-3
- adi,adis16576-2
- adi,adis16576-3
- adi,adis16577-2
- adi,adis16577-3
then:
properties:
@@ -112,6 +126,23 @@ allOf:
dependencies:
adi,sync-mode: [ clocks ]
- if:
properties:
compatible:
contains:
enum:
- adi,adis16575-2
- adi,adis16575-3
- adi,adis16576-2
- adi,adis16576-3
- adi,adis16577-2
- adi,adis16577-3
then:
properties:
spi-max-frequency:
maximum: 15000000
unevaluatedProperties: false
examples:
@@ -23,6 +23,12 @@ properties:
- adi,adis16497-1
- adi,adis16497-2
- adi,adis16497-3
- adi,adis16545-1
- adi,adis16545-2
- adi,adis16545-3
- adi,adis16547-1
- adi,adis16547-2
- adi,adis16547-3
reg:
maxItems: 1
@@ -16,7 +16,11 @@ description: |
properties:
compatible:
const: bosch,bmi160
oneOf:
- const: bosch,bmi160
- items:
- const: bosch,bmi120
- const: bosch,bmi160
reg:
maxItems: 1
@@ -4,14 +4,19 @@
$id: http://devicetree.org/schemas/iio/light/vishay,veml6075.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Vishay VEML6075 UVA and UVB sensor
title: Vishay VEML6075 UVA/B and VEML6040 RGBW sensors
maintainers:
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
description:
VEML6040 datasheet at https://www.vishay.com/docs/84276/veml6040.pdf
properties:
compatible:
const: vishay,veml6075
enum:
- vishay,veml6040
- vishay,veml6075
reg:
maxItems: 1
@@ -1254,6 +1254,8 @@ patternProperties:
description: Smart Battery System
"^schindler,.*":
description: Schindler
"^sciosense,.*":
description: ScioSense B.V.
"^seagate,.*":
description: Seagate Technology PLC
"^seeed,.*":
+2 -21
View File
@@ -380,24 +380,5 @@ data is structured.
4. IIO Interfacing Tools
========================
Linux Kernel Tools
------------------
Linux Kernel provides some userspace tools that can be used to retrieve data
from IIO sysfs:
* lsiio: example application that provides a list of IIO devices and triggers
* iio_event_monitor: example application that reads events from an IIO device
and prints them
* iio_generic_buffer: example application that reads data from buffer
* iio_utils: set of APIs, typically used to access sysfs files.
LibIIO
------
LibIIO is a C/C++ library that provides generic access to IIO devices. The
library abstracts the low-level details of the hardware, and provides a simple
yet complete programming interface that can be used for advanced projects.
For more information about LibIIO, please see:
https://github.com/analogdevicesinc/libiio
See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO
interfacing tools.
+443
View File
@@ -0,0 +1,443 @@
.. SPDX-License-Identifier: GPL-2.0
================
ADIS16480 driver
================
This driver supports Analog Device's IMUs on SPI bus.
1. Supported devices
====================
* `ADIS16375 <https://www.analog.com/ADIS16375>`_
* `ADIS16480 <https://www.analog.com/ADIS16480>`_
* `ADIS16485 <https://www.analog.com/ADIS16485>`_
* `ADIS16488 <https://www.analog.com/ADIS16488>`_
* `ADIS16490 <https://www.analog.com/ADIS16490>`_
* `ADIS16495 <https://www.analog.com/ADIS16495>`_
* `ADIS16497 <https://www.analog.com/ADIS16497>`_
* `ADIS16545 <https://www.analog.com/ADIS16545>`_
* `ADIS16547 <https://www.analog.com/ADIS16547>`_
Each supported device is a complete inertial system that includes a triaxial
gyroscope and a triaxial accelerometer. Each inertial sensor in device combines
with signal conditioning that optimizes dynamic performance. The factory
calibration characterizes each sensor for sensitivity, bias, and alignment. As
a result, each sensor has its own dynamic compensation formulas that provide
accurate sensor measurements.
2. Device attributes
====================
Accelerometer, gyroscope measurements are always provided. Furthermore, the
driver offers the capability to retrieve the delta angle and the delta velocity
measurements computed by the device.
The delta angle measurements represent a calculation of angular displacement
between each sample update, while the delta velocity measurements represent a
calculation of linear velocity change between each sample update.
Finally, temperature data are provided which show a coarse measurement of
the temperature inside of the IMU device. This data is most useful for
monitoring relative changes in the thermal environment.
ADIS16480 and ADIS16488 also provide access to barometric pressure data and
triaxial magnetometer measurements.
Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:deviceX``,
where X is the IIO index of the device. Under these folders reside a set of
device files, depending on the characteristics and features of the hardware
device in questions. These files are consistently generalized and documented in
the IIO ABI documentation.
The following tables show the adis16480 related device files, found in the
specific device folder path ``/sys/bus/iio/devices/iio:deviceX``.
**Available only for ADIS16480 and ADIS16488:**
+------------------------------------------+---------------------------------------------------------+
| 3-Axis Magnetometer related device files | Description |
+------------------------------------------+---------------------------------------------------------+
| in_magn_scale | Scale for the magnetometer channels. |
+------------------------------------------+---------------------------------------------------------+
| in_magn_x_calibbias | Calibration offset for the X-axis magnetometer channel. |
+------------------------------------------+---------------------------------------------------------+
| in_magn_x_filter_low_pass_3db_frequency | Bandwidth for the X-axis magnetometer channel. |
+------------------------------------------+---------------------------------------------------------+
| in_magn_x_raw | Raw X-axis magnetometer channel value. |
+------------------------------------------+---------------------------------------------------------+
| in_magn_y_calibbias | Calibration offset for the Y-axis magnetometer channel. |
+------------------------------------------+---------------------------------------------------------+
| in_magn_y_filter_low_pass_3db_frequency | Bandwidth for the Y-axis magnetometer channel. |
+------------------------------------------+---------------------------------------------------------+
| in_magn_y_raw | Raw Y-axis magnetometer channel value. |
+------------------------------------------+---------------------------------------------------------+
| in_magn_z_calibbias | Calibration offset for the Z-axis magnetometer channel. |
+------------------------------------------+---------------------------------------------------------+
| in_magn_z_filter_low_pass_3db_frequency | Bandwidth for the Z-axis magnetometer channel. |
+------------------------------------------+---------------------------------------------------------+
| in_magn_z_raw | Raw Z-axis magnetometer channel value. |
+------------------------------------------+---------------------------------------------------------+
+------------------------------------------+-----------------------------------------------------+
| Barometric pressure sensor related files | Description |
+------------------------------------------+-----------------------------------------------------+
| in_pressure0_calibbias | Calibration offset for barometric pressure channel. |
+------------------------------------------+-----------------------------------------------------+
| in_pressure0_raw | Raw barometric pressure channel value. |
+------------------------------------------+-----------------------------------------------------+
| in_pressure0_scale | Scale for the barometric pressure sensor channel. |
+------------------------------------------+-----------------------------------------------------+
**Available for all supported devices:**
+-------------------------------------------+----------------------------------------------------------+
| 3-Axis Accelerometer related device files | Description |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_scale | Scale for the accelerometer channels. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_x_calibbias | Calibration offset for the X-axis accelerometer channel. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_x_calibscale | Calibration scale for the X-axis accelerometer channel. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_x_filter_low_pass_3db_frequency | Bandwidth for the X-axis accelerometer channel. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_x_raw | Raw X-axis accelerometer channel value. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_y_calibbias | Calibration offset for the Y-axis accelerometer channel. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_y_calibscale | Calibration scale for the Y-axis accelerometer channel. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_y_filter_low_pass_3db_frequency | Bandwidth for the Y-axis accelerometer channel. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_y_raw | Raw Y-axis accelerometer channel value. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_z_calibbias | Calibration offset for the Z-axis accelerometer channel. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_z_calibscale | Calibration scale for the Z-axis accelerometer channel. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_z_filter_low_pass_3db_frequency | Bandwidth for the Z-axis accelerometer channel. |
+-------------------------------------------+----------------------------------------------------------+
| in_accel_z_raw | Raw Z-axis accelerometer channel value. |
+-------------------------------------------+----------------------------------------------------------+
| in_deltavelocity_scale | Scale for delta velocity channels. |
+-------------------------------------------+----------------------------------------------------------+
| in_deltavelocity_x_raw | Raw X-axis delta velocity channel value. |
+-------------------------------------------+----------------------------------------------------------+
| in_deltavelocity_y_raw | Raw Y-axis delta velocity channel value. |
+-------------------------------------------+----------------------------------------------------------+
| in_deltavelocity_z_raw | Raw Z-axis delta velocity channel value. |
+-------------------------------------------+----------------------------------------------------------+
+--------------------------------------------+------------------------------------------------------+
| 3-Axis Gyroscope related device files | Description |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_scale | Scale for the gyroscope channels. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_x_calibbias | Calibration offset for the X-axis gyroscope channel. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_x_calibscale | Calibration scale for the X-axis gyroscope channel. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_x_filter_low_pass_3db_frequency | Bandwidth for the X-axis gyroscope channel. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_x_raw | Raw X-axis gyroscope channel value. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_y_calibbias | Calibration offset for the Y-axis gyroscope channel. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_y_calibscale | Calibration scale for the Y-axis gyroscope channel. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_y_filter_low_pass_3db_frequency | Bandwidth for the Y-axis gyroscope channel. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_y_raw | Raw Y-axis gyroscope channel value. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_z_calibbias | Calibration offset for the Z-axis gyroscope channel. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_z_calibscale | Calibration scale for the Z-axis gyroscope channel. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_z_filter_low_pass_3db_frequency | Bandwidth for the Z-axis gyroscope channel. |
+--------------------------------------------+------------------------------------------------------+
| in_anglvel_z_raw | Raw Z-axis gyroscope channel value. |
+--------------------------------------------+------------------------------------------------------+
| in_deltaangl_scale | Scale for delta angle channels. |
+--------------------------------------------+------------------------------------------------------+
| in_deltaangl_x_raw | Raw X-axis delta angle channel value. |
+--------------------------------------------+------------------------------------------------------+
| in_deltaangl_y_raw | Raw Y-axis delta angle channel value. |
+--------------------------------------------+------------------------------------------------------+
| in_deltaangl_z_raw | Raw Z-axis delta angle channel value. |
+--------------------------------------------+------------------------------------------------------+
+----------------------------------+-------------------------------------------+
| Temperature sensor related files | Description |
+----------------------------------+-------------------------------------------+
| in_temp0_raw | Raw temperature channel value. |
+----------------------------------+-------------------------------------------+
| in_temp0_offset | Offset for the temperature sensor channel.|
+----------------------------------+-------------------------------------------+
| in_temp0_scale | Scale for the temperature sensor channel. |
+----------------------------------+-------------------------------------------+
+-------------------------------+---------------------------------------------------------+
| Miscellaneous device files | Description |
+-------------------------------+---------------------------------------------------------+
| name | Name of the IIO device. |
+-------------------------------+---------------------------------------------------------+
| sampling_frequency | Currently selected sample rate. |
+-------------------------------+---------------------------------------------------------+
The following table shows the adis16480 related device debug files, found in the
specific device debug folder path ``/sys/kernel/debug/iio/iio:deviceX``.
+----------------------+-------------------------------------------------------------------------+
| Debugfs device files | Description |
+----------------------+-------------------------------------------------------------------------+
| serial_number | The serial number of the chip in hexadecimal format. |
+----------------------+-------------------------------------------------------------------------+
| product_id | Chip specific product id (e.g. 16480, 16488, 16545, etc.). |
+----------------------+-------------------------------------------------------------------------+
| flash_count | The number of flash writes performed on the device. |
+----------------------+-------------------------------------------------------------------------+
| firmware_revision | String containing the firmware revision in the following format ##.##. |
+----------------------+-------------------------------------------------------------------------+
| firmware_date | String containing the firmware date in the following format mm-dd-yyyy. |
+----------------------+-------------------------------------------------------------------------+
Channels processed values
-------------------------
A channel value can be read from its _raw attribute. The value returned is the
raw value as reported by the devices. To get the processed value of the channel,
apply the following formula:
.. code-block:: bash
processed value = (_raw + _offset) * _scale
Where _offset and _scale are device attributes. If no _offset attribute is
present, simply assume its value is 0.
The adis16480 driver offers data for 7 types of channels, the table below shows
the measurement units for the processed value, which are defined by the IIO
framework:
+--------------------------------------+---------------------------+
| Channel type | Measurement unit |
+--------------------------------------+---------------------------+
| Acceleration on X, Y, and Z axis | Meters per Second squared |
+--------------------------------------+---------------------------+
| Angular velocity on X, Y and Z axis | Radians per second |
+--------------------------------------+---------------------------+
| Delta velocity on X. Y, and Z axis | Meters per Second |
+--------------------------------------+---------------------------+
| Delta angle on X, Y, and Z axis | Radians |
+--------------------------------------+---------------------------+
| Temperature | Millidegrees Celsius |
+--------------------------------------+---------------------------+
| Magnetic field along X, Y and Z axis | Gauss |
+--------------------------------------+---------------------------+
| Barometric pressure | kilo Pascal |
+--------------------------------------+---------------------------+
Usage examples
--------------
Show device name:
.. code-block:: bash
root:/sys/bus/iio/devices/iio:device0> cat name
adis16545-1
Show accelerometer channels value:
.. code-block:: bash
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_raw
1376728
root:/sys/bus/iio/devices/iio:device0> cat in_accel_y_raw
4487621
root:/sys/bus/iio/devices/iio:device0> cat in_accel_z_raw
262773792
root:/sys/bus/iio/devices/iio:device0> cat in_accel_scale
0.000000037
- X-axis acceleration = in_accel_x_raw * in_accel_scale = 0.050938936 m/s^2
- Y-axis acceleration = in_accel_y_raw * in_accel_scale = 0.166041977 m/s^2
- Z-axis acceleration = in_accel_z_raw * in_accel_scale = 9.722630304 m/s^2
Show gyroscope channels value:
.. code-block:: bash
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_x_raw
-1041702
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_raw
-273013
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_z_raw
2745116
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_scale
0.000000001
- X-axis angular velocity = in_anglvel_x_raw * in_anglvel_scale = 0.001041702 rad/s
- Y-axis angular velocity = in_anglvel_y_raw * in_anglvel_scale = 0.000273013 rad/s
- Z-axis angular velocity = in_anglvel_z_raw * in_anglvel_scale = 0.002745116 rad/s
Set calibration offset for accelerometer channels:
.. code-block:: bash
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
0
root:/sys/bus/iio/devices/iio:device0> echo 5000 > in_accel_x_calibbias
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
5000
Set calibration offset for gyroscope channels:
.. code-block:: bash
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias
0
root:/sys/bus/iio/devices/iio:device0> echo -5000 > in_anglvel_y_calibbias
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias
-5000
Set sampling frequency:
.. code-block:: bash
root:/sys/bus/iio/devices/iio:device0> cat sampling_frequency
4250.000000
root:/sys/bus/iio/devices/iio:device0> echo 1000 > sampling_frequency
1062.500000
Set bandwidth for accelerometer channels:
.. code-block:: bash
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_filter_low_pass_3db_frequency
0
root:/sys/bus/iio/devices/iio:device0> echo 300 > in_accel_x_filter_low_pass_3db_frequency
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_filter_low_pass_3db_frequency
300
Show serial number:
.. code-block:: bash
root:/sys/kernel/debug/iio/iio:device0> cat serial_number
0x000c
Show product id:
.. code-block:: bash
root:/sys/kernel/debug/iio/iio:device0> cat product_id
16545
Show flash count:
.. code-block:: bash
root:/sys/kernel/debug/iio/iio:device0> cat flash_count
88
Show firmware revision:
.. code-block:: bash
root:/sys/kernel/debug/iio/iio:device0> cat firmware_revision
1.4
Show firmware date:
.. code-block:: bash
root:/sys/kernel/debug/iio/iio:device0> cat firmware_date
09-23-2023
3. Device buffers
=================
This driver supports IIO buffers.
All devices support retrieving the raw acceleration, gyroscope and temperature
measurements using buffers.
The following device families also support retrieving the delta velocity, delta
angle and temperature measurements using buffers:
- ADIS16545
- ADIS16547
However, when retrieving acceleration or gyroscope data using buffers, delta
readings will not be available and vice versa. This is because the device only
allows to read either acceleration and gyroscope data or delta velocity and
delta angle data at a time and switching between these two burst data selection
modes is time consuming.
Usage examples
--------------
Set device trigger in current_trigger, if not already set:
.. code-block:: bash
root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger
root:/sys/bus/iio/devices/iio:device0> echo adis16545-1-dev0 > trigger/current_trigger
root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger
adis16545-1-dev0
Select channels for buffer read:
.. code-block:: bash
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_x_en
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_y_en
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_z_en
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_temp0_en
Set the number of samples to be stored in the buffer:
.. code-block:: bash
root:/sys/bus/iio/devices/iio:device0> echo 10 > buffer/length
Enable buffer readings:
.. code-block:: bash
root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable
Obtain buffered data::
root:/sys/bus/iio/devices/iio:device0> hexdump -C /dev/iio\:device0
...
00006aa0 09 62 00 00 ff ff fc a4 00 00 01 69 00 03 3c 08 |.b.........i..<.|
00006ab0 09 61 00 00 00 00 02 96 00 00 02 8f 00 03 37 50 |.a............7P|
00006ac0 09 61 00 00 00 00 12 3d 00 00 0b 89 00 03 2c 0b |.a.....=......,.|
00006ad0 09 61 00 00 00 00 1e dc 00 00 16 dd 00 03 25 bf |.a............%.|
00006ae0 09 61 00 00 00 00 1e e3 00 00 1b bf 00 03 27 0b |.a............'.|
00006af0 09 61 00 00 00 00 15 50 00 00 19 44 00 03 30 fd |.a.....P...D..0.|
00006b00 09 61 00 00 00 00 09 0e 00 00 14 41 00 03 3d 7f |.a.........A..=.|
00006b10 09 61 00 00 ff ff ff f0 00 00 0e bc 00 03 48 d0 |.a............H.|
00006b20 09 63 00 00 00 00 00 9f 00 00 0f 37 00 03 4c fe |.c.........7..L.|
00006b30 09 64 00 00 00 00 0b f6 00 00 18 92 00 03 43 22 |.d............C"|
00006b40 09 64 00 00 00 00 18 df 00 00 22 33 00 03 33 ab |.d........"3..3.|
00006b50 09 63 00 00 00 00 1e 81 00 00 26 be 00 03 29 60 |.c........&...)`|
00006b60 09 63 00 00 00 00 1b 13 00 00 22 2f 00 03 23 91 |.c........"/..#.|
...
See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered
data is structured.
4. IIO Interfacing Tools
========================
See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO
interfacing tools.
+27
View File
@@ -0,0 +1,27 @@
.. SPDX-License-Identifier: GPL-2.0
=====================
IIO Interfacing Tools
=====================
1. Linux Kernel Tools
=====================
Linux Kernel provides some userspace tools that can be used to retrieve data
from IIO sysfs:
* lsiio: example application that provides a list of IIO devices and triggers
* iio_event_monitor: example application that reads events from an IIO device
and prints them
* iio_generic_buffer: example application that reads data from buffer
* iio_utils: set of APIs, typically used to access sysfs files.
2. LibIIO
=========
LibIIO is a C/C++ library that provides generic access to IIO devices. The
library abstracts the low-level details of the hardware, and provides a simple
yet complete programming interface that can be used for advanced projects.
For more information about LibIIO, please see:
https://github.com/analogdevicesinc/libiio
+2
View File
@@ -9,6 +9,7 @@ Industrial I/O
iio_configfs
iio_devbuf
iio_tools
Industrial I/O Kernel Drivers
=============================
@@ -18,5 +19,6 @@ Industrial I/O Kernel Drivers
ad7944
adis16475
adis16480
bno055
ep93xx_adc
+19
View File
@@ -439,6 +439,16 @@ W: http://wiki.analog.com/AD7142
W: https://ez.analog.com/linux-software-drivers
F: drivers/input/misc/ad714x.c
AD738X ADC DRIVER (AD7380/1/2/4)
M: Michael Hennerich <michael.hennerich@analog.com>
M: Nuno Sá <nuno.sa@analog.com>
R: David Lechner <dlechner@baylibre.com>
S: Supported
W: https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/ad738x
W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
F: drivers/iio/adc/ad7380.c
AD7877 TOUCHSCREEN DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
S: Supported
@@ -11510,6 +11520,7 @@ M: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
L: linux-iio@vger.kernel.org
S: Maintained
W: https://invensense.tdk.com/
F: Documentation/ABI/testing/sysfs-bus-iio-inv_icm42600
F: Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
F: drivers/iio/imu/inv_icm42600/
@@ -19938,6 +19949,14 @@ F: include/linux/wait.h
F: include/uapi/linux/sched.h
F: kernel/sched/
SCIOSENSE ENS160 MULTI-GAS SENSOR DRIVER
M: Gustavo Silva <gustavograzs@gmail.com>
S: Maintained
F: drivers/iio/chemical/ens160_core.c
F: drivers/iio/chemical/ens160_i2c.c
F: drivers/iio/chemical/ens160_spi.c
F: drivers/iio/chemical/ens160.h
SCSI LIBSAS SUBSYSTEM
R: John Garry <john.g.garry@oracle.com>
R: Jason Yan <yanaijie@huawei.com>
+1 -7
View File
@@ -72,13 +72,7 @@ static int adxl313_spi_probe(struct spi_device *spi)
if (ret)
return ret;
/*
* Retrieves device specific data as a pointer to a
* adxl313_chip_info structure
*/
chip_data = device_get_match_data(&spi->dev);
if (!chip_data)
chip_data = (const struct adxl313_chip_info *)spi_get_device_id(spi)->driver_data;
chip_data = spi_get_device_match_data(spi);
regmap = devm_regmap_init_spi(spi,
&adxl31x_spi_regmap_config[chip_data->type]);
+3 -7
View File
@@ -28,13 +28,9 @@ static int adxl355_spi_probe(struct spi_device *spi)
const struct adxl355_chip_info *chip_data;
struct regmap *regmap;
chip_data = device_get_match_data(&spi->dev);
if (!chip_data) {
chip_data = (void *)spi_get_device_id(spi)->driver_data;
if (!chip_data)
return -EINVAL;
}
chip_data = spi_get_device_match_data(spi);
if (!chip_data)
return -EINVAL;
regmap = devm_regmap_init_spi(spi, &adxl355_spi_regmap_config);
if (IS_ERR(regmap)) {
+2 -2
View File
@@ -61,8 +61,8 @@ static int adxl367_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adxl367_i2c_id[] = {
{ "adxl367", 0 },
{ },
{ "adxl367" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id);
+1 -1
View File
@@ -42,7 +42,7 @@ static int adxl372_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adxl372_i2c_id[] = {
{ "adxl372", 0 },
{ "adxl372" },
{}
};
MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
+1 -1
View File
@@ -28,7 +28,7 @@ static int bma400_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bma400_i2c_ids[] = {
{ "bma400", 0 },
{ "bma400" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bma400_i2c_ids);
-5
View File
@@ -114,11 +114,6 @@ enum bmi088_odr_modes {
BMI088_ACCEL_MODE_ODR_1600 = 0xc,
};
struct bmi088_scale_info {
int scale;
u8 reg_range;
};
struct bmi088_accel_chip_info {
const char *name;
u8 chip_id;
+1 -1
View File
@@ -268,7 +268,7 @@ static int da311_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume);
static const struct i2c_device_id da311_i2c_id[] = {
{"da311", 0},
{ "da311" },
{}
};
MODULE_DEVICE_TABLE(i2c, da311_i2c_id);
+3 -3
View File
@@ -201,9 +201,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend,
dmard06_resume);
static const struct i2c_device_id dmard06_id[] = {
{ "dmard05", 0 },
{ "dmard06", 0 },
{ "dmard07", 0 },
{ "dmard05" },
{ "dmard06" },
{ "dmard07" },
{ }
};
MODULE_DEVICE_TABLE(i2c, dmard06_id);
+2 -2
View File
@@ -125,8 +125,8 @@ static int dmard09_probe(struct i2c_client *client)
}
static const struct i2c_device_id dmard09_id[] = {
{ "dmard09", 0 },
{ },
{ "dmard09" },
{ }
};
MODULE_DEVICE_TABLE(i2c, dmard09_id);
+1 -1
View File
@@ -231,7 +231,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend,
dmard10_resume);
static const struct i2c_device_id dmard10_i2c_id[] = {
{"dmard10", 0},
{ "dmard10" },
{}
};
MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id);
+2 -2
View File
@@ -43,8 +43,8 @@ static const struct of_device_id kxsd9_of_match[] = {
MODULE_DEVICE_TABLE(of, kxsd9_of_match);
static const struct i2c_device_id kxsd9_i2c_id[] = {
{"kxsd9", 0},
{ },
{ "kxsd9" },
{ }
};
MODULE_DEVICE_TABLE(i2c, kxsd9_i2c_id);
+1 -1
View File
@@ -180,7 +180,7 @@ static int mc3230_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume);
static const struct i2c_device_id mc3230_i2c_id[] = {
{"mc3230", 0},
{ "mc3230" },
{}
};
MODULE_DEVICE_TABLE(i2c, mc3230_i2c_id);
+2 -2
View File
@@ -32,8 +32,8 @@ static void mma7455_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id mma7455_i2c_ids[] = {
{ "mma7455", 0 },
{ "mma7456", 0 },
{ "mma7455" },
{ "mma7456" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma7455_i2c_ids);
+36 -16
View File
@@ -38,21 +38,6 @@
static const int mma7660_nscale = 467142857;
#define MMA7660_CHANNEL(reg, axis) { \
.type = IIO_ACCEL, \
.address = reg, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec mma7660_channels[] = {
MMA7660_CHANNEL(MMA7660_REG_XOUT, X),
MMA7660_CHANNEL(MMA7660_REG_YOUT, Y),
MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z),
};
enum mma7660_mode {
MMA7660_MODE_STANDBY,
MMA7660_MODE_ACTIVE
@@ -62,6 +47,21 @@ struct mma7660_data {
struct i2c_client *client;
struct mutex lock;
enum mma7660_mode mode;
struct iio_mount_matrix orientation;
};
static const struct iio_mount_matrix *
mma7660_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct mma7660_data *data = iio_priv(indio_dev);
return &data->orientation;
}
static const struct iio_chan_spec_ext_info mma7660_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, mma7660_get_mount_matrix),
{ }
};
static IIO_CONST_ATTR(in_accel_scale_available, MMA7660_SCALE_AVAIL);
@@ -75,6 +75,22 @@ static const struct attribute_group mma7660_attribute_group = {
.attrs = mma7660_attributes
};
#define MMA7660_CHANNEL(reg, axis) { \
.type = IIO_ACCEL, \
.address = reg, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.ext_info = mma7660_ext_info, \
}
static const struct iio_chan_spec mma7660_channels[] = {
MMA7660_CHANNEL(MMA7660_REG_XOUT, X),
MMA7660_CHANNEL(MMA7660_REG_YOUT, Y),
MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z),
};
static int mma7660_set_mode(struct mma7660_data *data,
enum mma7660_mode mode)
{
@@ -187,6 +203,10 @@ static int mma7660_probe(struct i2c_client *client)
mutex_init(&data->lock);
data->mode = MMA7660_MODE_STANDBY;
ret = iio_read_mount_matrix(&client->dev, &data->orientation);
if (ret)
return ret;
indio_dev->info = &mma7660_info;
indio_dev->name = MMA7660_DRIVER_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -241,7 +261,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend,
mma7660_resume);
static const struct i2c_device_id mma7660_i2c_id[] = {
{"mma7660", 0},
{ "mma7660" },
{}
};
MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id);
+1 -1
View File
@@ -595,7 +595,7 @@ static const struct acpi_device_id mma9551_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match);
static const struct i2c_device_id mma9551_id[] = {
{"mma9551", 0},
{ "mma9551" },
{}
};
+2 -2
View File
@@ -1234,8 +1234,8 @@ static const struct acpi_device_id mma9553_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match);
static const struct i2c_device_id mma9553_id[] = {
{"mma9553", 0},
{},
{ "mma9553" },
{}
};
MODULE_DEVICE_TABLE(i2c, mma9553_id);
+3 -3
View File
@@ -584,9 +584,9 @@ static const struct of_device_id mxc4005_of_match[] = {
MODULE_DEVICE_TABLE(of, mxc4005_of_match);
static const struct i2c_device_id mxc4005_id[] = {
{"mxc4005", 0},
{"mxc6655", 0},
{ },
{ "mxc4005" },
{ "mxc6655" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mxc4005_id);
+2 -2
View File
@@ -172,8 +172,8 @@ static const struct acpi_device_id mxc6255_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match);
static const struct i2c_device_id mxc6255_id[] = {
{"mxc6225", 0},
{"mxc6255", 0},
{ "mxc6225" },
{ "mxc6255" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mxc6255_id);
+2 -2
View File
@@ -633,8 +633,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend,
static const struct i2c_device_id stk8312_i2c_id[] = {
/* Deprecated in favour of lowercase form */
{ "STK8312", 0 },
{ "stk8312", 0 },
{ "STK8312" },
{ "stk8312" },
{}
};
MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id);
+1 -1
View File
@@ -525,7 +525,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend,
stk8ba50_resume);
static const struct i2c_device_id stk8ba50_i2c_id[] = {
{"stk8ba50", 0},
{ "stk8ba50" },
{}
};
MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id);
+25 -3
View File
@@ -88,12 +88,17 @@ config AD7173
called ad7173.
config AD7192
tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver"
tristate "Analog Devices AD7192 and similar ADC driver"
depends on SPI
select AD_SIGMA_DELTA
help
Say yes here to build support for Analog Devices AD7190,
AD7192, AD7193 or AD7195 SPI analog to digital converters (ADC).
Say yes here to build support for Analog Devices SPI analog to digital
converters (ADC):
- AD7190
- AD7192
- AD7193
- AD7194
- AD7195
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
@@ -155,6 +160,22 @@ config AD7298
To compile this driver as a module, choose M here: the
module will be called ad7298.
config AD7380
tristate "Analog Devices AD7380 ADC driver"
depends on SPI_MASTER
select IIO_BUFFER
select IIO_TRIGGER
select IIO_TRIGGERED_BUFFER
help
AD7380 is a family of simultaneous sampling ADCs that share the same
SPI register map and have similar pinouts.
Say yes here to build support for Analog Devices AD7380 ADC and
similar chips.
To compile this driver as a module, choose M here: the module will be
called ad7380.
config AD7476
tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD and TI"
depends on SPI
@@ -332,6 +353,7 @@ config AD9467
config ADI_AXI_ADC
tristate "Analog Devices Generic AXI ADC IP core driver"
depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA || COMPILE_TEST
select IIO_BUFFER
select IIO_BUFFER_HW_CONSUMER
select IIO_BUFFER_DMAENGINE
+13 -12
View File
@@ -18,7 +18,7 @@ obj-$(CONFIG_AD7280) += ad7280a.o
obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7292) += ad7292.o
obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7923) += ad7923.o
obj-$(CONFIG_AD7380) += ad7380.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
@@ -29,6 +29,7 @@ obj-$(CONFIG_AD7780) += ad7780.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AD7923) += ad7923.o
obj-$(CONFIG_AD7944) += ad7944.o
obj-$(CONFIG_AD7949) += ad7949.o
obj-$(CONFIG_AD799X) += ad799x.o
@@ -90,42 +91,43 @@ obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
obj-$(CONFIG_PAC1934) += pac1934.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_SPMI_RRADC) += qcom-spmi-rradc.o
obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
obj-$(CONFIG_RICHTEK_RTQ6056) += rtq6056.o
obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_RICHTEK_RTQ6056) += rtq6056.o
obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o
obj-$(CONFIG_SUN20I_GPADC) += sun20i-gpadc-iio.o
obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o
obj-$(CONFIG_STM32_ADC) += stm32-adc.o
obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o
obj-$(CONFIG_STM32_DFSDM_ADC) += stm32-dfsdm-adc.o
obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o
obj-$(CONFIG_STMPE_ADC) += stmpe-adc.o
obj-$(CONFIG_SUN20I_GPADC) += sun20i-gpadc-iio.o
obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o
obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.o
obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o
obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o
obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o
obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TI_LMP92064) += ti-lmp92064.o
obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
@@ -134,7 +136,6 @@ obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o
xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o
obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o
obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o
obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o
+225 -48
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* AD7190 AD7192 AD7193 AD7195 SPI ADC driver
* AD7192 and similar SPI ADC driver
*
* Copyright 2011-2015 Analog Devices Inc.
*/
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/units.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -128,10 +129,24 @@
#define AD7193_CH_AIN8 0x480 /* AIN7 - AINCOM */
#define AD7193_CH_AINCOM 0x600 /* AINCOM - AINCOM */
#define AD7194_CH_POS(x) (((x) - 1) << 4)
#define AD7194_CH_NEG(x) ((x) - 1)
/* 10th bit corresponds to CON18(Pseudo) */
#define AD7194_CH(p) (BIT(10) | AD7194_CH_POS(p))
#define AD7194_DIFF_CH(p, n) (AD7194_CH_POS(p) | AD7194_CH_NEG(n))
#define AD7194_CH_TEMP 0x100
#define AD7194_CH_BASE_NR 2
#define AD7194_CH_AIN_START 1
#define AD7194_CH_AIN_NR 16
#define AD7194_CH_MAX_NR 272
/* ID Register Bit Designations (AD7192_REG_ID) */
#define CHIPID_AD7190 0x4
#define CHIPID_AD7192 0x0
#define CHIPID_AD7193 0x2
#define CHIPID_AD7194 0x3
#define CHIPID_AD7195 0x6
#define AD7192_ID_MASK GENMASK(3, 0)
@@ -169,6 +184,7 @@ enum {
ID_AD7190,
ID_AD7192,
ID_AD7193,
ID_AD7194,
ID_AD7195,
};
@@ -177,7 +193,9 @@ struct ad7192_chip_info {
const char *name;
const struct iio_chan_spec *channels;
u8 num_channels;
const struct ad_sigma_delta_info *sigma_delta_info;
const struct iio_info *info;
int (*parse_channels)(struct iio_dev *indio_dev);
};
struct ad7192_state {
@@ -186,10 +204,12 @@ struct ad7192_state {
struct regulator *vref;
struct clk *mclk;
u16 int_vref_mv;
u32 aincom_mv;
u32 fclk;
u32 mode;
u32 conf;
u32 scale_avail[8][2];
u32 filter_freq_avail[4][2];
u32 oversampling_ratio_avail[4];
u8 gpocon;
u8 clock_sel;
@@ -343,6 +363,18 @@ static const struct ad_sigma_delta_info ad7192_sigma_delta_info = {
.irq_flags = IRQF_TRIGGER_FALLING,
};
static const struct ad_sigma_delta_info ad7194_sigma_delta_info = {
.set_channel = ad7192_set_channel,
.append_status = ad7192_append_status,
.disable_all = ad7192_disable_all,
.set_mode = ad7192_set_mode,
.has_registers = true,
.addr_shift = 3,
.read_mask = BIT(6),
.status_ch_mask = GENMASK(3, 0),
.irq_flags = IRQF_TRIGGER_FALLING,
};
static const struct ad_sd_calib_data ad7192_calib_arr[8] = {
{AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN1},
{AD7192_MODE_CAL_INT_FULL, AD7192_CH_AIN1},
@@ -473,6 +505,16 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev)
st->oversampling_ratio_avail[2] = 8;
st->oversampling_ratio_avail[3] = 16;
st->filter_freq_avail[0][0] = 600;
st->filter_freq_avail[1][0] = 800;
st->filter_freq_avail[2][0] = 2300;
st->filter_freq_avail[3][0] = 2720;
st->filter_freq_avail[0][1] = 1000;
st->filter_freq_avail[1][1] = 1000;
st->filter_freq_avail[2][1] = 1000;
st->filter_freq_avail[3][1] = 1000;
return 0;
}
@@ -586,48 +628,24 @@ static int ad7192_get_f_adc(struct ad7192_state *st)
f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode));
}
static void ad7192_get_available_filter_freq(struct ad7192_state *st,
int *freq)
static void ad7192_update_filter_freq_avail(struct ad7192_state *st)
{
unsigned int fadc;
/* Formulas for filter at page 25 of the datasheet */
fadc = ad7192_compute_f_adc(st, false, true);
freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
st->filter_freq_avail[0][0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
fadc = ad7192_compute_f_adc(st, true, true);
freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
st->filter_freq_avail[1][0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
fadc = ad7192_compute_f_adc(st, false, false);
freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
st->filter_freq_avail[2][0] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
fadc = ad7192_compute_f_adc(st, true, false);
freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
st->filter_freq_avail[3][0] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
}
static ssize_t ad7192_show_filter_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
unsigned int freq_avail[4], i;
size_t len = 0;
ad7192_get_available_filter_freq(st, freq_avail);
for (i = 0; i < ARRAY_SIZE(freq_avail); i++)
len += sysfs_emit_at(buf, len, "%d.%03d ", freq_avail[i] / 1000,
freq_avail[i] % 1000);
buf[len - 1] = '\n';
return len;
}
static IIO_DEVICE_ATTR(filter_low_pass_3db_frequency_available,
0444, ad7192_show_filter_avail, NULL, 0);
static IIO_DEVICE_ATTR(bridge_switch_en, 0644,
ad7192_show_bridge_switch, ad7192_set,
AD7192_REG_GPOCON);
@@ -637,7 +655,6 @@ static IIO_DEVICE_ATTR(ac_excitation_en, 0644,
AD7192_REG_CONF);
static struct attribute *ad7192_attributes[] = {
&iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
NULL
};
@@ -647,7 +664,6 @@ static const struct attribute_group ad7192_attribute_group = {
};
static struct attribute *ad7195_attributes[] = {
&iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
&iio_dev_attr_ac_excitation_en.dev_attr.attr,
NULL
@@ -665,17 +681,15 @@ static unsigned int ad7192_get_temp_scale(bool unipolar)
static int ad7192_set_3db_filter_freq(struct ad7192_state *st,
int val, int val2)
{
int freq_avail[4], i, ret, freq;
int i, ret, freq;
unsigned int diff_new, diff_old;
int idx = 0;
diff_old = U32_MAX;
freq = val * 1000 + val2;
ad7192_get_available_filter_freq(st, freq_avail);
for (i = 0; i < ARRAY_SIZE(freq_avail); i++) {
diff_new = abs(freq - freq_avail[i]);
for (i = 0; i < ARRAY_SIZE(st->filter_freq_avail); i++) {
diff_new = abs(freq - st->filter_freq_avail[i][0]);
if (diff_new < diff_old) {
diff_old = diff_new;
idx = i;
@@ -759,10 +773,24 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
*val = -(1 << (chan->scan_type.realbits - 1));
else
*val = 0;
switch (chan->type) {
case IIO_VOLTAGE:
/*
* Only applies to pseudo-differential inputs.
* AINCOM voltage has to be converted to "raw" units.
*/
if (st->aincom_mv && !chan->differential)
*val += DIV_ROUND_CLOSEST_ULL((u64)st->aincom_mv * NANO,
st->scale_avail[gain][1]);
return IIO_VAL_INT;
/* Kelvin to Celsius */
if (chan->type == IIO_TEMP)
case IIO_TEMP:
*val -= 273 * ad7192_get_temp_scale(unipolar);
return IIO_VAL_INT;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
*val = DIV_ROUND_CLOSEST(ad7192_get_f_adc(st), 1024);
return IIO_VAL_INT;
@@ -792,10 +820,11 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
if (ret)
return ret;
mutex_lock(&st->lock);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
ret = -EINVAL;
mutex_lock(&st->lock);
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
if (val2 == st->scale_avail[i][1]) {
ret = 0;
@@ -809,7 +838,6 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
ad7192_calibrate_all(st);
break;
}
mutex_unlock(&st->lock);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
if (!val) {
@@ -826,13 +854,13 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
st->mode &= ~AD7192_MODE_RATE_MASK;
st->mode |= FIELD_PREP(AD7192_MODE_RATE_MASK, div);
ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
ad7192_update_filter_freq_avail(st);
break;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000);
break;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
ret = -EINVAL;
mutex_lock(&st->lock);
for (i = 0; i < ARRAY_SIZE(st->oversampling_ratio_avail); i++)
if (val == st->oversampling_ratio_avail[i]) {
ret = 0;
@@ -845,12 +873,14 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
3, st->mode);
break;
}
mutex_unlock(&st->lock);
ad7192_update_filter_freq_avail(st);
break;
default:
ret = -EINVAL;
}
mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
return ret;
@@ -888,6 +918,12 @@ static int ad7192_read_avail(struct iio_dev *indio_dev,
/* Values are stored in a 2D matrix */
*length = ARRAY_SIZE(st->scale_avail) * 2;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*vals = (int *)st->filter_freq_avail;
*type = IIO_VAL_FRACTIONAL;
*length = ARRAY_SIZE(st->filter_freq_avail) * 2;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*vals = (int *)st->oversampling_ratio_avail;
@@ -930,6 +966,14 @@ static const struct iio_info ad7192_info = {
.update_scan_mode = ad7192_update_scan_mode,
};
static const struct iio_info ad7194_info = {
.read_raw = ad7192_read_raw,
.write_raw = ad7192_write_raw,
.write_raw_get_fmt = ad7192_write_raw_get_fmt,
.read_avail = ad7192_read_avail,
.validate_trigger = ad_sd_validate_trigger,
};
static const struct iio_info ad7195_info = {
.read_raw = ad7192_read_raw,
.write_raw = ad7192_write_raw,
@@ -956,7 +1000,9 @@ static const struct iio_info ad7195_info = {
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
(_mask_all), \
.info_mask_shared_by_type_available = (_mask_type_av), \
.info_mask_shared_by_all_available = (_mask_all_av), \
.info_mask_shared_by_all_available = \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
(_mask_all_av), \
.ext_info = (_ext_info), \
.scan_index = (_si), \
.scan_type = { \
@@ -1019,12 +1065,95 @@ static const struct iio_chan_spec ad7193_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(14),
};
static bool ad7194_validate_ain_channel(struct device *dev, u32 ain)
{
return in_range(ain, AD7194_CH_AIN_START, AD7194_CH_AIN_NR);
}
static int ad7194_parse_channels(struct iio_dev *indio_dev)
{
struct device *dev = indio_dev->dev.parent;
struct iio_chan_spec *ad7194_channels;
const struct iio_chan_spec ad7194_chan = AD7193_CHANNEL(0, 0, 0);
const struct iio_chan_spec ad7194_chan_diff = AD7193_DIFF_CHANNEL(0, 0, 0, 0);
const struct iio_chan_spec ad7194_chan_temp = AD719x_TEMP_CHANNEL(0, 0);
const struct iio_chan_spec ad7194_chan_timestamp = IIO_CHAN_SOFT_TIMESTAMP(0);
unsigned int num_channels, index = 0;
u32 ain[2];
int ret;
num_channels = device_get_child_node_count(dev);
if (num_channels > AD7194_CH_MAX_NR)
return dev_err_probe(dev, -EINVAL, "Too many channels: %u\n",
num_channels);
num_channels += AD7194_CH_BASE_NR;
ad7194_channels = devm_kcalloc(dev, num_channels,
sizeof(*ad7194_channels), GFP_KERNEL);
if (!ad7194_channels)
return -ENOMEM;
indio_dev->channels = ad7194_channels;
indio_dev->num_channels = num_channels;
device_for_each_child_node_scoped(dev, child) {
ret = fwnode_property_read_u32_array(child, "diff-channels",
ain, ARRAY_SIZE(ain));
if (ret == 0) {
if (!ad7194_validate_ain_channel(dev, ain[0]))
return dev_err_probe(dev, -EINVAL,
"Invalid AIN channel: %u\n",
ain[0]);
if (!ad7194_validate_ain_channel(dev, ain[1]))
return dev_err_probe(dev, -EINVAL,
"Invalid AIN channel: %u\n",
ain[1]);
*ad7194_channels = ad7194_chan_diff;
ad7194_channels->scan_index = index++;
ad7194_channels->channel = ain[0];
ad7194_channels->channel2 = ain[1];
ad7194_channels->address = AD7194_DIFF_CH(ain[0], ain[1]);
} else {
ret = fwnode_property_read_u32(child, "single-channel",
&ain[0]);
if (ret)
return dev_err_probe(dev, ret,
"Missing channel property\n");
if (!ad7194_validate_ain_channel(dev, ain[0]))
return dev_err_probe(dev, -EINVAL,
"Invalid AIN channel: %u\n",
ain[0]);
*ad7194_channels = ad7194_chan;
ad7194_channels->scan_index = index++;
ad7194_channels->channel = ain[0];
ad7194_channels->address = AD7194_CH(ain[0]);
}
ad7194_channels++;
}
*ad7194_channels = ad7194_chan_temp;
ad7194_channels->scan_index = index++;
ad7194_channels->address = AD7194_CH_TEMP;
ad7194_channels++;
*ad7194_channels = ad7194_chan_timestamp;
ad7194_channels->scan_index = index;
return 0;
}
static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
[ID_AD7190] = {
.chip_id = CHIPID_AD7190,
.name = "ad7190",
.channels = ad7192_channels,
.num_channels = ARRAY_SIZE(ad7192_channels),
.sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7192_info,
},
[ID_AD7192] = {
@@ -1032,6 +1161,7 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
.name = "ad7192",
.channels = ad7192_channels,
.num_channels = ARRAY_SIZE(ad7192_channels),
.sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7192_info,
},
[ID_AD7193] = {
@@ -1039,13 +1169,22 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
.name = "ad7193",
.channels = ad7193_channels,
.num_channels = ARRAY_SIZE(ad7193_channels),
.sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7192_info,
},
[ID_AD7194] = {
.chip_id = CHIPID_AD7194,
.name = "ad7194",
.info = &ad7194_info,
.sigma_delta_info = &ad7194_sigma_delta_info,
.parse_channels = ad7194_parse_channels,
},
[ID_AD7195] = {
.chip_id = CHIPID_AD7195,
.name = "ad7195",
.channels = ad7192_channels,
.num_channels = ARRAY_SIZE(ad7192_channels),
.sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7195_info,
},
};
@@ -1059,6 +1198,7 @@ static int ad7192_probe(struct spi_device *spi)
{
struct ad7192_state *st;
struct iio_dev *indio_dev;
struct regulator *aincom;
int ret;
if (!spi->irq) {
@@ -1074,6 +1214,35 @@ static int ad7192_probe(struct spi_device *spi)
mutex_init(&st->lock);
/*
* Regulator aincom is optional to maintain compatibility with older DT.
* Newer firmware should provide a zero volt fixed supply if wired to
* ground.
*/
aincom = devm_regulator_get_optional(&spi->dev, "aincom");
if (IS_ERR(aincom)) {
if (PTR_ERR(aincom) != -ENODEV)
return dev_err_probe(&spi->dev, PTR_ERR(aincom),
"Failed to get AINCOM supply\n");
st->aincom_mv = 0;
} else {
ret = regulator_enable(aincom);
if (ret)
return dev_err_probe(&spi->dev, ret,
"Failed to enable specified AINCOM supply\n");
ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, aincom);
if (ret)
return ret;
ret = regulator_get_voltage(aincom);
if (ret < 0)
return dev_err_probe(&spi->dev, ret,
"Device tree error, AINCOM voltage undefined\n");
st->aincom_mv = ret / MILLI;
}
st->avdd = devm_regulator_get(&spi->dev, "avdd");
if (IS_ERR(st->avdd))
return PTR_ERR(st->avdd);
@@ -1122,11 +1291,17 @@ static int ad7192_probe(struct spi_device *spi)
st->chip_info = spi_get_device_match_data(spi);
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = st->chip_info->info;
if (st->chip_info->parse_channels) {
ret = st->chip_info->parse_channels(indio_dev);
if (ret)
return ret;
} else {
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
}
ret = ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info);
ret = ad_sd_init(&st->sd, indio_dev, spi, st->chip_info->sigma_delta_info);
if (ret)
return ret;
@@ -1163,6 +1338,7 @@ static const struct of_device_id ad7192_of_match[] = {
{ .compatible = "adi,ad7190", .data = &ad7192_chip_info_tbl[ID_AD7190] },
{ .compatible = "adi,ad7192", .data = &ad7192_chip_info_tbl[ID_AD7192] },
{ .compatible = "adi,ad7193", .data = &ad7192_chip_info_tbl[ID_AD7193] },
{ .compatible = "adi,ad7194", .data = &ad7192_chip_info_tbl[ID_AD7194] },
{ .compatible = "adi,ad7195", .data = &ad7192_chip_info_tbl[ID_AD7195] },
{}
};
@@ -1172,6 +1348,7 @@ static const struct spi_device_id ad7192_ids[] = {
{ "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] },
{ "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] },
{ "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] },
{ "ad7194", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] },
{ "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] },
{}
};
@@ -1188,6 +1365,6 @@ static struct spi_driver ad7192_driver = {
module_spi_driver(ad7192_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC");
MODULE_DESCRIPTION("Analog Devices AD7192 and similar ADC");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);
+1 -1
View File
@@ -536,7 +536,7 @@ static int ad7291_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad7291_id[] = {
{ "ad7291", 0 },
{ "ad7291" },
{}
};
+833
View File
@@ -0,0 +1,833 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Analog Devices AD738x Simultaneous Sampling SAR ADCs
*
* Copyright 2017 Analog Devices Inc.
* Copyright 2024 BayLibre, SAS
*
* Datasheets of supported parts:
* ad7380/1 : https://www.analog.com/media/en/technical-documentation/data-sheets/AD7380-7381.pdf
* ad7383/4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-7384.pdf
* ad7380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7380-4.pdf
* 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
*/
#include <linux/align.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kernel.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/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#define MAX_NUM_CHANNELS 4
/* 2.5V internal reference voltage */
#define AD7380_INTERNAL_REF_MV 2500
/* reading and writing registers is more reliable at lower than max speed */
#define AD7380_REG_WR_SPEED_HZ 10000000
#define AD7380_REG_WR BIT(15)
#define AD7380_REG_REGADDR GENMASK(14, 12)
#define AD7380_REG_DATA GENMASK(11, 0)
#define AD7380_REG_ADDR_NOP 0x0
#define AD7380_REG_ADDR_CONFIG1 0x1
#define AD7380_REG_ADDR_CONFIG2 0x2
#define AD7380_REG_ADDR_ALERT 0x3
#define AD7380_REG_ADDR_ALERT_LOW_TH 0x4
#define AD7380_REG_ADDR_ALERT_HIGH_TH 0x5
#define AD7380_CONFIG1_OS_MODE BIT(9)
#define AD7380_CONFIG1_OSR GENMASK(8, 6)
#define AD7380_CONFIG1_CRC_W BIT(5)
#define AD7380_CONFIG1_CRC_R BIT(4)
#define AD7380_CONFIG1_ALERTEN BIT(3)
#define AD7380_CONFIG1_RES BIT(2)
#define AD7380_CONFIG1_REFSEL BIT(1)
#define AD7380_CONFIG1_PMODE BIT(0)
#define AD7380_CONFIG2_SDO2 GENMASK(9, 8)
#define AD7380_CONFIG2_SDO BIT(8)
#define AD7380_CONFIG2_RESET GENMASK(7, 0)
#define AD7380_CONFIG2_RESET_SOFT 0x3C
#define AD7380_CONFIG2_RESET_HARD 0xFF
#define AD7380_ALERT_LOW_TH GENMASK(11, 0)
#define AD7380_ALERT_HIGH_TH GENMASK(11, 0)
#define T_CONVERT_NS 190 /* conversion time */
#define T_CONVERT_0_NS 10 /* 1st conversion start time (oversampling) */
#define T_CONVERT_X_NS 500 /* xth conversion start time (oversampling) */
struct ad7380_timing_specs {
const unsigned int t_csh_ns; /* CS minimum high time */
};
struct ad7380_chip_info {
const char *name;
const struct iio_chan_spec *channels;
unsigned int num_channels;
const char * const *vcm_supplies;
unsigned int num_vcm_supplies;
const unsigned long *available_scan_masks;
const struct ad7380_timing_specs *timing_specs;
};
enum {
AD7380_SCAN_TYPE_NORMAL,
AD7380_SCAN_TYPE_RESOLUTION_BOOST,
};
/* Extended scan types for 14-bit chips. */
static const struct iio_scan_type ad7380_scan_type_14[] = {
[AD7380_SCAN_TYPE_NORMAL] = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
.endianness = IIO_CPU
},
[AD7380_SCAN_TYPE_RESOLUTION_BOOST] = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU
},
};
/* Extended scan types for 16-bit chips. */
static const struct iio_scan_type ad7380_scan_type_16[] = {
[AD7380_SCAN_TYPE_NORMAL] = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU
},
[AD7380_SCAN_TYPE_RESOLUTION_BOOST] = {
.sign = 's',
.realbits = 18,
.storagebits = 32,
.endianness = IIO_CPU
},
};
#define AD7380_CHANNEL(index, bits, diff) { \
.type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.info_mask_shared_by_type_available = \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.indexed = 1, \
.differential = (diff), \
.channel = (diff) ? (2 * (index)) : (index), \
.channel2 = (diff) ? (2 * (index) + 1) : 0, \
.scan_index = (index), \
.has_ext_scan_type = 1, \
.ext_scan_type = ad7380_scan_type_##bits, \
.num_ext_scan_type = ARRAY_SIZE(ad7380_scan_type_##bits),\
}
#define DEFINE_AD7380_2_CHANNEL(name, bits, diff) \
static const struct iio_chan_spec name[] = { \
AD7380_CHANNEL(0, bits, diff), \
AD7380_CHANNEL(1, bits, diff), \
IIO_CHAN_SOFT_TIMESTAMP(2), \
}
#define DEFINE_AD7380_4_CHANNEL(name, bits, diff) \
static const struct iio_chan_spec name[] = { \
AD7380_CHANNEL(0, bits, diff), \
AD7380_CHANNEL(1, bits, diff), \
AD7380_CHANNEL(2, bits, diff), \
AD7380_CHANNEL(3, bits, diff), \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
/* fully differential */
DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1);
DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1);
DEFINE_AD7380_4_CHANNEL(ad7380_4_channels, 16, 1);
DEFINE_AD7380_4_CHANNEL(ad7381_4_channels, 14, 1);
/* pseudo differential */
DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0);
DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0);
DEFINE_AD7380_4_CHANNEL(ad7383_4_channels, 16, 0);
DEFINE_AD7380_4_CHANNEL(ad7384_4_channels, 14, 0);
static const char * const ad7380_2_channel_vcm_supplies[] = {
"aina", "ainb",
};
static const char * const ad7380_4_channel_vcm_supplies[] = {
"aina", "ainb", "ainc", "aind",
};
/* Since this is simultaneous sampling, we don't allow individual channels. */
static const unsigned long ad7380_2_channel_scan_masks[] = {
GENMASK(1, 0),
0
};
static const unsigned long ad7380_4_channel_scan_masks[] = {
GENMASK(3, 0),
0
};
static const struct ad7380_timing_specs ad7380_timing = {
.t_csh_ns = 10,
};
static const struct ad7380_timing_specs ad7380_4_timing = {
.t_csh_ns = 20,
};
/*
* Available oversampling ratios. The indices correspond with the bit value
* expected by the chip. The available ratios depend on the averaging mode,
* only normal averaging is supported for now.
*/
static const int ad7380_oversampling_ratios[] = {
1, 2, 4, 8, 16, 32,
};
static const struct ad7380_chip_info ad7380_chip_info = {
.name = "ad7380",
.channels = ad7380_channels,
.num_channels = ARRAY_SIZE(ad7380_channels),
.available_scan_masks = ad7380_2_channel_scan_masks,
.timing_specs = &ad7380_timing,
};
static const struct ad7380_chip_info ad7381_chip_info = {
.name = "ad7381",
.channels = ad7381_channels,
.num_channels = ARRAY_SIZE(ad7381_channels),
.available_scan_masks = ad7380_2_channel_scan_masks,
.timing_specs = &ad7380_timing,
};
static const struct ad7380_chip_info ad7383_chip_info = {
.name = "ad7383",
.channels = ad7383_channels,
.num_channels = ARRAY_SIZE(ad7383_channels),
.vcm_supplies = ad7380_2_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
.available_scan_masks = ad7380_2_channel_scan_masks,
.timing_specs = &ad7380_timing,
};
static const struct ad7380_chip_info ad7384_chip_info = {
.name = "ad7384",
.channels = ad7384_channels,
.num_channels = ARRAY_SIZE(ad7384_channels),
.vcm_supplies = ad7380_2_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
.available_scan_masks = ad7380_2_channel_scan_masks,
.timing_specs = &ad7380_timing,
};
static const struct ad7380_chip_info ad7380_4_chip_info = {
.name = "ad7380-4",
.channels = ad7380_4_channels,
.num_channels = ARRAY_SIZE(ad7380_4_channels),
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
};
static const struct ad7380_chip_info ad7381_4_chip_info = {
.name = "ad7381-4",
.channels = ad7381_4_channels,
.num_channels = ARRAY_SIZE(ad7381_4_channels),
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
};
static const struct ad7380_chip_info ad7383_4_chip_info = {
.name = "ad7383-4",
.channels = ad7383_4_channels,
.num_channels = ARRAY_SIZE(ad7383_4_channels),
.vcm_supplies = ad7380_4_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
};
static const struct ad7380_chip_info ad7384_4_chip_info = {
.name = "ad7384-4",
.channels = ad7384_4_channels,
.num_channels = ARRAY_SIZE(ad7384_4_channels),
.vcm_supplies = ad7380_4_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
.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;
struct regmap *regmap;
unsigned int oversampling_ratio;
bool resolution_boost_enabled;
unsigned int vref_mv;
unsigned int vcm_mv[MAX_NUM_CHANNELS];
/* xfers, message an buffer for reading sample data */
struct spi_transfer xfer[2];
struct spi_message msg;
/*
* DMA (thus cache coherency maintenance) requires the transfer buffers
* to live in their own cache lines.
*
* Make the buffer large enough for MAX_NUM_CHANNELS 32-bit samples and
* one 64-bit aligned 64-bit timestamp.
*/
u8 scan_data[ALIGN(MAX_NUM_CHANNELS * sizeof(u32), sizeof(s64))
+ sizeof(s64)] __aligned(IIO_DMA_MINALIGN);
/* buffers for reading/writing registers */
u16 tx;
u16 rx;
};
static int ad7380_regmap_reg_write(void *context, unsigned int reg,
unsigned int val)
{
struct ad7380_state *st = context;
struct spi_transfer xfer = {
.speed_hz = AD7380_REG_WR_SPEED_HZ,
.bits_per_word = 16,
.len = 2,
.tx_buf = &st->tx,
};
st->tx = FIELD_PREP(AD7380_REG_WR, 1) |
FIELD_PREP(AD7380_REG_REGADDR, reg) |
FIELD_PREP(AD7380_REG_DATA, val);
return spi_sync_transfer(st->spi, &xfer, 1);
}
static int ad7380_regmap_reg_read(void *context, unsigned int reg,
unsigned int *val)
{
struct ad7380_state *st = context;
struct spi_transfer xfers[] = {
{
.speed_hz = AD7380_REG_WR_SPEED_HZ,
.bits_per_word = 16,
.len = 2,
.tx_buf = &st->tx,
.cs_change = 1,
.cs_change_delay = {
.value = st->chip_info->timing_specs->t_csh_ns,
.unit = SPI_DELAY_UNIT_NSECS,
},
}, {
.speed_hz = AD7380_REG_WR_SPEED_HZ,
.bits_per_word = 16,
.len = 2,
.rx_buf = &st->rx,
},
};
int ret;
st->tx = FIELD_PREP(AD7380_REG_WR, 0) |
FIELD_PREP(AD7380_REG_REGADDR, reg) |
FIELD_PREP(AD7380_REG_DATA, 0);
ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
if (ret < 0)
return ret;
*val = FIELD_GET(AD7380_REG_DATA, st->rx);
return 0;
}
static const struct regmap_config ad7380_regmap_config = {
.reg_bits = 3,
.val_bits = 12,
.reg_read = ad7380_regmap_reg_read,
.reg_write = ad7380_regmap_reg_write,
.max_register = AD7380_REG_ADDR_ALERT_HIGH_TH,
.can_sleep = true,
};
static int ad7380_debugfs_reg_access(struct iio_dev *indio_dev, u32 reg,
u32 writeval, u32 *readval)
{
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
struct ad7380_state *st = iio_priv(indio_dev);
if (readval)
return regmap_read(st->regmap, reg, readval);
else
return regmap_write(st->regmap, reg, writeval);
}
unreachable();
}
/**
* ad7380_update_xfers - update the SPI transfers base on the current scan type
* @st: device instance specific state
* @scan_type: current scan type
*/
static void ad7380_update_xfers(struct ad7380_state *st,
const struct iio_scan_type *scan_type)
{
/*
* First xfer only triggers conversion and has to be long enough for
* all conversions to complete, which can be multiple conversion in the
* case of oversampling. Technically T_CONVERT_X_NS is lower for some
* chips, but we use the maximum value for simplicity for now.
*/
if (st->oversampling_ratio > 1)
st->xfer[0].delay.value = T_CONVERT_0_NS + T_CONVERT_X_NS *
(st->oversampling_ratio - 1);
else
st->xfer[0].delay.value = T_CONVERT_NS;
st->xfer[0].delay.unit = SPI_DELAY_UNIT_NSECS;
/*
* Second xfer reads all channels. Data size depends on if resolution
* boost is enabled or not.
*/
st->xfer[1].bits_per_word = scan_type->realbits;
st->xfer[1].len = BITS_TO_BYTES(scan_type->storagebits) *
(st->chip_info->num_channels - 1);
}
static int ad7380_triggered_buffer_preenable(struct iio_dev *indio_dev)
{
struct ad7380_state *st = iio_priv(indio_dev);
const struct iio_scan_type *scan_type;
/*
* Currently, we always read all channels at the same time. The scan_type
* is the same for all channels, so we just pass the first channel.
*/
scan_type = iio_get_current_scan_type(indio_dev, &indio_dev->channels[0]);
if (IS_ERR(scan_type))
return PTR_ERR(scan_type);
ad7380_update_xfers(st, scan_type);
return spi_optimize_message(st->spi, &st->msg);
}
static int ad7380_triggered_buffer_postdisable(struct iio_dev *indio_dev)
{
struct ad7380_state *st = iio_priv(indio_dev);
spi_unoptimize_message(&st->msg);
return 0;
}
static const struct iio_buffer_setup_ops ad7380_buffer_setup_ops = {
.preenable = ad7380_triggered_buffer_preenable,
.postdisable = ad7380_triggered_buffer_postdisable,
};
static irqreturn_t ad7380_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7380_state *st = iio_priv(indio_dev);
int ret;
ret = spi_sync(st->spi, &st->msg);
if (ret)
goto out;
iio_push_to_buffers_with_timestamp(indio_dev, &st->scan_data,
pf->timestamp);
out:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ad7380_read_direct(struct ad7380_state *st, unsigned int scan_index,
const struct iio_scan_type *scan_type, int *val)
{
int ret;
ad7380_update_xfers(st, scan_type);
ret = spi_sync(st->spi, &st->msg);
if (ret < 0)
return ret;
if (scan_type->storagebits > 16)
*val = sign_extend32(*(u32 *)(st->scan_data + 4 * scan_index),
scan_type->realbits - 1);
else
*val = sign_extend32(*(u16 *)(st->scan_data + 2 * scan_index),
scan_type->realbits - 1);
return IIO_VAL_INT;
}
static int ad7380_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long info)
{
struct ad7380_state *st = iio_priv(indio_dev);
const struct iio_scan_type *scan_type;
scan_type = iio_get_current_scan_type(indio_dev, chan);
if (IS_ERR(scan_type))
return PTR_ERR(scan_type);
switch (info) {
case IIO_CHAN_INFO_RAW:
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
return ad7380_read_direct(st, chan->scan_index,
scan_type, val);
}
unreachable();
case IIO_CHAN_INFO_SCALE:
/*
* According to the datasheet, the LSB size is:
* * (2 × VREF) / 2^N, for differential chips
* * VREF / 2^N, for pseudo-differential chips
* where N is the ADC resolution (i.e realbits)
*/
*val = st->vref_mv;
*val2 = scan_type->realbits - chan->differential;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
/*
* According to IIO ABI, offset is applied before scale,
* so offset is: vcm_mv / scale
*/
*val = st->vcm_mv[chan->channel] * (1 << scan_type->realbits)
/ st->vref_mv;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = st->oversampling_ratio;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int ad7380_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_OVERSAMPLING_RATIO:
*vals = ad7380_oversampling_ratios;
*length = ARRAY_SIZE(ad7380_oversampling_ratios);
*type = IIO_VAL_INT;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
/**
* ad7380_osr_to_regval - convert ratio to OSR register value
* @ratio: ratio to check
*
* Check if ratio is present in the list of available ratios and return the
* corresponding value that needs to be written to the register to select that
* ratio.
*
* Returns: register value (0 to 7) or -EINVAL if there is not an exact match
*/
static int ad7380_osr_to_regval(int ratio)
{
int i;
for (i = 0; i < ARRAY_SIZE(ad7380_oversampling_ratios); i++) {
if (ratio == ad7380_oversampling_ratios[i])
return i;
}
return -EINVAL;
}
static int ad7380_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
{
struct ad7380_state *st = iio_priv(indio_dev);
int ret, osr, boost;
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
osr = ad7380_osr_to_regval(val);
if (osr < 0)
return osr;
/* always enable resolution boost when oversampling is enabled */
boost = osr > 0 ? 1 : 0;
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
ret = regmap_update_bits(st->regmap,
AD7380_REG_ADDR_CONFIG1,
AD7380_CONFIG1_OSR | AD7380_CONFIG1_RES,
FIELD_PREP(AD7380_CONFIG1_OSR, osr) |
FIELD_PREP(AD7380_CONFIG1_RES, boost));
if (ret)
return ret;
st->oversampling_ratio = val;
st->resolution_boost_enabled = boost;
/*
* Perform a soft reset. This will flush the oversampling
* block and FIFO but will maintain the content of the
* configurable registers.
*/
return regmap_update_bits(st->regmap,
AD7380_REG_ADDR_CONFIG2,
AD7380_CONFIG2_RESET,
FIELD_PREP(AD7380_CONFIG2_RESET,
AD7380_CONFIG2_RESET_SOFT));
}
unreachable();
default:
return -EINVAL;
}
}
static int ad7380_get_current_scan_type(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad7380_state *st = iio_priv(indio_dev);
return st->resolution_boost_enabled ? AD7380_SCAN_TYPE_RESOLUTION_BOOST
: AD7380_SCAN_TYPE_NORMAL;
}
static const struct iio_info ad7380_info = {
.read_raw = &ad7380_read_raw,
.read_avail = &ad7380_read_avail,
.write_raw = &ad7380_write_raw,
.get_current_scan_type = &ad7380_get_current_scan_type,
.debugfs_reg_access = &ad7380_debugfs_reg_access,
};
static int ad7380_init(struct ad7380_state *st, struct regulator *vref)
{
int ret;
/* perform hard reset */
ret = regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
AD7380_CONFIG2_RESET,
FIELD_PREP(AD7380_CONFIG2_RESET,
AD7380_CONFIG2_RESET_HARD));
if (ret < 0)
return ret;
/* select internal or external reference voltage */
ret = regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG1,
AD7380_CONFIG1_REFSEL,
FIELD_PREP(AD7380_CONFIG1_REFSEL,
vref ? 1 : 0));
if (ret < 0)
return ret;
/* This is the default value after reset. */
st->oversampling_ratio = 1;
/* SPI 1-wire mode */
return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
AD7380_CONFIG2_SDO,
FIELD_PREP(AD7380_CONFIG2_SDO, 1));
}
static void ad7380_regulator_disable(void *p)
{
regulator_disable(p);
}
static int ad7380_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ad7380_state *st;
struct regulator *vref;
int ret, i;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
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");
vref = devm_regulator_get_optional(&spi->dev, "refio");
if (IS_ERR(vref)) {
if (PTR_ERR(vref) != -ENODEV)
return dev_err_probe(&spi->dev, PTR_ERR(vref),
"Failed to get refio regulator\n");
vref = NULL;
}
/*
* If there is no REFIO supply, then it means that we are using
* the internal 2.5V reference, otherwise REFIO is reference voltage.
*/
if (vref) {
ret = regulator_enable(vref);
if (ret)
return ret;
ret = devm_add_action_or_reset(&spi->dev,
ad7380_regulator_disable, vref);
if (ret)
return ret;
ret = regulator_get_voltage(vref);
if (ret < 0)
return ret;
st->vref_mv = ret / 1000;
} else {
st->vref_mv = AD7380_INTERNAL_REF_MV;
}
if (st->chip_info->num_vcm_supplies > ARRAY_SIZE(st->vcm_mv))
return dev_err_probe(&spi->dev, -EINVAL,
"invalid number of VCM supplies\n");
/*
* pseudo-differential chips have common mode supplies for the negative
* input pin.
*/
for (i = 0; i < st->chip_info->num_vcm_supplies; i++) {
struct regulator *vcm;
vcm = devm_regulator_get(&spi->dev,
st->chip_info->vcm_supplies[i]);
if (IS_ERR(vcm))
return dev_err_probe(&spi->dev, PTR_ERR(vcm),
"Failed to get %s regulator\n",
st->chip_info->vcm_supplies[i]);
ret = regulator_enable(vcm);
if (ret)
return ret;
ret = devm_add_action_or_reset(&spi->dev,
ad7380_regulator_disable, vcm);
if (ret)
return ret;
ret = regulator_get_voltage(vcm);
if (ret < 0)
return ret;
st->vcm_mv[i] = ret / 1000;
}
st->regmap = devm_regmap_init(&spi->dev, NULL, st, &ad7380_regmap_config);
if (IS_ERR(st->regmap))
return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
"failed to allocate register map\n");
/*
* Setting up a low latency read for getting sample data. Used for both
* direct read an triggered buffer. Additional fields will be set up in
* ad7380_update_xfers() based on the current state of the driver at the
* time of the read.
*/
/* toggle CS (no data xfer) to trigger a conversion */
st->xfer[0].cs_change = 1;
st->xfer[0].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
st->xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
/* then do a second xfer to read the data */
st->xfer[1].rx_buf = st->scan_data;
spi_message_init_with_transfers(&st->msg, st->xfer, ARRAY_SIZE(st->xfer));
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->name = st->chip_info->name;
indio_dev->info = &ad7380_info;
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,
iio_pollfunc_store_time,
ad7380_trigger_handler,
&ad7380_buffer_setup_ops);
if (ret)
return ret;
ret = ad7380_init(st, vref);
if (ret)
return ret;
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id ad7380_of_match_table[] = {
{ .compatible = "adi,ad7380", .data = &ad7380_chip_info },
{ .compatible = "adi,ad7381", .data = &ad7381_chip_info },
{ .compatible = "adi,ad7383", .data = &ad7383_chip_info },
{ .compatible = "adi,ad7384", .data = &ad7384_chip_info },
{ .compatible = "adi,ad7380-4", .data = &ad7380_4_chip_info },
{ .compatible = "adi,ad7381-4", .data = &ad7381_4_chip_info },
{ .compatible = "adi,ad7383-4", .data = &ad7383_4_chip_info },
{ .compatible = "adi,ad7384-4", .data = &ad7384_4_chip_info },
{ }
};
static const struct spi_device_id ad7380_id_table[] = {
{ "ad7380", (kernel_ulong_t)&ad7380_chip_info },
{ "ad7381", (kernel_ulong_t)&ad7381_chip_info },
{ "ad7383", (kernel_ulong_t)&ad7383_chip_info },
{ "ad7384", (kernel_ulong_t)&ad7384_chip_info },
{ "ad7380-4", (kernel_ulong_t)&ad7380_4_chip_info },
{ "ad7381-4", (kernel_ulong_t)&ad7381_4_chip_info },
{ "ad7383-4", (kernel_ulong_t)&ad7383_4_chip_info },
{ "ad7384-4", (kernel_ulong_t)&ad7384_4_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7380_id_table);
static struct spi_driver ad7380_driver = {
.driver = {
.name = "ad7380",
.of_match_table = ad7380_of_match_table,
},
.probe = ad7380_probe,
.id_table = ad7380_id_table,
};
module_spi_driver(ad7380_driver);
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD738x ADC driver");
MODULE_LICENSE("GPL");
+8 -11
View File
@@ -174,17 +174,14 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = ad7606_scan_direct(indio_dev, chan->address);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
*val = (short)ret;
return IIO_VAL_INT;
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
ret = ad7606_scan_direct(indio_dev, chan->address);
if (ret < 0)
return ret;
*val = (short) ret;
return IIO_VAL_INT;
}
unreachable();
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
ch = chan->address;
+3 -5
View File
@@ -259,7 +259,6 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc
/**
* ad7944_convert_and_acquire - Perform a single conversion and acquisition
* @adc: The ADC device structure
* @chan: The channel specification
* Return: 0 on success, a negative error code on failure
*
* Perform a conversion and acquisition of a single sample using the
@@ -268,8 +267,7 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc
* Upon successful return adc->sample.raw will contain the conversion result
* (or adc->chain_mode_buf if the device is using chain mode).
*/
static int ad7944_convert_and_acquire(struct ad7944_adc *adc,
const struct iio_chan_spec *chan)
static int ad7944_convert_and_acquire(struct ad7944_adc *adc)
{
int ret;
@@ -291,7 +289,7 @@ static int ad7944_single_conversion(struct ad7944_adc *adc,
{
int ret;
ret = ad7944_convert_and_acquire(adc, chan);
ret = ad7944_convert_and_acquire(adc);
if (ret)
return ret;
@@ -361,7 +359,7 @@ static irqreturn_t ad7944_trigger_handler(int irq, void *p)
struct ad7944_adc *adc = iio_priv(indio_dev);
int ret;
ret = ad7944_convert_and_acquire(adc, &indio_dev->channels[0]);
ret = ad7944_convert_and_acquire(adc);
if (ret)
goto out;
+50 -53
View File
@@ -107,27 +107,27 @@
#define AD9647_MAX_TEST_POINTS 32
struct ad9467_chip_info {
const char *name;
unsigned int id;
const struct iio_chan_spec *channels;
unsigned int num_channels;
const unsigned int (*scale_table)[2];
int num_scales;
unsigned long max_rate;
unsigned int default_output_mode;
unsigned int vref_mask;
unsigned int num_lanes;
const char *name;
unsigned int id;
const struct iio_chan_spec *channels;
unsigned int num_channels;
const unsigned int (*scale_table)[2];
int num_scales;
unsigned long max_rate;
unsigned int default_output_mode;
unsigned int vref_mask;
unsigned int num_lanes;
/* data clock output */
bool has_dco;
bool has_dco;
};
struct ad9467_state {
const struct ad9467_chip_info *info;
struct iio_backend *back;
struct spi_device *spi;
struct clk *clk;
unsigned int output_mode;
unsigned int (*scales)[2];
const struct ad9467_chip_info *info;
struct iio_backend *back;
struct spi_device *spi;
struct clk *clk;
unsigned int output_mode;
unsigned int (*scales)[2];
/*
* Times 2 because we may also invert the signal polarity and run the
* calibration again. For some reference on the test points (ad9265) see:
@@ -138,12 +138,13 @@ struct ad9467_state {
* at the io delay control section.
*/
DECLARE_BITMAP(calib_map, AD9647_MAX_TEST_POINTS * 2);
struct gpio_desc *pwrdown_gpio;
struct gpio_desc *pwrdown_gpio;
/* ensure consistent state obtained on multiple related accesses */
struct mutex lock;
struct mutex lock;
u8 buf[3] __aligned(IIO_DMA_MINALIGN);
};
static int ad9467_spi_read(struct spi_device *spi, unsigned int reg)
static int ad9467_spi_read(struct ad9467_state *st, unsigned int reg)
{
unsigned char tbuf[2], rbuf[1];
int ret;
@@ -151,7 +152,7 @@ static int ad9467_spi_read(struct spi_device *spi, unsigned int reg)
tbuf[0] = 0x80 | (reg >> 8);
tbuf[1] = reg & 0xFF;
ret = spi_write_then_read(spi,
ret = spi_write_then_read(st->spi,
tbuf, ARRAY_SIZE(tbuf),
rbuf, ARRAY_SIZE(rbuf));
@@ -161,35 +162,32 @@ static int ad9467_spi_read(struct spi_device *spi, unsigned int reg)
return rbuf[0];
}
static int ad9467_spi_write(struct spi_device *spi, unsigned int reg,
static int ad9467_spi_write(struct ad9467_state *st, unsigned int reg,
unsigned int val)
{
unsigned char buf[3];
st->buf[0] = reg >> 8;
st->buf[1] = reg & 0xFF;
st->buf[2] = val;
buf[0] = reg >> 8;
buf[1] = reg & 0xFF;
buf[2] = val;
return spi_write(spi, buf, ARRAY_SIZE(buf));
return spi_write(st->spi, st->buf, ARRAY_SIZE(st->buf));
}
static int ad9467_reg_access(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval)
{
struct ad9467_state *st = iio_priv(indio_dev);
struct spi_device *spi = st->spi;
int ret;
if (!readval) {
guard(mutex)(&st->lock);
ret = ad9467_spi_write(spi, reg, writeval);
ret = ad9467_spi_write(st, reg, writeval);
if (ret)
return ret;
return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER,
return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
ret = ad9467_spi_read(spi, reg);
ret = ad9467_spi_read(st, reg);
if (ret < 0)
return ret;
*readval = ret;
@@ -295,7 +293,7 @@ static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2)
unsigned int i, vref_val;
int ret;
ret = ad9467_spi_read(st->spi, AN877_ADC_REG_VREF);
ret = ad9467_spi_read(st, AN877_ADC_REG_VREF);
if (ret < 0)
return ret;
@@ -330,31 +328,31 @@ static int ad9467_set_scale(struct ad9467_state *st, int val, int val2)
continue;
guard(mutex)(&st->lock);
ret = ad9467_spi_write(st->spi, AN877_ADC_REG_VREF,
ret = ad9467_spi_write(st, AN877_ADC_REG_VREF,
info->scale_table[i][1]);
if (ret < 0)
return ret;
return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
return -EINVAL;
}
static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
static int ad9467_outputmode_set(struct ad9467_state *st, unsigned int mode)
{
int ret;
ret = ad9467_spi_write(spi, AN877_ADC_REG_OUTPUT_MODE, mode);
ret = ad9467_spi_write(st, AN877_ADC_REG_OUTPUT_MODE, mode);
if (ret < 0)
return ret;
return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER,
return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
static int ad9647_calibrate_prepare(const struct ad9467_state *st)
static int ad9647_calibrate_prepare(struct ad9467_state *st)
{
struct iio_backend_data_fmt data = {
.enable = false,
@@ -362,17 +360,17 @@ static int ad9647_calibrate_prepare(const struct ad9467_state *st)
unsigned int c;
int ret;
ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TEST_IO,
ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO,
AN877_ADC_TESTMODE_PN9_SEQ);
if (ret)
return ret;
ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
ret = ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
if (ret)
return ret;
ret = ad9467_outputmode_set(st->spi, st->info->default_output_mode);
ret = ad9467_outputmode_set(st, st->info->default_output_mode);
if (ret)
return ret;
@@ -390,7 +388,7 @@ static int ad9647_calibrate_prepare(const struct ad9467_state *st)
return iio_backend_chan_enable(st->back, 0);
}
static int ad9647_calibrate_polarity_set(const struct ad9467_state *st,
static int ad9647_calibrate_polarity_set(struct ad9467_state *st,
bool invert)
{
enum iio_backend_sample_trigger trigger;
@@ -401,7 +399,7 @@ static int ad9647_calibrate_polarity_set(const struct ad9467_state *st,
if (invert)
phase |= AN877_ADC_INVERT_DCO_CLK;
return ad9467_spi_write(st->spi, AN877_ADC_REG_OUTPUT_PHASE,
return ad9467_spi_write(st, AN877_ADC_REG_OUTPUT_PHASE,
phase);
}
@@ -437,19 +435,18 @@ static unsigned int ad9467_find_optimal_point(const unsigned long *calib_map,
return cnt;
}
static int ad9467_calibrate_apply(const struct ad9467_state *st,
unsigned int val)
static int ad9467_calibrate_apply(struct ad9467_state *st, unsigned int val)
{
unsigned int lane;
int ret;
if (st->info->has_dco) {
ret = ad9467_spi_write(st->spi, AN877_ADC_REG_OUTPUT_DELAY,
ret = ad9467_spi_write(st, AN877_ADC_REG_OUTPUT_DELAY,
val);
if (ret)
return ret;
return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
@@ -462,7 +459,7 @@ static int ad9467_calibrate_apply(const struct ad9467_state *st,
return 0;
}
static int ad9647_calibrate_stop(const struct ad9467_state *st)
static int ad9647_calibrate_stop(struct ad9467_state *st)
{
struct iio_backend_data_fmt data = {
.sign_extend = true,
@@ -487,16 +484,16 @@ static int ad9647_calibrate_stop(const struct ad9467_state *st)
}
mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
ret = ad9467_outputmode_set(st->spi, mode);
ret = ad9467_outputmode_set(st, mode);
if (ret)
return ret;
ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TEST_IO,
ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO,
AN877_ADC_TESTMODE_OFF);
if (ret)
return ret;
return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
@@ -846,7 +843,7 @@ static int ad9467_probe(struct spi_device *spi)
if (ret)
return ret;
id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID);
id = ad9467_spi_read(st, AN877_ADC_REG_CHIP_ID);
if (id != st->info->id) {
dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n",
id, st->info->id);
+17 -1
View File
@@ -42,6 +42,9 @@
#define ADI_AXI_ADC_REG_CTRL 0x0044
#define ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK BIT(1)
#define ADI_AXI_ADC_REG_DRP_STATUS 0x0074
#define ADI_AXI_ADC_DRP_LOCKED BIT(17)
/* ADC Channel controls */
#define ADI_AXI_REG_CHAN_CTRL(c) (0x0400 + (c) * 0x40)
@@ -83,14 +86,26 @@ struct adi_axi_adc_state {
static int axi_adc_enable(struct iio_backend *back)
{
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
unsigned int __val;
int ret;
guard(mutex)(&st->lock);
ret = regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
ADI_AXI_REG_RSTN_MMCM_RSTN);
if (ret)
return ret;
fsleep(10000);
/*
* Make sure the DRP (Dynamic Reconfiguration Port) is locked. Not all
* designs really use it but if they don't we still get the lock bit
* set. So let's do it all the time so the code is generic.
*/
ret = regmap_read_poll_timeout(st->regmap, ADI_AXI_ADC_REG_DRP_STATUS,
__val, __val & ADI_AXI_ADC_DRP_LOCKED,
100, 1000);
if (ret)
return ret;
return regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN);
}
@@ -99,6 +114,7 @@ static void axi_adc_disable(struct iio_backend *back)
{
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
guard(mutex)(&st->lock);
regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
}
+279
View File
@@ -22,11 +22,19 @@
#include <linux/iio/machine.h>
#include <linux/mfd/axp20x.h>
#define AXP192_ADC_EN1_MASK GENMASK(7, 0)
#define AXP192_ADC_EN2_MASK (GENMASK(3, 0) | BIT(7))
#define AXP20X_ADC_EN1_MASK GENMASK(7, 0)
#define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7))
#define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0))
#define AXP192_GPIO30_IN_RANGE_GPIO0 BIT(0)
#define AXP192_GPIO30_IN_RANGE_GPIO1 BIT(1)
#define AXP192_GPIO30_IN_RANGE_GPIO2 BIT(2)
#define AXP192_GPIO30_IN_RANGE_GPIO3 BIT(3)
#define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0)
#define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1)
@@ -71,6 +79,25 @@ struct axp20x_adc_iio {
const struct axp_data *data;
};
enum axp192_adc_channel_v {
AXP192_ACIN_V = 0,
AXP192_VBUS_V,
AXP192_TS_IN,
AXP192_GPIO0_V,
AXP192_GPIO1_V,
AXP192_GPIO2_V,
AXP192_GPIO3_V,
AXP192_IPSOUT_V,
AXP192_BATT_V,
};
enum axp192_adc_channel_i {
AXP192_ACIN_I = 0,
AXP192_VBUS_I,
AXP192_BATT_CHRG_I,
AXP192_BATT_DISCHRG_I,
};
enum axp20x_adc_channel_v {
AXP20X_ACIN_V = 0,
AXP20X_VBUS_V,
@@ -158,6 +185,43 @@ static struct iio_map axp22x_maps[] = {
* The only exception is for the battery. batt_v will be in_voltage6_raw and
* charge current in_current6_raw and discharge current will be in_current7_raw.
*/
static const struct iio_chan_spec axp192_adc_channels[] = {
AXP20X_ADC_CHANNEL(AXP192_ACIN_V, "acin_v", IIO_VOLTAGE,
AXP20X_ACIN_V_ADC_H),
AXP20X_ADC_CHANNEL(AXP192_ACIN_I, "acin_i", IIO_CURRENT,
AXP20X_ACIN_I_ADC_H),
AXP20X_ADC_CHANNEL(AXP192_VBUS_V, "vbus_v", IIO_VOLTAGE,
AXP20X_VBUS_V_ADC_H),
AXP20X_ADC_CHANNEL(AXP192_VBUS_I, "vbus_i", IIO_CURRENT,
AXP20X_VBUS_I_ADC_H),
{
.type = IIO_TEMP,
.address = AXP20X_TEMP_ADC_H,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.datasheet_name = "pmic_temp",
},
AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
AXP20X_GPIO0_V_ADC_H),
AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO1_V, "gpio1_v", IIO_VOLTAGE,
AXP20X_GPIO1_V_ADC_H),
AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO2_V, "gpio2_v", IIO_VOLTAGE,
AXP192_GPIO2_V_ADC_H),
AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO3_V, "gpio3_v", IIO_VOLTAGE,
AXP192_GPIO3_V_ADC_H),
AXP20X_ADC_CHANNEL(AXP192_IPSOUT_V, "ipsout_v", IIO_VOLTAGE,
AXP20X_IPSOUT_V_HIGH_H),
AXP20X_ADC_CHANNEL(AXP192_BATT_V, "batt_v", IIO_VOLTAGE,
AXP20X_BATT_V_H),
AXP20X_ADC_CHANNEL(AXP192_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
AXP20X_BATT_CHRG_I_H),
AXP20X_ADC_CHANNEL(AXP192_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
AXP20X_BATT_DISCHRG_I_H),
AXP20X_ADC_CHANNEL(AXP192_TS_IN, "ts_v", IIO_VOLTAGE,
AXP20X_TS_IN_H),
};
static const struct iio_chan_spec axp20x_adc_channels[] = {
AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v", IIO_VOLTAGE,
AXP20X_ACIN_V_ADC_H),
@@ -231,6 +295,27 @@ static const struct iio_chan_spec axp813_adc_channels[] = {
AXP288_TS_ADC_H),
};
static int axp192_adc_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
int ret, size;
if (chan->type == IIO_CURRENT &&
(chan->channel == AXP192_BATT_CHRG_I ||
chan->channel == AXP192_BATT_DISCHRG_I))
size = 13;
else
size = 12;
ret = axp20x_read_variable_width(info->regmap, chan->address, size);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
}
static int axp20x_adc_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
@@ -283,6 +368,44 @@ static int axp813_adc_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
}
static int axp192_adc_scale_voltage(int channel, int *val, int *val2)
{
switch (channel) {
case AXP192_ACIN_V:
case AXP192_VBUS_V:
*val = 1;
*val2 = 700000;
return IIO_VAL_INT_PLUS_MICRO;
case AXP192_GPIO0_V:
case AXP192_GPIO1_V:
case AXP192_GPIO2_V:
case AXP192_GPIO3_V:
*val = 0;
*val2 = 500000;
return IIO_VAL_INT_PLUS_MICRO;
case AXP192_BATT_V:
*val = 1;
*val2 = 100000;
return IIO_VAL_INT_PLUS_MICRO;
case AXP192_IPSOUT_V:
*val = 1;
*val2 = 400000;
return IIO_VAL_INT_PLUS_MICRO;
case AXP192_TS_IN:
/* 0.8 mV per LSB */
*val = 0;
*val2 = 800000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
{
switch (channel) {
@@ -386,6 +509,29 @@ static int axp20x_adc_scale_current(int channel, int *val, int *val2)
}
}
static int axp192_adc_scale(struct iio_chan_spec const *chan, int *val,
int *val2)
{
switch (chan->type) {
case IIO_VOLTAGE:
return axp192_adc_scale_voltage(chan->channel, val, val2);
case IIO_CURRENT:
/*
* AXP192 current channels are identical to the AXP20x,
* therefore we can re-use the scaling function.
*/
return axp20x_adc_scale_current(chan->channel, val, val2);
case IIO_TEMP:
*val = 100;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int axp20x_adc_scale(struct iio_chan_spec const *chan, int *val,
int *val2)
{
@@ -445,6 +591,42 @@ static int axp813_adc_scale(struct iio_chan_spec const *chan, int *val,
}
}
static int axp192_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
int *val)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
unsigned int regval;
int ret;
ret = regmap_read(info->regmap, AXP192_GPIO30_IN_RANGE, &regval);
if (ret < 0)
return ret;
switch (channel) {
case AXP192_GPIO0_V:
regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO0, regval);
break;
case AXP192_GPIO1_V:
regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO1, regval);
break;
case AXP192_GPIO2_V:
regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO2, regval);
break;
case AXP192_GPIO3_V:
regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO3, regval);
break;
default:
return -EINVAL;
}
*val = regval ? 700000 : 0;
return IIO_VAL_INT;
}
static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
int *val)
{
@@ -473,6 +655,22 @@ static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
return IIO_VAL_INT;
}
static int axp192_adc_offset(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
switch (chan->type) {
case IIO_VOLTAGE:
return axp192_adc_offset_voltage(indio_dev, chan->channel, val);
case IIO_TEMP:
*val = -1447;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int axp20x_adc_offset(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
@@ -489,6 +687,25 @@ static int axp20x_adc_offset(struct iio_dev *indio_dev,
}
}
static int axp192_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
switch (mask) {
case IIO_CHAN_INFO_OFFSET:
return axp192_adc_offset(indio_dev, chan, val);
case IIO_CHAN_INFO_SCALE:
return axp192_adc_scale(chan, val, val2);
case IIO_CHAN_INFO_RAW:
return axp192_adc_raw(indio_dev, chan, val);
default:
return -EINVAL;
}
}
static int axp20x_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
@@ -549,6 +766,51 @@ static int axp813_read_raw(struct iio_dev *indio_dev,
}
}
static int axp192_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
unsigned int regmask, regval;
/*
* The AXP192 PMIC allows the user to choose between 0V and 0.7V offsets
* for (independently) GPIO0-3 when in ADC mode.
*/
if (mask != IIO_CHAN_INFO_OFFSET)
return -EINVAL;
if (val != 0 && val != 700000)
return -EINVAL;
switch (chan->channel) {
case AXP192_GPIO0_V:
regmask = AXP192_GPIO30_IN_RANGE_GPIO0;
regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO0, !!val);
break;
case AXP192_GPIO1_V:
regmask = AXP192_GPIO30_IN_RANGE_GPIO1;
regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO1, !!val);
break;
case AXP192_GPIO2_V:
regmask = AXP192_GPIO30_IN_RANGE_GPIO2;
regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO2, !!val);
break;
case AXP192_GPIO3_V:
regmask = AXP192_GPIO30_IN_RANGE_GPIO3;
regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO3, !!val);
break;
default:
return -EINVAL;
}
return regmap_update_bits(info->regmap, AXP192_GPIO30_IN_RANGE, regmask, regval);
}
static int axp20x_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
@@ -584,6 +846,11 @@ static int axp20x_write_raw(struct iio_dev *indio_dev,
return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, regmask, regval);
}
static const struct iio_info axp192_adc_iio_info = {
.read_raw = axp192_read_raw,
.write_raw = axp192_write_raw,
};
static const struct iio_info axp20x_adc_iio_info = {
.read_raw = axp20x_read_raw,
.write_raw = axp20x_write_raw,
@@ -629,6 +896,16 @@ struct axp_data {
struct iio_map *maps;
};
static const struct axp_data axp192_data = {
.iio_info = &axp192_adc_iio_info,
.num_channels = ARRAY_SIZE(axp192_adc_channels),
.channels = axp192_adc_channels,
.adc_en1_mask = AXP192_ADC_EN1_MASK,
.adc_en2_mask = AXP192_ADC_EN2_MASK,
.adc_rate = axp20x_adc_rate,
.maps = axp20x_maps,
};
static const struct axp_data axp20x_data = {
.iio_info = &axp20x_adc_iio_info,
.num_channels = ARRAY_SIZE(axp20x_adc_channels),
@@ -658,6 +935,7 @@ static const struct axp_data axp813_data = {
};
static const struct of_device_id axp20x_adc_of_match[] = {
{ .compatible = "x-powers,axp192-adc", .data = (void *)&axp192_data, },
{ .compatible = "x-powers,axp209-adc", .data = (void *)&axp20x_data, },
{ .compatible = "x-powers,axp221-adc", .data = (void *)&axp22x_data, },
{ .compatible = "x-powers,axp813-adc", .data = (void *)&axp813_data, },
@@ -666,6 +944,7 @@ static const struct of_device_id axp20x_adc_of_match[] = {
MODULE_DEVICE_TABLE(of, axp20x_adc_of_match);
static const struct platform_device_id axp20x_adc_id_match[] = {
{ .name = "axp192-adc", .driver_data = (kernel_ulong_t)&axp192_data, },
{ .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
{ .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
{ .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, },
+1
View File
@@ -920,4 +920,5 @@ static struct platform_driver ingenic_adc_driver = {
.probe = ingenic_adc_probe,
};
module_platform_driver(ingenic_adc_driver);
MODULE_DESCRIPTION("ADC driver for the Ingenic JZ47xx SoCs");
MODULE_LICENSE("GPL v2");
+1 -1
View File
@@ -124,7 +124,7 @@ static int ltc2485_probe(struct i2c_client *client)
}
static const struct i2c_device_id ltc2485_id[] = {
{ "ltc2485", 0 },
{ "ltc2485" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc2485_id);
+1 -4
View File
@@ -116,10 +116,7 @@ static int max11205_probe(struct spi_device *spi)
ad_sd_init(&st->sd, indio_dev, spi, &max11205_sigma_delta_info);
st->chip_info = device_get_match_data(&spi->dev);
if (!st->chip_info)
st->chip_info =
(const struct max11205_chip_info *)spi_get_device_id(spi)->driver_data;
st->chip_info = spi_get_device_match_data(spi);
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
-6
View File
@@ -1114,7 +1114,6 @@ static int mcp3564_config(struct iio_dev *indio_dev)
{
struct mcp3564_state *adc = iio_priv(indio_dev);
struct device *dev = &adc->spi->dev;
const struct spi_device_id *dev_id;
u8 tmp_reg;
u16 tmp_u16;
enum mcp3564_ids ids;
@@ -1212,11 +1211,6 @@ static int mcp3564_config(struct iio_dev *indio_dev)
* try using fallback compatible in device tree to deal with some newer part number.
*/
adc->chip_info = spi_get_device_match_data(adc->spi);
if (!adc->chip_info) {
dev_id = spi_get_device_id(adc->spi);
adc->chip_info = (const struct mcp3564_chip_info *)dev_id->driver_data;
}
adc->have_vref = adc->chip_info->have_vref;
} else {
adc->chip_info = &mcp3564_chip_infos_tbl[ids];
+1 -1
View File
@@ -532,7 +532,7 @@ static int nau7802_probe(struct i2c_client *client)
}
static const struct i2c_device_id nau7802_i2c_id[] = {
{ "nau7802", 0 },
{ "nau7802" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id);
-5
View File
@@ -227,11 +227,6 @@ struct pac1934_features {
const char *name;
};
struct samp_rate_mapping {
u16 samp_rate;
u8 shift2value;
};
static const unsigned int samp_rate_map_tbl[] = {
[PAC1934_SAMP_1024SPS] = 1024,
[PAC1934_SAMP_256SPS] = 256,
+7 -11
View File
@@ -137,17 +137,13 @@ static int ti_adc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = ti_adc_read_measurement(data, chan, val);
iio_device_release_direct_mode(indio_dev);
if (ret)
return ret;
return IIO_VAL_INT;
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
ret = ti_adc_read_measurement(data, chan, val);
if (ret)
return ret;
return IIO_VAL_INT;
}
unreachable();
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(data->ref);
if (ret < 0)
+1 -3
View File
@@ -802,9 +802,7 @@ static int ads131e08_probe(struct spi_device *spi)
unsigned long adc_clk_ns;
int ret;
info = device_get_match_data(&spi->dev);
if (!info)
info = (void *)spi_get_device_id(spi)->driver_data;
info = spi_get_device_match_data(spi);
if (!info) {
dev_err(&spi->dev, "failed to get match data\n");
return -ENODEV;
+1 -1
View File
@@ -447,7 +447,7 @@ static int ads7924_probe(struct i2c_client *client)
}
static const struct i2c_device_id ads7924_id[] = {
{ "ads7924", 0 },
{ "ads7924" },
{}
};
MODULE_DEVICE_TABLE(i2c, ads7924_id);
+1 -6
View File
@@ -804,12 +804,7 @@ static int tsc2046_adc_probe(struct spi_device *spi)
return -EINVAL;
}
dcfg = device_get_match_data(dev);
if (!dcfg) {
const struct spi_device_id *id = spi_get_device_id(spi);
dcfg = (const struct tsc2046_adc_dcfg *)id->driver_data;
}
dcfg = spi_get_device_match_data(spi);
if (!dcfg)
return -EINVAL;
+1
View File
@@ -1430,5 +1430,6 @@ static struct platform_driver ams_driver = {
};
module_platform_driver(ams_driver);
MODULE_DESCRIPTION("Xilinx AMS driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Xilinx, Inc.");
+3 -10
View File
@@ -1365,16 +1365,9 @@ static int ad74413r_probe(struct spi_device *spi)
st->spi = spi;
st->dev = &spi->dev;
st->chip_info = device_get_match_data(&spi->dev);
if (!st->chip_info) {
const struct spi_device_id *id = spi_get_device_id(spi);
if (id)
st->chip_info =
(struct ad74413r_chip_info *)id->driver_data;
if (!st->chip_info)
return -EINVAL;
}
st->chip_info = spi_get_device_match_data(spi);
if (!st->chip_info)
return -EINVAL;
mutex_init(&st->lock);
init_completion(&st->adc_data_completion);
+1
View File
@@ -287,4 +287,5 @@ int devm_iio_kfifo_buffer_setup_ext(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_iio_kfifo_buffer_setup_ext);
MODULE_DESCRIPTION("Industrial I/O buffering based on kfifo");
MODULE_LICENSE("GPL");
+20
View File
@@ -76,6 +76,26 @@ config CCS811
Say Y here to build I2C interface support for the AMS
CCS811 VOC (Volatile Organic Compounds) sensor
config ENS160
tristate "ScioSense ENS160 sensor driver"
depends on (I2C || SPI)
select REGMAP
select ENS160_I2C if I2C
select ENS160_SPI if SPI
help
Say yes here to build support for ScioSense ENS160 multi-gas sensor.
This driver can also be built as a module. If so, the module for I2C
would be called ens160_i2c and ens160_spi for SPI support.
config ENS160_I2C
tristate
select REGMAP_I2C
config ENS160_SPI
tristate
select REGMAP_SPI
config IAQCORE
tristate "AMS iAQ-Core VOC sensors"
depends on I2C
+3
View File
@@ -11,6 +11,9 @@ obj-$(CONFIG_BME680) += bme680_core.o
obj-$(CONFIG_BME680_I2C) += bme680_i2c.o
obj-$(CONFIG_BME680_SPI) += bme680_spi.o
obj-$(CONFIG_CCS811) += ccs811.o
obj-$(CONFIG_ENS160) += ens160_core.o
obj-$(CONFIG_ENS160_I2C) += ens160_i2c.o
obj-$(CONFIG_ENS160_SPI) += ens160_spi.o
obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
obj-$(CONFIG_PMS7003) += pms7003.o
obj-$(CONFIG_SCD30_CORE) += scd30_core.o
+2 -2
View File
@@ -24,7 +24,7 @@ struct ams_iaqcore_reading {
u8 status;
__be32 resistance;
__be16 voc_ppb;
} __attribute__((__packed__));
} __packed;
struct ams_iaqcore_data {
struct i2c_client *client;
@@ -163,7 +163,7 @@ static int ams_iaqcore_probe(struct i2c_client *client)
}
static const struct i2c_device_id ams_iaqcore_id[] = {
{ "ams-iaq-core", 0 },
{ "ams-iaq-core" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ams_iaqcore_id);
+2 -2
View File
@@ -36,8 +36,8 @@ static int bme680_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bme680_i2c_id[] = {
{"bme680", 0},
{},
{ "bme680" },
{}
};
MODULE_DEVICE_TABLE(i2c, bme680_i2c_id);
+1 -1
View File
@@ -551,7 +551,7 @@ static void ccs811_remove(struct i2c_client *client)
}
static const struct i2c_device_id ccs811_id[] = {
{"ccs811", 0},
{ "ccs811" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ccs811_id);
+10
View File
@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef ENS160_H_
#define ENS160_H_
int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name);
extern const struct dev_pm_ops ens160_pm_ops;
#endif
+367
View File
@@ -0,0 +1,367 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ScioSense ENS160 multi-gas sensor driver
*
* Copyright (c) 2024 Gustavo Silva <gustavograzs@gmail.com>
*
* Datasheet:
* https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
*/
#include <linux/bitfield.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "ens160.h"
#define ENS160_PART_ID 0x160
#define ENS160_BOOTING_TIME_MS 10U
#define ENS160_REG_PART_ID 0x00
#define ENS160_REG_OPMODE 0x10
#define ENS160_REG_CONFIG 0x11
#define ENS160_REG_CONFIG_INTEN BIT(0)
#define ENS160_REG_CONFIG_INTDAT BIT(1)
#define ENS160_REG_CONFIG_INT_CFG BIT(5)
#define ENS160_REG_MODE_DEEP_SLEEP 0x00
#define ENS160_REG_MODE_IDLE 0x01
#define ENS160_REG_MODE_STANDARD 0x02
#define ENS160_REG_MODE_RESET 0xF0
#define ENS160_REG_COMMAND 0x12
#define ENS160_REG_COMMAND_GET_APPVER 0x0E
#define ENS160_REG_COMMAND_CLRGPR 0xCC
#define ENS160_REG_TEMP_IN 0x13
#define ENS160_REG_RH_IN 0x15
#define ENS160_REG_DEVICE_STATUS 0x20
#define ENS160_REG_DATA_AQI 0x21
#define ENS160_REG_DATA_TVOC 0x22
#define ENS160_REG_DATA_ECO2 0x24
#define ENS160_REG_DATA_T 0x30
#define ENS160_REG_DATA_RH 0x32
#define ENS160_REG_GPR_READ4 0x4C
#define ENS160_STATUS_VALIDITY_FLAG GENMASK(3, 2)
#define ENS160_STATUS_NORMAL 0x00
struct ens160_data {
struct regmap *regmap;
/* Protect reads from the sensor */
struct mutex mutex;
struct {
__le16 chans[2];
s64 timestamp __aligned(8);
} scan __aligned(IIO_DMA_MINALIGN);
u8 fw_version[3];
__le16 buf;
};
static const struct iio_chan_spec ens160_channels[] = {
{
.type = IIO_CONCENTRATION,
.channel2 = IIO_MOD_VOC,
.modified = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.address = ENS160_REG_DATA_TVOC,
.scan_index = 0,
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_LE,
},
},
{
.type = IIO_CONCENTRATION,
.channel2 = IIO_MOD_CO2,
.modified = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.address = ENS160_REG_DATA_ECO2,
.scan_index = 1,
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_LE,
},
},
IIO_CHAN_SOFT_TIMESTAMP(2),
};
static int ens160_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct ens160_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
guard(mutex)(&data->mutex);
ret = regmap_bulk_read(data->regmap, chan->address,
&data->buf, sizeof(data->buf));
if (ret)
return ret;
*val = le16_to_cpu(data->buf);
return IIO_VAL_INT;
}
unreachable();
case IIO_CHAN_INFO_SCALE:
switch (chan->channel2) {
case IIO_MOD_CO2:
/* The sensor reads CO2 data as ppm */
*val = 0;
*val2 = 100;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_MOD_VOC:
/* The sensor reads VOC data as ppb */
*val = 0;
*val2 = 100;
return IIO_VAL_INT_PLUS_NANO;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int ens160_set_mode(struct ens160_data *data, u8 mode)
{
int ret;
ret = regmap_write(data->regmap, ENS160_REG_OPMODE, mode);
if (ret)
return ret;
msleep(ENS160_BOOTING_TIME_MS);
return 0;
}
static void ens160_set_idle(void *data)
{
ens160_set_mode(data, ENS160_REG_MODE_IDLE);
}
static int ens160_chip_init(struct ens160_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
unsigned int status;
int ret;
ret = ens160_set_mode(data, ENS160_REG_MODE_RESET);
if (ret)
return ret;
ret = regmap_bulk_read(data->regmap, ENS160_REG_PART_ID, &data->buf,
sizeof(data->buf));
if (ret)
return ret;
if (le16_to_cpu(data->buf) != ENS160_PART_ID)
return -ENODEV;
ret = ens160_set_mode(data, ENS160_REG_MODE_IDLE);
if (ret)
return ret;
ret = regmap_write(data->regmap, ENS160_REG_COMMAND,
ENS160_REG_COMMAND_CLRGPR);
if (ret)
return ret;
ret = regmap_write(data->regmap, ENS160_REG_COMMAND,
ENS160_REG_COMMAND_GET_APPVER);
if (ret)
return ret;
ret = regmap_bulk_read(data->regmap, ENS160_REG_GPR_READ4,
data->fw_version, sizeof(data->fw_version));
if (ret)
return ret;
dev_info(dev, "firmware version: %u.%u.%u\n", data->fw_version[2],
data->fw_version[1], data->fw_version[0]);
ret = ens160_set_mode(data, ENS160_REG_MODE_STANDARD);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, ens160_set_idle, data);
if (ret)
return ret;
ret = regmap_read(data->regmap, ENS160_REG_DEVICE_STATUS, &status);
if (ret)
return ret;
if (FIELD_GET(ENS160_STATUS_VALIDITY_FLAG, status)
!= ENS160_STATUS_NORMAL)
return -EINVAL;
return 0;
}
static const struct iio_info ens160_info = {
.read_raw = ens160_read_raw,
};
static int ens160_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ens160_data *data = iio_priv(indio_dev);
return ens160_set_mode(data, ENS160_REG_MODE_DEEP_SLEEP);
}
static int ens160_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ens160_data *data = iio_priv(indio_dev);
int ret;
ret = ens160_set_mode(data, ENS160_REG_MODE_IDLE);
if (ret)
return ret;
return ens160_set_mode(data, ENS160_REG_MODE_STANDARD);
}
EXPORT_NS_SIMPLE_DEV_PM_OPS(ens160_pm_ops, ens160_suspend, ens160_resume,
IIO_ENS160);
static irqreturn_t ens160_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ens160_data *data = iio_priv(indio_dev);
int ret;
guard(mutex)(&data->mutex);
ret = regmap_bulk_read(data->regmap, ENS160_REG_DATA_TVOC,
data->scan.chans, sizeof(data->scan.chans));
if (ret)
goto err;
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ens160_set_trigger_state(struct iio_trigger *trig, bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct ens160_data *data = iio_priv(indio_dev);
unsigned int int_bits = ENS160_REG_CONFIG_INTEN |
ENS160_REG_CONFIG_INTDAT |
ENS160_REG_CONFIG_INT_CFG;
if (state)
return regmap_set_bits(data->regmap, ENS160_REG_CONFIG,
int_bits);
else
return regmap_clear_bits(data->regmap, ENS160_REG_CONFIG,
int_bits);
}
static const struct iio_trigger_ops ens160_trigger_ops = {
.set_trigger_state = ens160_set_trigger_state,
.validate_device = iio_trigger_validate_own_device,
};
static int ens160_setup_trigger(struct iio_dev *indio_dev, int irq)
{
struct device *dev = indio_dev->dev.parent;
struct iio_trigger *trig;
int ret;
trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
iio_device_id(indio_dev));
if (!trig)
return dev_err_probe(dev, -ENOMEM,
"failed to allocate trigger\n");
trig->ops = &ens160_trigger_ops;
iio_trigger_set_drvdata(trig, indio_dev);
ret = devm_iio_trigger_register(dev, trig);
if (ret)
return ret;
indio_dev->trig = iio_trigger_get(trig);
ret = devm_request_threaded_irq(dev, irq,
iio_trigger_generic_data_rdy_poll,
NULL,
IRQF_ONESHOT,
indio_dev->name,
indio_dev->trig);
if (ret)
return dev_err_probe(dev, ret, "failed to request irq\n");
return 0;
}
int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name)
{
struct ens160_data *data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
data->regmap = regmap;
indio_dev->name = name;
indio_dev->info = &ens160_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ens160_channels;
indio_dev->num_channels = ARRAY_SIZE(ens160_channels);
if (irq > 0) {
ret = ens160_setup_trigger(indio_dev, irq);
if (ret)
return dev_err_probe(dev, ret,
"failed to setup trigger\n");
}
ret = ens160_chip_init(data);
if (ret)
return dev_err_probe(dev, ret, "chip initialization failed\n");
mutex_init(&data->mutex);
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
ens160_trigger_handler, NULL);
if (ret)
return ret;
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS(devm_ens160_core_probe, IIO_ENS160);
MODULE_AUTHOR("Gustavo Silva <gustavograzs@gmail.com>");
MODULE_DESCRIPTION("ScioSense ENS160 driver");
MODULE_LICENSE("GPL v2");
+62
View File
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ScioSense ENS160 multi-gas sensor I2C driver
*
* Copyright (c) 2024 Gustavo Silva <gustavograzs@gmail.com>
*
* 7-Bit I2C slave address is:
* - 0x52 if ADDR pin LOW
* - 0x53 if ADDR pin HIGH
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "ens160.h"
static const struct regmap_config ens160_regmap_i2c_conf = {
.reg_bits = 8,
.val_bits = 8,
};
static int ens160_i2c_probe(struct i2c_client *client)
{
struct regmap *regmap;
regmap = devm_regmap_init_i2c(client, &ens160_regmap_i2c_conf);
if (IS_ERR(regmap))
return dev_err_probe(&client->dev, PTR_ERR(regmap),
"Failed to register i2c regmap\n");
return devm_ens160_core_probe(&client->dev, regmap, client->irq,
"ens160");
}
static const struct i2c_device_id ens160_i2c_id[] = {
{ "ens160" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ens160_i2c_id);
static const struct of_device_id ens160_of_i2c_match[] = {
{ .compatible = "sciosense,ens160" },
{ }
};
MODULE_DEVICE_TABLE(of, ens160_of_i2c_match);
static struct i2c_driver ens160_i2c_driver = {
.driver = {
.name = "ens160",
.of_match_table = ens160_of_i2c_match,
.pm = pm_sleep_ptr(&ens160_pm_ops),
},
.probe = ens160_i2c_probe,
.id_table = ens160_i2c_id,
};
module_i2c_driver(ens160_i2c_driver);
MODULE_AUTHOR("Gustavo Silva <gustavograzs@gmail.com>");
MODULE_DESCRIPTION("ScioSense ENS160 I2C driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(IIO_ENS160);
+61
View File
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ScioSense ENS160 multi-gas sensor SPI driver
*
* Copyright (c) 2024 Gustavo Silva <gustavograzs@gmail.com>
*/
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "ens160.h"
#define ENS160_SPI_READ BIT(0)
static const struct regmap_config ens160_regmap_spi_conf = {
.reg_bits = 8,
.val_bits = 8,
.reg_shift = -1,
.read_flag_mask = ENS160_SPI_READ,
};
static int ens160_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
regmap = devm_regmap_init_spi(spi, &ens160_regmap_spi_conf);
if (IS_ERR(regmap))
return dev_err_probe(&spi->dev, PTR_ERR(regmap),
"Failed to register spi regmap\n");
return devm_ens160_core_probe(&spi->dev, regmap, spi->irq, "ens160");
}
static const struct of_device_id ens160_spi_of_match[] = {
{ .compatible = "sciosense,ens160" },
{ }
};
MODULE_DEVICE_TABLE(of, ens160_spi_of_match);
static const struct spi_device_id ens160_spi_id[] = {
{ "ens160" },
{ }
};
MODULE_DEVICE_TABLE(spi, ens160_spi_id);
static struct spi_driver ens160_spi_driver = {
.driver = {
.name = "ens160",
.of_match_table = ens160_spi_of_match,
.pm = pm_sleep_ptr(&ens160_pm_ops),
},
.probe = ens160_spi_probe,
.id_table = ens160_spi_id,
};
module_spi_driver(ens160_spi_driver);
MODULE_AUTHOR("Gustavo Silva <gustavograzs@gmail.com>");
MODULE_DESCRIPTION("ScioSense ENS160 SPI driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(IIO_ENS160);
+1
View File
@@ -149,6 +149,7 @@ config AD9739A
config ADI_AXI_DAC
tristate "Analog Devices Generic AXI DAC IP core driver"
depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA || COMPILE_TEST
select IIO_BUFFER
select IIO_BUFFER_DMAENGINE
select REGMAP_MMIO
+95 -45
View File
@@ -117,7 +117,7 @@
#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - ch) * 3)
/* Useful defines */
#define AD3552R_NUM_CH 2
#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
@@ -139,8 +139,10 @@ enum ad3552r_ch_vref_select {
AD3552R_EXTERNAL_VREF_PIN_INPUT
};
enum ad3542r_id {
enum ad3552r_id {
AD3541R_ID = 0x400b,
AD3542R_ID = 0x4009,
AD3551R_ID = 0x400a,
AD3552R_ID = 0x4008,
};
@@ -261,17 +263,26 @@ struct ad3552r_ch_data {
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;
};
struct ad3552r_desc {
const struct ad3552r_model_data *model_data;
/* Used to look the spi bus for atomic operations where needed */
struct mutex lock;
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_ldac;
struct spi_device *spi;
struct ad3552r_ch_data ch_data[AD3552R_NUM_CH];
struct iio_chan_spec channels[AD3552R_NUM_CH + 1];
struct ad3552r_ch_data ch_data[AD3552R_MAX_CH];
struct iio_chan_spec channels[AD3552R_MAX_CH + 1];
unsigned long enabled_ch;
unsigned int num_ch;
enum ad3542r_id chip_id;
};
static const u16 addr_mask_map[][2] = {
@@ -528,7 +539,7 @@ static int32_t ad3552r_trigger_hw_ldac(struct gpio_desc *ldac)
static int ad3552r_write_all_channels(struct ad3552r_desc *dac, u8 *data)
{
int err, len;
u8 addr, buff[AD3552R_NUM_CH * AD3552R_MAX_REG_SIZE + 1];
u8 addr, buff[AD3552R_MAX_CH * AD3552R_MAX_REG_SIZE + 1];
addr = AD3552R_REG_ADDR_CH_INPUT_24B(1);
/* CH1 */
@@ -586,7 +597,7 @@ static irqreturn_t ad3552r_trigger_handler(int irq, void *p)
struct iio_buffer *buf = indio_dev->buffer;
struct ad3552r_desc *dac = iio_priv(indio_dev);
/* Maximum size of a scan */
u8 buff[AD3552R_NUM_CH * AD3552R_MAX_REG_SIZE];
u8 buff[AD3552R_MAX_CH * AD3552R_MAX_REG_SIZE];
int err;
memset(buff, 0, sizeof(buff));
@@ -745,13 +756,8 @@ static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch)
} else {
/* Normal range */
idx = dac->ch_data[ch].range;
if (dac->chip_id == AD3542R_ID) {
v_min = ad3542r_ch_ranges[idx][0];
v_max = ad3542r_ch_ranges[idx][1];
} else {
v_min = ad3552r_ch_ranges[idx][0];
v_max = ad3552r_ch_ranges[idx][1];
}
v_min = dac->model_data->ranges_table[idx][0];
v_max = dac->model_data->ranges_table[idx][1];
}
/*
@@ -775,22 +781,14 @@ static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch)
dac->ch_data[ch].offset_dec = div_s64(tmp, span);
}
static int ad3552r_find_range(u16 id, s32 *vals)
static int ad3552r_find_range(const struct ad3552r_model_data *model_data,
s32 *vals)
{
int i, len;
const s32 (*ranges)[2];
int i;
if (id == AD3542R_ID) {
len = ARRAY_SIZE(ad3542r_ch_ranges);
ranges = ad3542r_ch_ranges;
} else {
len = ARRAY_SIZE(ad3552r_ch_ranges);
ranges = ad3552r_ch_ranges;
}
for (i = 0; i < len; i++)
if (vals[0] == ranges[i][0] * 1000 &&
vals[1] == ranges[i][1] * 1000)
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;
@@ -940,10 +938,10 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
if (err)
return dev_err_probe(dev, err,
"mandatory reg property missing\n");
if (ch >= AD3552R_NUM_CH)
if (ch >= dac->model_data->num_hw_channels)
return dev_err_probe(dev, -EINVAL,
"reg must be less than %d\n",
AD3552R_NUM_CH);
dac->model_data->num_hw_channels);
if (fwnode_property_present(child, "adi,output-range-microvolt")) {
err = fwnode_property_read_u32_array(child,
@@ -954,7 +952,7 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
return dev_err_probe(dev, err,
"adi,output-range-microvolt property could not be parsed\n");
err = ad3552r_find_range(dac->chip_id, vals);
err = ad3552r_find_range(dac->model_data, vals);
if (err < 0)
return dev_err_probe(dev, err,
"Invalid adi,output-range-microvolt value\n");
@@ -967,9 +965,10 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
return err;
dac->ch_data[ch].range = val;
} else if (dac->chip_id == AD3542R_ID) {
} else if (dac->model_data->requires_output_range) {
return dev_err_probe(dev, -EINVAL,
"adi,output-range-microvolt is required for ad3542r\n");
"adi,output-range-microvolt is required for %s\n",
dac->model_data->model_name);
} else {
err = ad3552r_configure_custom_gain(dac, child, ch);
if (err)
@@ -989,7 +988,8 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
}
/* Disable unused channels */
for_each_clear_bit(ch, &dac->enabled_ch, AD3552R_NUM_CH) {
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 (err)
@@ -1032,7 +1032,7 @@ static int ad3552r_init(struct ad3552r_desc *dac)
}
id |= val << 8;
if (id != dac->chip_id) {
if (id != dac->model_data->chip_id) {
dev_err(&dac->spi->dev, "Product id not matching\n");
return -ENODEV;
}
@@ -1042,7 +1042,6 @@ static int ad3552r_init(struct ad3552r_desc *dac)
static int ad3552r_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct ad3552r_desc *dac;
struct iio_dev *indio_dev;
int err;
@@ -1053,7 +1052,9 @@ static int ad3552r_probe(struct spi_device *spi)
dac = iio_priv(indio_dev);
dac->spi = spi;
dac->chip_id = id->driver_data;
dac->model_data = spi_get_device_match_data(spi);
if (!dac->model_data)
return -EINVAL;
mutex_init(&dac->lock);
@@ -1062,10 +1063,7 @@ static int ad3552r_probe(struct spi_device *spi)
return err;
/* Config triggered buffer device */
if (dac->chip_id == AD3552R_ID)
indio_dev->name = "ad3552r";
else
indio_dev->name = "ad3542r";
indio_dev->name = dac->model_data->model_name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ad3552r_iio_info;
indio_dev->num_channels = dac->num_ch;
@@ -1083,16 +1081,68 @@ static int ad3552r_probe(struct spi_device *spi)
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct ad3552r_model_data ad3541r_model_data = {
.model_name = "ad3541r",
.chip_id = AD3541R_ID,
.num_hw_channels = 1,
.ranges_table = ad3542r_ch_ranges,
.num_ranges = ARRAY_SIZE(ad3542r_ch_ranges),
.requires_output_range = true,
};
static const struct ad3552r_model_data ad3542r_model_data = {
.model_name = "ad3542r",
.chip_id = AD3542R_ID,
.num_hw_channels = 2,
.ranges_table = ad3542r_ch_ranges,
.num_ranges = ARRAY_SIZE(ad3542r_ch_ranges),
.requires_output_range = true,
};
static const struct ad3552r_model_data ad3551r_model_data = {
.model_name = "ad3551r",
.chip_id = AD3551R_ID,
.num_hw_channels = 1,
.ranges_table = ad3552r_ch_ranges,
.num_ranges = ARRAY_SIZE(ad3552r_ch_ranges),
.requires_output_range = false,
};
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),
.requires_output_range = false,
};
static const struct spi_device_id ad3552r_id[] = {
{ "ad3542r", AD3542R_ID },
{ "ad3552r", AD3552R_ID },
{
.name = "ad3541r",
.driver_data = (kernel_ulong_t)&ad3541r_model_data
},
{
.name = "ad3542r",
.driver_data = (kernel_ulong_t)&ad3542r_model_data
},
{
.name = "ad3551r",
.driver_data = (kernel_ulong_t)&ad3551r_model_data
},
{
.name = "ad3552r",
.driver_data = (kernel_ulong_t)&ad3552r_model_data
},
{ }
};
MODULE_DEVICE_TABLE(spi, ad3552r_id);
static const struct of_device_id ad3552r_of_match[] = {
{ .compatible = "adi,ad3542r"},
{ .compatible = "adi,ad3552r"},
{ .compatible = "adi,ad3541r", .data = &ad3541r_model_data },
{ .compatible = "adi,ad3542r", .data = &ad3542r_model_data },
{ .compatible = "adi,ad3551r", .data = &ad3551r_model_data },
{ .compatible = "adi,ad3552r", .data = &ad3552r_model_data },
{ }
};
MODULE_DEVICE_TABLE(of, ad3552r_of_match);
+3 -8
View File
@@ -132,7 +132,6 @@ static const struct regmap_config max5522_regmap_config = {
static int max5522_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct iio_dev *indio_dev;
struct max5522_state *state;
int ret;
@@ -144,13 +143,9 @@ static int max5522_spi_probe(struct spi_device *spi)
}
state = iio_priv(indio_dev);
state->chip_info = device_get_match_data(&spi->dev);
if (!state->chip_info) {
state->chip_info =
(struct max5522_chip_info *)(id->driver_data);
if (!state->chip_info)
return -EINVAL;
}
state->chip_info = spi_get_device_match_data(spi);
if (!state->chip_info)
return -EINVAL;
state->vrefin_reg = devm_regulator_get(&spi->dev, "vrefin");
if (IS_ERR(state->vrefin_reg))
+1 -1
View File
@@ -591,7 +591,7 @@ static int mcp4728_probe(struct i2c_client *client)
}
static const struct i2c_device_id mcp4728_id[] = {
{ "mcp4728", 0 },
{ "mcp4728" },
{}
};
MODULE_DEVICE_TABLE(i2c, mcp4728_id);
-1
View File
@@ -9,7 +9,6 @@
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/iio/iio.h>
+3 -3
View File
@@ -47,9 +47,9 @@ static const struct acpi_device_id bmg160_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match);
static const struct i2c_device_id bmg160_i2c_id[] = {
{"bmg160", 0},
{"bmi055_gyro", 0},
{"bmi088_gyro", 0},
{ "bmg160" },
{ "bmi055_gyro" },
{ "bmi088_gyro" },
{}
};
+1 -1
View File
@@ -39,7 +39,7 @@ static void fxas21002c_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id fxas21002c_i2c_id[] = {
{ "fxas21002c", 0 },
{ "fxas21002c" },
{ }
};
MODULE_DEVICE_TABLE(i2c, fxas21002c_i2c_id);
+1 -1
View File
@@ -387,7 +387,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(itg3200_pm_ops, itg3200_suspend,
itg3200_resume);
static const struct i2c_device_id itg3200_id[] = {
{ "itg3200", 0 },
{ "itg3200" },
{ }
};
MODULE_DEVICE_TABLE(i2c, itg3200_id);
+1 -1
View File
@@ -582,7 +582,7 @@ static int afe4404_probe(struct i2c_client *client)
}
static const struct i2c_device_id afe4404_ids[] = {
{ "afe4404", 0 },
{ "afe4404" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, afe4404_ids);
+1 -1
View File
@@ -483,7 +483,7 @@ static void max30100_remove(struct i2c_client *client)
}
static const struct i2c_device_id max30100_id[] = {
{ "max30100", 0 },
{ "max30100" },
{}
};
MODULE_DEVICE_TABLE(i2c, max30100_id);
+1 -1
View File
@@ -253,7 +253,7 @@ static int am2315_probe(struct i2c_client *client)
}
static const struct i2c_device_id am2315_i2c_id[] = {
{"am2315", 0},
{ "am2315" },
{}
};
MODULE_DEVICE_TABLE(i2c, am2315_i2c_id);
+6 -6
View File
@@ -396,12 +396,12 @@ static int hdc100x_probe(struct i2c_client *client)
}
static const struct i2c_device_id hdc100x_id[] = {
{ "hdc100x", 0 },
{ "hdc1000", 0 },
{ "hdc1008", 0 },
{ "hdc1010", 0 },
{ "hdc1050", 0 },
{ "hdc1080", 0 },
{ "hdc100x" },
{ "hdc1000" },
{ "hdc1008" },
{ "hdc1010" },
{ "hdc1050" },
{ "hdc1080" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hdc100x_id);
+2 -2
View File
@@ -163,8 +163,8 @@ static int si7005_probe(struct i2c_client *client)
}
static const struct i2c_device_id si7005_id[] = {
{ "si7005", 0 },
{ "th02", 0 },
{ "si7005" },
{ "th02" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si7005_id);
+135 -6
View File
@@ -23,6 +23,7 @@
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/stat.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -33,17 +34,38 @@
#define SI7020CMD_TEMP_HOLD 0xE3
/* Software Reset */
#define SI7020CMD_RESET 0xFE
#define SI7020CMD_USR_WRITE 0xE6
/* "Heater Enabled" bit in the User Register */
#define SI7020_USR_HEATER_EN BIT(2)
#define SI7020CMD_HEATER_WRITE 0x51
/* Heater current configuration bits */
#define SI7020_HEATER_VAL GENMASK(3, 0)
struct si7020_data {
struct i2c_client *client;
/* Lock for cached register values */
struct mutex lock;
u8 user_reg;
u8 heater_reg;
};
static const int si7020_heater_vals[] = { 0, 1, 0xF };
static int si7020_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct i2c_client **client = iio_priv(indio_dev);
struct si7020_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = i2c_smbus_read_word_swapped(*client,
if (chan->type == IIO_CURRENT) {
*val = data->heater_reg;
return IIO_VAL_INT;
}
ret = i2c_smbus_read_word_swapped(data->client,
chan->type == IIO_TEMP ?
SI7020CMD_TEMP_HOLD :
SI7020CMD_RH_HOLD);
@@ -96,17 +118,118 @@ static const struct iio_chan_spec si7020_channels[] = {
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
},
{
.type = IIO_CURRENT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
.extend_name = "heater",
}
};
static int si7020_update_reg(struct si7020_data *data,
u8 *reg, u8 cmd, u8 mask, u8 val)
{
u8 new = (*reg & ~mask) | val;
int ret;
ret = i2c_smbus_write_byte_data(data->client, cmd, new);
if (ret)
return ret;
*reg = new;
return 0;
}
static int si7020_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct si7020_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->type != IIO_CURRENT || val2 != 0 ||
val < si7020_heater_vals[0] || val > si7020_heater_vals[2])
return -EINVAL;
scoped_guard(mutex, &data->lock)
ret = si7020_update_reg(data, &data->heater_reg,
SI7020CMD_HEATER_WRITE, SI7020_HEATER_VAL, val);
return ret;
default:
return -EINVAL;
}
}
static int si7020_read_available(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals,
int *type, int *length, long mask)
{
if (mask != IIO_CHAN_INFO_RAW || chan->type != IIO_CURRENT)
return -EINVAL;
*vals = si7020_heater_vals;
*type = IIO_VAL_INT;
return IIO_AVAIL_RANGE;
}
static ssize_t si7020_show_heater_en(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct si7020_data *data = iio_priv(indio_dev);
return sysfs_emit(buf, "%d\n", !!(data->user_reg & SI7020_USR_HEATER_EN));
}
static ssize_t si7020_store_heater_en(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct si7020_data *data = iio_priv(indio_dev);
int ret;
bool val;
ret = kstrtobool(buf, &val);
if (ret)
return ret;
scoped_guard(mutex, &data->lock)
ret = si7020_update_reg(data, &data->user_reg, SI7020CMD_USR_WRITE,
SI7020_USR_HEATER_EN, val ? SI7020_USR_HEATER_EN : 0);
return ret < 0 ? ret : len;
}
static IIO_DEVICE_ATTR(heater_enable, 0644,
si7020_show_heater_en, si7020_store_heater_en, 0);
static struct attribute *si7020_attributes[] = {
&iio_dev_attr_heater_enable.dev_attr.attr,
NULL
};
static const struct attribute_group si7020_attribute_group = {
.attrs = si7020_attributes,
};
static const struct iio_info si7020_info = {
.read_raw = si7020_read_raw,
.write_raw = si7020_write_raw,
.read_avail = si7020_read_available,
.attrs = &si7020_attribute_group,
};
static int si7020_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct i2c_client **data;
struct si7020_data *data;
int ret;
if (!i2c_check_functionality(client->adapter,
@@ -126,7 +249,9 @@ static int si7020_probe(struct i2c_client *client)
return -ENOMEM;
data = iio_priv(indio_dev);
*data = client;
i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->lock);
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -134,12 +259,16 @@ static int si7020_probe(struct i2c_client *client)
indio_dev->channels = si7020_channels;
indio_dev->num_channels = ARRAY_SIZE(si7020_channels);
/* All the "reserved" bits in the User Register are 1s by default */
data->user_reg = 0x3A;
data->heater_reg = 0x0;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id si7020_id[] = {
{ "si7020", 0 },
{ "th06", 0 },
{ "si7020" },
{ "th06" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si7020_id);
+2 -2
View File
@@ -36,8 +36,8 @@ config ADIS16475
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for Analog Devices ADIS16470, ADIS16475,
ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16505, ADIS16507 inertial
sensors.
ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16501, ADIS16505,
ADIS16507 inertial sensors.
To compile this driver as a module, choose M here: the module will be
called adis16475.
File diff suppressed because it is too large Load Diff
+343 -50
View File
@@ -104,11 +104,10 @@
*/
#define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10)
#define ADIS16495_REG_BURST_CMD ADIS16480_REG(0x00, 0x7C)
#define ADIS16495_BURST_ID 0xA5A5
#define ADIS16495_GYRO_ACCEL_BURST_ID 0xA5A5
#define ADIS16545_DELTA_ANG_VEL_BURST_ID 0xC3C3
/* total number of segments in burst */
#define ADIS16495_BURST_MAX_DATA 20
/* spi max speed in burst mode */
#define ADIS16495_BURST_MAX_SPEED 6000000
#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20)
@@ -134,6 +133,10 @@
#define ADIS16480_SYNC_MODE_MSK BIT(8)
#define ADIS16480_SYNC_MODE(x) FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x)
#define ADIS16545_BURST_DATA_SEL_0_CHN_MASK GENMASK(5, 0)
#define ADIS16545_BURST_DATA_SEL_1_CHN_MASK GENMASK(16, 11)
#define ADIS16545_BURST_DATA_SEL_MASK BIT(8)
struct adis16480_chip_info {
unsigned int num_channels;
const struct iio_chan_spec *channels;
@@ -142,11 +145,14 @@ struct adis16480_chip_info {
unsigned int accel_max_val;
unsigned int accel_max_scale;
unsigned int temp_scale;
unsigned int deltang_max_val;
unsigned int deltvel_max_val;
unsigned int int_clk;
unsigned int max_dec_rate;
const unsigned int *filter_freqs;
bool has_pps_clk_mode;
bool has_sleep_cnt;
bool has_burst_delta_data;
const struct adis_data adis_data;
};
@@ -170,6 +176,7 @@ struct adis16480 {
struct clk *ext_clk;
enum adis16480_clock_mode clk_mode;
unsigned int clk_freq;
u16 burst_id;
/* Alignment needed for the timestamp */
__be16 data[ADIS16495_BURST_MAX_DATA] __aligned(8);
};
@@ -447,6 +454,12 @@ enum {
ADIS16480_SCAN_MAGN_Z,
ADIS16480_SCAN_BARO,
ADIS16480_SCAN_TEMP,
ADIS16480_SCAN_DELTANG_X,
ADIS16480_SCAN_DELTANG_Y,
ADIS16480_SCAN_DELTANG_Z,
ADIS16480_SCAN_DELTVEL_X,
ADIS16480_SCAN_DELTVEL_Y,
ADIS16480_SCAN_DELTVEL_Z,
};
static const unsigned int adis16480_calibbias_regs[] = {
@@ -690,6 +703,14 @@ static int adis16480_read_raw(struct iio_dev *indio_dev,
*val = 131; /* 1310mbar = 131 kPa */
*val2 = 32767 << 16;
return IIO_VAL_FRACTIONAL;
case IIO_DELTA_ANGL:
*val = st->chip_info->deltang_max_val;
*val2 = 31;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_DELTA_VELOCITY:
*val = st->chip_info->deltvel_max_val;
*val2 = 31;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
@@ -763,6 +784,24 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
BIT(IIO_CHAN_INFO_CALIBSCALE), \
32)
#define ADIS16480_DELTANG_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _DELTAANG_OUT, ADIS16480_SCAN_DELTANG_ ## _mod, \
0, 32)
#define ADIS16480_DELTANG_CHANNEL_NO_SCAN(_mod) \
ADIS16480_MOD_CHANNEL(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _DELTAANG_OUT, -1, 0, 32)
#define ADIS16480_DELTVEL_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _DELTAVEL_OUT, ADIS16480_SCAN_DELTVEL_ ## _mod, \
0, 32)
#define ADIS16480_DELTVEL_CHANNEL_NO_SCAN(_mod) \
ADIS16480_MOD_CHANNEL(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _DELTAVEL_OUT, -1, 0, 32)
#define ADIS16480_MAGN_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \
@@ -818,7 +857,13 @@ static const struct iio_chan_spec adis16480_channels[] = {
ADIS16480_MAGN_CHANNEL(Z),
ADIS16480_PRESSURE_CHANNEL(),
ADIS16480_TEMP_CHANNEL(),
IIO_CHAN_SOFT_TIMESTAMP(11)
IIO_CHAN_SOFT_TIMESTAMP(11),
ADIS16480_DELTANG_CHANNEL_NO_SCAN(X),
ADIS16480_DELTANG_CHANNEL_NO_SCAN(Y),
ADIS16480_DELTANG_CHANNEL_NO_SCAN(Z),
ADIS16480_DELTVEL_CHANNEL_NO_SCAN(X),
ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Y),
ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z),
};
static const struct iio_chan_spec adis16485_channels[] = {
@@ -829,7 +874,30 @@ static const struct iio_chan_spec adis16485_channels[] = {
ADIS16480_ACCEL_CHANNEL(Y),
ADIS16480_ACCEL_CHANNEL(Z),
ADIS16480_TEMP_CHANNEL(),
IIO_CHAN_SOFT_TIMESTAMP(7)
IIO_CHAN_SOFT_TIMESTAMP(7),
ADIS16480_DELTANG_CHANNEL_NO_SCAN(X),
ADIS16480_DELTANG_CHANNEL_NO_SCAN(Y),
ADIS16480_DELTANG_CHANNEL_NO_SCAN(Z),
ADIS16480_DELTVEL_CHANNEL_NO_SCAN(X),
ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Y),
ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z),
};
static const struct iio_chan_spec adis16545_channels[] = {
ADIS16480_GYRO_CHANNEL(X),
ADIS16480_GYRO_CHANNEL(Y),
ADIS16480_GYRO_CHANNEL(Z),
ADIS16480_ACCEL_CHANNEL(X),
ADIS16480_ACCEL_CHANNEL(Y),
ADIS16480_ACCEL_CHANNEL(Z),
ADIS16480_TEMP_CHANNEL(),
ADIS16480_DELTANG_CHANNEL(X),
ADIS16480_DELTANG_CHANNEL(Y),
ADIS16480_DELTANG_CHANNEL(Z),
ADIS16480_DELTVEL_CHANNEL(X),
ADIS16480_DELTVEL_CHANNEL(Y),
ADIS16480_DELTVEL_CHANNEL(Z),
IIO_CHAN_SOFT_TIMESTAMP(17),
};
enum adis16480_variant {
@@ -844,6 +912,12 @@ enum adis16480_variant {
ADIS16497_1,
ADIS16497_2,
ADIS16497_3,
ADIS16545_1,
ADIS16545_2,
ADIS16545_3,
ADIS16547_1,
ADIS16547_2,
ADIS16547_3
};
#define ADIS16480_DIAG_STAT_XGYRO_FAIL 0
@@ -872,33 +946,33 @@ static const char * const adis16480_status_error_msgs[] = {
static int adis16480_enable_irq(struct adis *adis, bool enable);
#define ADIS16480_DATA(_prod_id, _timeouts, _burst_len) \
{ \
.diag_stat_reg = ADIS16480_REG_DIAG_STS, \
.glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \
.prod_id_reg = ADIS16480_REG_PROD_ID, \
.prod_id = (_prod_id), \
.has_paging = true, \
.read_delay = 5, \
.write_delay = 5, \
.self_test_mask = BIT(1), \
.self_test_reg = ADIS16480_REG_GLOB_CMD, \
.status_error_msgs = adis16480_status_error_msgs, \
.status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | \
BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | \
BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | \
BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | \
BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | \
BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | \
BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | \
BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | \
BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | \
BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \
.enable_irq = adis16480_enable_irq, \
.timeouts = (_timeouts), \
.burst_reg_cmd = ADIS16495_REG_BURST_CMD, \
.burst_len = (_burst_len), \
.burst_max_speed_hz = ADIS16495_BURST_MAX_SPEED \
#define ADIS16480_DATA(_prod_id, _timeouts, _burst_len, _burst_max_speed) \
{ \
.diag_stat_reg = ADIS16480_REG_DIAG_STS, \
.glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \
.prod_id_reg = ADIS16480_REG_PROD_ID, \
.prod_id = (_prod_id), \
.has_paging = true, \
.read_delay = 5, \
.write_delay = 5, \
.self_test_mask = BIT(1), \
.self_test_reg = ADIS16480_REG_GLOB_CMD, \
.status_error_msgs = adis16480_status_error_msgs, \
.status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | \
BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | \
BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | \
BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | \
BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | \
BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | \
BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | \
BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | \
BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | \
BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \
.enable_irq = adis16480_enable_irq, \
.timeouts = (_timeouts), \
.burst_reg_cmd = ADIS16495_REG_BURST_CMD, \
.burst_len = (_burst_len), \
.burst_max_speed_hz = _burst_max_speed \
}
static const struct adis_timeout adis16485_timeouts = {
@@ -925,6 +999,12 @@ static const struct adis_timeout adis16495_1_timeouts = {
.self_test_ms = 20,
};
static const struct adis_timeout adis16545_timeouts = {
.reset_ms = 315,
.sw_reset_ms = 270,
.self_test_ms = 35,
};
static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16375] = {
.channels = adis16485_channels,
@@ -940,11 +1020,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(21973 << 16),
.accel_max_scale = 18,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(180),
.deltvel_max_val = 100,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
.adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0),
.adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0, 0),
},
[ADIS16480] = {
.channels = adis16480_channels,
@@ -954,11 +1036,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(12500 << 16),
.accel_max_scale = 10,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(720),
.deltvel_max_val = 200,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
.adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0),
.adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0, 0),
},
[ADIS16485] = {
.channels = adis16485_channels,
@@ -968,11 +1052,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
.accel_max_scale = 5,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(720),
.deltvel_max_val = 50,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
.adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0),
.adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0, 0),
},
[ADIS16488] = {
.channels = adis16480_channels,
@@ -982,11 +1068,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(22500 << 16),
.accel_max_scale = 18,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(720),
.deltvel_max_val = 200,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
.adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0),
.adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0, 0),
},
[ADIS16490] = {
.channels = adis16485_channels,
@@ -996,11 +1084,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(16000 << 16),
.accel_max_scale = 8,
.temp_scale = 14285, /* 14.285 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(720),
.deltvel_max_val = 200,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0),
.adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0, 0),
},
[ADIS16495_1] = {
.channels = adis16485_channels,
@@ -1010,13 +1100,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(360),
.deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
ADIS16495_BURST_MAX_DATA * 2),
ADIS16495_BURST_MAX_DATA * 2,
6000000),
},
[ADIS16495_2] = {
.channels = adis16485_channels,
@@ -1026,13 +1119,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(720),
.deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
ADIS16495_BURST_MAX_DATA * 2),
ADIS16495_BURST_MAX_DATA * 2,
6000000),
},
[ADIS16495_3] = {
.channels = adis16485_channels,
@@ -1042,13 +1138,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(2160),
.deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
ADIS16495_BURST_MAX_DATA * 2),
ADIS16495_BURST_MAX_DATA * 2,
6000000),
},
[ADIS16497_1] = {
.channels = adis16485_channels,
@@ -1058,13 +1157,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(360),
.deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
ADIS16495_BURST_MAX_DATA * 2),
ADIS16495_BURST_MAX_DATA * 2,
6000000),
},
[ADIS16497_2] = {
.channels = adis16485_channels,
@@ -1074,13 +1176,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(720),
.deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
ADIS16495_BURST_MAX_DATA * 2),
ADIS16495_BURST_MAX_DATA * 2,
6000000),
},
[ADIS16497_3] = {
.channels = adis16485_channels,
@@ -1090,13 +1195,136 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(2160),
.deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
ADIS16495_BURST_MAX_DATA * 2),
ADIS16495_BURST_MAX_DATA * 2,
6000000),
},
[ADIS16545_1] = {
.channels = adis16545_channels,
.num_channels = ARRAY_SIZE(adis16545_channels),
.gyro_max_val = 20000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(125),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 7000, /* 7 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(360),
.deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.has_burst_delta_data = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16545, &adis16545_timeouts,
ADIS16495_BURST_MAX_DATA * 2,
6500000),
},
[ADIS16545_2] = {
.channels = adis16545_channels,
.num_channels = ARRAY_SIZE(adis16545_channels),
.gyro_max_val = 18000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 7000, /* 7 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(720),
.deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.has_burst_delta_data = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16545, &adis16545_timeouts,
ADIS16495_BURST_MAX_DATA * 2,
6500000),
},
[ADIS16545_3] = {
.channels = adis16545_channels,
.num_channels = ARRAY_SIZE(adis16545_channels),
.gyro_max_val = 20000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 7000, /* 7 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(2160),
.deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.has_burst_delta_data = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16545, &adis16545_timeouts,
ADIS16495_BURST_MAX_DATA * 2,
6500000),
},
[ADIS16547_1] = {
.channels = adis16545_channels,
.num_channels = ARRAY_SIZE(adis16545_channels),
.gyro_max_val = 20000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(125),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 7000, /* 7 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(360),
.deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.has_burst_delta_data = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16547, &adis16545_timeouts,
ADIS16495_BURST_MAX_DATA * 2,
6500000),
},
[ADIS16547_2] = {
.channels = adis16545_channels,
.num_channels = ARRAY_SIZE(adis16545_channels),
.gyro_max_val = 18000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 7000, /* 7 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(720),
.deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.has_burst_delta_data = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16547, &adis16545_timeouts,
ADIS16495_BURST_MAX_DATA * 2,
6500000),
},
[ADIS16547_3] = {
.channels = adis16545_channels,
.num_channels = ARRAY_SIZE(adis16545_channels),
.gyro_max_val = 20000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 7000, /* 7 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(2160),
.deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.has_burst_delta_data = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16547, &adis16545_timeouts,
ADIS16495_BURST_MAX_DATA * 2,
6500000),
},
};
@@ -1122,7 +1350,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
struct adis16480 *st = iio_priv(indio_dev);
struct adis *adis = &st->adis;
struct device *dev = &adis->spi->dev;
int ret, bit, offset, i = 0;
int ret, bit, offset, i = 0, buff_offset = 0;
__be16 *buffer;
u32 crc;
bool valid;
@@ -1155,8 +1383,8 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
* 16-bit responses containing the BURST_ID depending on the sclk. If
* clk > 3.6MHz, then we will have two BURST_ID in a row. If clk < 3MHZ,
* we have only one. To manage that variation, we use the transition from the
* BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5. If
* we not find this variation in the first 4 segments, then the data should
* BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5/0xC3C3.
* If we not find this variation in the first 4 segments, then the data should
* not be valid.
*/
buffer = adis->buffer;
@@ -1164,7 +1392,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
u16 curr = be16_to_cpu(buffer[offset]);
u16 next = be16_to_cpu(buffer[offset + 1]);
if (curr == ADIS16495_BURST_ID && next != ADIS16495_BURST_ID) {
if (curr == st->burst_id && next != st->burst_id) {
offset++;
break;
}
@@ -1191,11 +1419,24 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
switch (bit) {
case ADIS16480_SCAN_TEMP:
st->data[i++] = buffer[offset + 1];
/*
* The temperature channel has 16-bit storage size.
* We need to perform the padding to have the buffer
* elements naturally aligned in case there are any
* 32-bit storage size channels enabled which are added
* in the buffer after the temprature data. In case
* there is no data being added after the temperature
* data, the padding is harmless.
*/
st->data[i++] = 0;
break;
case ADIS16480_SCAN_DELTANG_X ... ADIS16480_SCAN_DELTVEL_Z:
buff_offset = ADIS16480_SCAN_DELTANG_X;
fallthrough;
case ADIS16480_SCAN_GYRO_X ... ADIS16480_SCAN_ACCEL_Z:
/* The lower register data is sequenced first */
st->data[i++] = buffer[2 * bit + offset + 3];
st->data[i++] = buffer[2 * bit + offset + 2];
st->data[i++] = buffer[2 * (bit - buff_offset) + offset + 3];
st->data[i++] = buffer[2 * (bit - buff_offset) + offset + 2];
break;
}
}
@@ -1207,10 +1448,41 @@ irq_done:
return IRQ_HANDLED;
}
static const unsigned long adis16545_channel_masks[] = {
ADIS16545_BURST_DATA_SEL_0_CHN_MASK | BIT(ADIS16480_SCAN_TEMP) | BIT(17),
ADIS16545_BURST_DATA_SEL_1_CHN_MASK | BIT(ADIS16480_SCAN_TEMP) | BIT(17),
0,
};
static int adis16480_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
u16 en;
int ret;
struct adis16480 *st = iio_priv(indio_dev);
if (st->chip_info->has_burst_delta_data) {
if (*scan_mask & ADIS16545_BURST_DATA_SEL_0_CHN_MASK) {
en = FIELD_PREP(ADIS16545_BURST_DATA_SEL_MASK, 0);
st->burst_id = ADIS16495_GYRO_ACCEL_BURST_ID;
} else {
en = FIELD_PREP(ADIS16545_BURST_DATA_SEL_MASK, 1);
st->burst_id = ADIS16545_DELTA_ANG_VEL_BURST_ID;
}
ret = __adis_update_bits(&st->adis, ADIS16480_REG_CONFIG,
ADIS16545_BURST_DATA_SEL_MASK, en);
if (ret)
return ret;
}
return adis_update_scan_mode(indio_dev, scan_mask);
}
static const struct iio_info adis16480_info = {
.read_raw = &adis16480_read_raw,
.write_raw = &adis16480_write_raw,
.update_scan_mode = adis_update_scan_mode,
.update_scan_mode = &adis16480_update_scan_mode,
.debugfs_reg_access = adis_debugfs_reg_access,
};
@@ -1407,6 +1679,8 @@ static int adis16480_probe(struct spi_device *spi)
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
if (st->chip_info->has_burst_delta_data)
indio_dev->available_scan_masks = adis16545_channel_masks;
indio_dev->info = &adis16480_info;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1420,6 +1694,13 @@ static int adis16480_probe(struct spi_device *spi)
if (ret)
return ret;
/*
* By default, use burst id for gyroscope and accelerometer data.
* This is the only option for devices which do not offer delta angle
* and delta velocity burst readings.
*/
st->burst_id = ADIS16495_GYRO_ACCEL_BURST_ID;
if (st->chip_info->has_sleep_cnt) {
ret = devm_add_action_or_reset(dev, adis16480_stop, indio_dev);
if (ret)
@@ -1493,6 +1774,12 @@ static const struct spi_device_id adis16480_ids[] = {
{ "adis16497-1", ADIS16497_1 },
{ "adis16497-2", ADIS16497_2 },
{ "adis16497-3", ADIS16497_3 },
{ "adis16545-1", ADIS16545_1 },
{ "adis16545-2", ADIS16545_2 },
{ "adis16545-3", ADIS16545_3 },
{ "adis16547-1", ADIS16547_1 },
{ "adis16547-2", ADIS16547_2 },
{ "adis16547-3", ADIS16547_3 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16480_ids);
@@ -1509,6 +1796,12 @@ static const struct of_device_id adis16480_of_match[] = {
{ .compatible = "adi,adis16497-1" },
{ .compatible = "adi,adis16497-2" },
{ .compatible = "adi,adis16497-3" },
{ .compatible = "adi,adis16545-1" },
{ .compatible = "adi,adis16545-2" },
{ .compatible = "adi,adis16545-3" },
{ .compatible = "adi,adis16547-1" },
{ .compatible = "adi,adis16547-2" },
{ .compatible = "adi,adis16547-3" },
{ },
};
MODULE_DEVICE_TABLE(of, adis16480_of_match);
+18 -14
View File
@@ -175,31 +175,36 @@ static void adis_buffer_cleanup(void *arg)
}
/**
* devm_adis_setup_buffer_and_trigger() - Sets up buffer and trigger for
* the managed adis device
* devm_adis_setup_buffer_and_trigger_with_attrs() - Sets up buffer and trigger
* for the managed adis device with buffer attributes.
* @adis: The adis device
* @indio_dev: The IIO device
* @trigger_handler: Optional trigger handler, may be NULL.
* @trigger_handler: Trigger handler: should handle the buffer readings.
* @ops: Optional buffer setup functions, may be NULL.
* @buffer_attrs: Extra buffer attributes.
*
* Returns 0 on success, a negative error code otherwise.
*
* This function sets up the buffer and trigger for a adis devices. If
* 'trigger_handler' is NULL the default trigger handler will be used. The
* default trigger handler will simply read the registers assigned to the
* currently active channels.
* This function sets up the buffer (with buffer setup functions and extra
* buffer attributes) and trigger for a adis devices with buffer attributes.
*/
int
devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
irq_handler_t trigger_handler)
devm_adis_setup_buffer_and_trigger_with_attrs(struct adis *adis, struct iio_dev *indio_dev,
irq_handler_t trigger_handler,
const struct iio_buffer_setup_ops *ops,
const struct iio_dev_attr **buffer_attrs)
{
int ret;
if (!trigger_handler)
trigger_handler = adis_trigger_handler;
ret = devm_iio_triggered_buffer_setup(&adis->spi->dev, indio_dev,
&iio_pollfunc_store_time,
trigger_handler, NULL);
ret = devm_iio_triggered_buffer_setup_ext(&adis->spi->dev, indio_dev,
&iio_pollfunc_store_time,
trigger_handler,
IIO_BUFFER_DIRECTION_IN,
ops,
buffer_attrs);
if (ret)
return ret;
@@ -212,5 +217,4 @@ devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
return devm_add_action_or_reset(&adis->spi->dev, adis_buffer_cleanup,
adis);
}
EXPORT_SYMBOL_NS_GPL(devm_adis_setup_buffer_and_trigger, IIO_ADISLIB);
EXPORT_SYMBOL_NS_GPL(devm_adis_setup_buffer_and_trigger_with_attrs, IIO_ADISLIB);
+26 -11
View File
@@ -34,17 +34,24 @@ static int adis_validate_irq_flag(struct adis *adis)
if (adis->data->unmasked_drdy)
adis->irq_flag |= IRQF_NO_AUTOEN;
/*
* Typically this devices have data ready either on the rising edge or
* on the falling edge of the data ready pin. This checks enforces that
* one of those is set in the drivers... It defaults to
* IRQF_TRIGGER_RISING for backward compatibility with devices that
* don't support changing the pin polarity.
* Typically adis devices without FIFO have data ready either on the
* rising edge or on the falling edge of the data ready pin.
* IMU devices with FIFO support have the watermark pin level driven
* either high or low when the FIFO is filled with the desired number
* of samples.
* It defaults to IRQF_TRIGGER_RISING for backward compatibility with
* devices that don't support changing the pin polarity.
*/
if (direction == IRQF_TRIGGER_NONE) {
adis->irq_flag |= IRQF_TRIGGER_RISING;
return 0;
} else if (direction != IRQF_TRIGGER_RISING &&
direction != IRQF_TRIGGER_FALLING) {
direction != IRQF_TRIGGER_FALLING && !adis->data->has_fifo) {
dev_err(&adis->spi->dev, "Invalid IRQ mask: %08lx\n",
adis->irq_flag);
return -EINVAL;
} else if (direction != IRQF_TRIGGER_HIGH &&
direction != IRQF_TRIGGER_LOW && adis->data->has_fifo) {
dev_err(&adis->spi->dev, "Invalid IRQ mask: %08lx\n",
adis->irq_flag);
return -EINVAL;
@@ -77,11 +84,19 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
if (ret)
return ret;
ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
&iio_trigger_generic_data_rdy_poll,
adis->irq_flag,
indio_dev->name,
adis->trig);
if (adis->data->has_fifo)
ret = devm_request_threaded_irq(&adis->spi->dev, adis->spi->irq,
NULL,
&iio_trigger_generic_data_rdy_poll,
adis->irq_flag | IRQF_ONESHOT,
indio_dev->name,
adis->trig);
else
ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
&iio_trigger_generic_data_rdy_poll,
adis->irq_flag,
indio_dev->name,
adis->trig);
if (ret)
return ret;
+20 -6
View File
@@ -26,6 +26,7 @@
#include "bmi160.h"
#define BMI160_REG_CHIP_ID 0x00
#define BMI120_CHIP_ID_VAL 0xD3
#define BMI160_CHIP_ID_VAL 0xD1
#define BMI160_REG_PMU_STATUS 0x03
@@ -112,6 +113,11 @@
.ext_info = bmi160_ext_info, \
}
static const u8 bmi_chip_ids[] = {
BMI120_CHIP_ID_VAL,
BMI160_CHIP_ID_VAL,
};
/* scan indexes follow DATA register order */
enum bmi160_scan_axis {
BMI160_SCAN_EXT_MAGN_X = 0,
@@ -704,6 +710,16 @@ static int bmi160_setup_irq(struct iio_dev *indio_dev, int irq,
return bmi160_probe_trigger(indio_dev, irq, irq_type);
}
static int bmi160_check_chip_id(const u8 chip_id)
{
for (int i = 0; i < ARRAY_SIZE(bmi_chip_ids); i++) {
if (chip_id == bmi_chip_ids[i])
return 0;
}
return -ENODEV;
}
static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
{
int ret;
@@ -737,12 +753,10 @@ static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
dev_err(dev, "Error reading chip id\n");
goto disable_regulator;
}
if (val != BMI160_CHIP_ID_VAL) {
dev_err(dev, "Wrong chip id, got %x expected %x\n",
val, BMI160_CHIP_ID_VAL);
ret = -ENODEV;
goto disable_regulator;
}
ret = bmi160_check_chip_id(val);
if (ret)
dev_warn(dev, "Chip id not found: %x\n", val);
ret = bmi160_set_mode(data, BMI160_ACCEL, true);
if (ret)
+4 -1
View File
@@ -37,7 +37,8 @@ static int bmi160_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bmi160_i2c_id[] = {
{"bmi160", 0},
{ "bmi120" },
{ "bmi160" },
{}
};
MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id);
@@ -52,12 +53,14 @@ static const struct acpi_device_id bmi160_acpi_match[] = {
* the affected devices are from 2021/2022.
*/
{"10EC5280", 0},
{"BMI0120", 0},
{"BMI0160", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
static const struct of_device_id bmi160_of_match[] = {
{ .compatible = "bosch,bmi120" },
{ .compatible = "bosch,bmi160" },
{ },
};
+3
View File
@@ -34,18 +34,21 @@ static int bmi160_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id bmi160_spi_id[] = {
{"bmi120", 0},
{"bmi160", 0},
{}
};
MODULE_DEVICE_TABLE(spi, bmi160_spi_id);
static const struct acpi_device_id bmi160_acpi_match[] = {
{"BMI0120", 0},
{"BMI0160", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
static const struct of_device_id bmi160_of_match[] = {
{ .compatible = "bosch,bmi120" },
{ .compatible = "bosch,bmi160" },
{ },
};
+5 -3
View File
@@ -2083,9 +2083,11 @@ int bmi323_core_probe(struct device *dev)
if (ret)
return -EINVAL;
ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
if (!iio_read_acpi_mount_matrix(dev, &data->orientation, "ROTM")) {
ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
}
indio_dev->name = "bmi323-imu";
indio_dev->info = &bmi323_info;
+1 -1
View File
@@ -30,7 +30,7 @@ static int bno055_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bno055_i2c_id[] = {
{"bno055", 0},
{ "bno055" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bno055_i2c_id);
+1 -1
View File
@@ -36,7 +36,7 @@ static int fxos8700_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id fxos8700_i2c_id[] = {
{"fxos8700", 0},
{ "fxos8700" },
{ }
};
MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id);
@@ -177,11 +177,15 @@ struct inv_icm42600_state {
* struct inv_icm42600_sensor_state - sensor state variables
* @scales: table of scales.
* @scales_len: length (nb of items) of the scales table.
* @power_mode: sensor requested power mode (for common frequencies)
* @filter: sensor filter.
* @ts: timestamp module states.
*/
struct inv_icm42600_sensor_state {
const int *scales;
size_t scales_len;
enum inv_icm42600_sensor_mode power_mode;
enum inv_icm42600_filter filter;
struct inv_sensors_timestamp ts;
};
@@ -55,8 +55,108 @@ enum inv_icm42600_accel_scan {
INV_ICM42600_ACCEL_SCAN_TIMESTAMP,
};
static const char * const inv_icm42600_accel_power_mode_items[] = {
"low-noise",
"low-power",
};
static const int inv_icm42600_accel_power_mode_values[] = {
INV_ICM42600_SENSOR_MODE_LOW_NOISE,
INV_ICM42600_SENSOR_MODE_LOW_POWER,
};
static const int inv_icm42600_accel_filter_values[] = {
INV_ICM42600_FILTER_BW_ODR_DIV_2,
INV_ICM42600_FILTER_AVG_16X,
};
static int inv_icm42600_accel_power_mode_set(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
unsigned int idx)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
int power_mode, filter;
if (chan->type != IIO_ACCEL)
return -EINVAL;
if (idx >= ARRAY_SIZE(inv_icm42600_accel_power_mode_values))
return -EINVAL;
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
power_mode = inv_icm42600_accel_power_mode_values[idx];
filter = inv_icm42600_accel_filter_values[idx];
guard(mutex)(&st->lock);
/* prevent change if power mode is not supported by the ODR */
switch (power_mode) {
case INV_ICM42600_SENSOR_MODE_LOW_NOISE:
if (st->conf.accel.odr >= INV_ICM42600_ODR_6_25HZ_LP &&
st->conf.accel.odr <= INV_ICM42600_ODR_1_5625HZ_LP)
return -EPERM;
break;
case INV_ICM42600_SENSOR_MODE_LOW_POWER:
default:
if (st->conf.accel.odr <= INV_ICM42600_ODR_1KHZ_LN)
return -EPERM;
break;
}
accel_st->power_mode = power_mode;
accel_st->filter = filter;
return 0;
}
static int inv_icm42600_accel_power_mode_get(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
unsigned int idx;
int power_mode;
if (chan->type != IIO_ACCEL)
return -EINVAL;
guard(mutex)(&st->lock);
/* if sensor is on, returns actual power mode and not configured one */
switch (st->conf.accel.mode) {
case INV_ICM42600_SENSOR_MODE_LOW_POWER:
case INV_ICM42600_SENSOR_MODE_LOW_NOISE:
power_mode = st->conf.accel.mode;
break;
default:
power_mode = accel_st->power_mode;
break;
}
for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_accel_power_mode_values); ++idx) {
if (power_mode == inv_icm42600_accel_power_mode_values[idx])
break;
}
if (idx >= ARRAY_SIZE(inv_icm42600_accel_power_mode_values))
return -EINVAL;
return idx;
}
static const struct iio_enum inv_icm42600_accel_power_mode_enum = {
.items = inv_icm42600_accel_power_mode_items,
.num_items = ARRAY_SIZE(inv_icm42600_accel_power_mode_items),
.set = inv_icm42600_accel_power_mode_set,
.get = inv_icm42600_accel_power_mode_get,
};
static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42600_get_mount_matrix),
IIO_ENUM_AVAILABLE("power_mode", IIO_SHARED_BY_TYPE,
&inv_icm42600_accel_power_mode_enum),
IIO_ENUM("power_mode", IIO_SHARED_BY_TYPE,
&inv_icm42600_accel_power_mode_enum),
{},
};
@@ -120,7 +220,8 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev,
if (*scan_mask & INV_ICM42600_SCAN_MASK_ACCEL_3AXIS) {
/* enable accel sensor */
conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
conf.mode = accel_st->power_mode;
conf.filter = accel_st->filter;
ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_accel);
if (ret)
goto out_unlock;
@@ -144,10 +245,12 @@ out_unlock:
return ret;
}
static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st,
static int inv_icm42600_accel_read_sensor(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int16_t *val)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
struct device *dev = regmap_get_device(st->map);
struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
unsigned int reg;
@@ -175,7 +278,8 @@ static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st,
mutex_lock(&st->lock);
/* enable accel sensor */
conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
conf.mode = accel_st->power_mode;
conf.filter = accel_st->filter;
ret = inv_icm42600_set_accel_conf(st, &conf, NULL);
if (ret)
goto exit;
@@ -277,6 +381,12 @@ static int inv_icm42600_accel_write_scale(struct iio_dev *indio_dev,
/* IIO format int + micro */
static const int inv_icm42600_accel_odr[] = {
/* 1.5625Hz */
1, 562500,
/* 3.125Hz */
3, 125000,
/* 6.25Hz */
6, 250000,
/* 12.5Hz */
12, 500000,
/* 25Hz */
@@ -296,6 +406,9 @@ static const int inv_icm42600_accel_odr[] = {
};
static const int inv_icm42600_accel_odr_conv[] = {
INV_ICM42600_ODR_1_5625HZ_LP,
INV_ICM42600_ODR_3_125HZ_LP,
INV_ICM42600_ODR_6_25HZ_LP,
INV_ICM42600_ODR_12_5HZ,
INV_ICM42600_ODR_25HZ,
INV_ICM42600_ODR_50HZ,
@@ -581,7 +694,7 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev,
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = inv_icm42600_accel_read_sensor(st, chan, &data);
ret = inv_icm42600_accel_read_sensor(indio_dev, chan, &data);
iio_device_release_direct_mode(indio_dev);
if (ret)
return ret;
@@ -754,6 +867,9 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
accel_st->scales_len = ARRAY_SIZE(inv_icm42600_accel_scale);
break;
}
/* low-power by default at init */
accel_st->power_mode = INV_ICM42600_SENSOR_MODE_LOW_POWER;
accel_st->filter = INV_ICM42600_FILTER_AVG_16X;
/*
* clock period is 32kHz (31250ns)
@@ -34,12 +34,56 @@ static const struct regmap_range_cfg inv_icm42600_regmap_ranges[] = {
},
};
static const struct regmap_range inv_icm42600_regmap_volatile_yes_ranges[] = {
/* Sensor data registers */
regmap_reg_range(0x001D, 0x002A),
/* INT status, FIFO, APEX data */
regmap_reg_range(0x002D, 0x0038),
/* Signal path reset */
regmap_reg_range(0x004B, 0x004B),
/* FIFO lost packets */
regmap_reg_range(0x006C, 0x006D),
/* Timestamp value */
regmap_reg_range(0x1062, 0x1064),
};
static const struct regmap_range inv_icm42600_regmap_volatile_no_ranges[] = {
regmap_reg_range(0x0000, 0x001C),
regmap_reg_range(0x006E, 0x1061),
regmap_reg_range(0x1065, 0x4FFF),
};
static const struct regmap_access_table inv_icm42600_regmap_volatile_accesses[] = {
{
.yes_ranges = inv_icm42600_regmap_volatile_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(inv_icm42600_regmap_volatile_yes_ranges),
.no_ranges = inv_icm42600_regmap_volatile_no_ranges,
.n_no_ranges = ARRAY_SIZE(inv_icm42600_regmap_volatile_no_ranges),
},
};
static const struct regmap_range inv_icm42600_regmap_rd_noinc_no_ranges[] = {
regmap_reg_range(0x0000, INV_ICM42600_REG_FIFO_DATA - 1),
regmap_reg_range(INV_ICM42600_REG_FIFO_DATA + 1, 0x4FFF),
};
static const struct regmap_access_table inv_icm42600_regmap_rd_noinc_accesses[] = {
{
.no_ranges = inv_icm42600_regmap_rd_noinc_no_ranges,
.n_no_ranges = ARRAY_SIZE(inv_icm42600_regmap_rd_noinc_no_ranges),
},
};
const struct regmap_config inv_icm42600_regmap_config = {
.name = "inv_icm42600",
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x4FFF,
.ranges = inv_icm42600_regmap_ranges,
.num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges),
.volatile_table = inv_icm42600_regmap_volatile_accesses,
.rd_noinc_table = inv_icm42600_regmap_rd_noinc_accesses,
.cache_type = REGCACHE_RBTREE,
};
EXPORT_SYMBOL_NS_GPL(inv_icm42600_regmap_config, IIO_ICM42600);
@@ -248,6 +292,23 @@ int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st,
if (conf->filter < 0)
conf->filter = oldconf->filter;
/* force power mode against ODR when sensor is on */
switch (conf->mode) {
case INV_ICM42600_SENSOR_MODE_LOW_POWER:
case INV_ICM42600_SENSOR_MODE_LOW_NOISE:
if (conf->odr <= INV_ICM42600_ODR_1KHZ_LN) {
conf->mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
conf->filter = INV_ICM42600_FILTER_BW_ODR_DIV_2;
} else if (conf->odr >= INV_ICM42600_ODR_6_25HZ_LP &&
conf->odr <= INV_ICM42600_ODR_1_5625HZ_LP) {
conf->mode = INV_ICM42600_SENSOR_MODE_LOW_POWER;
conf->filter = INV_ICM42600_FILTER_AVG_16X;
}
break;
default:
break;
}
/* set ACCEL_CONFIG0 register (accel fullscale & odr) */
if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->fs) |
@@ -441,6 +502,16 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st,
if (ret)
return ret;
/*
* Use RC clock for accel low-power to fix glitches when switching
* gyro on/off while accel low-power is on.
*/
ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG1,
INV_ICM42600_INTF_CONFIG1_ACCEL_LP_CLK_RC,
INV_ICM42600_INTF_CONFIG1_ACCEL_LP_CLK_RC);
if (ret)
return ret;
return inv_icm42600_set_conf(st, hw->conf);
}
+1 -1
View File
@@ -1505,7 +1505,7 @@ static const struct acpi_device_id kmx61_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, kmx61_acpi_match);
static const struct i2c_device_id kmx61_id[] = {
{"kmx611021", 0},
{ "kmx611021" },
{}
};
+98 -31
View File
@@ -365,8 +365,16 @@ static ssize_t iio_show_fixed_type(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
u8 type = this_attr->c->scan_type.endianness;
const struct iio_scan_type *scan_type;
u8 type;
scan_type = iio_get_current_scan_type(indio_dev, this_attr->c);
if (IS_ERR(scan_type))
return PTR_ERR(scan_type);
type = scan_type->endianness;
if (type == IIO_CPU) {
#ifdef __LITTLE_ENDIAN
@@ -375,21 +383,21 @@ static ssize_t iio_show_fixed_type(struct device *dev,
type = IIO_BE;
#endif
}
if (this_attr->c->scan_type.repeat > 1)
if (scan_type->repeat > 1)
return sysfs_emit(buf, "%s:%c%d/%dX%d>>%u\n",
iio_endian_prefix[type],
this_attr->c->scan_type.sign,
this_attr->c->scan_type.realbits,
this_attr->c->scan_type.storagebits,
this_attr->c->scan_type.repeat,
this_attr->c->scan_type.shift);
scan_type->sign,
scan_type->realbits,
scan_type->storagebits,
scan_type->repeat,
scan_type->shift);
else
return sysfs_emit(buf, "%s:%c%d/%d>>%u\n",
iio_endian_prefix[type],
this_attr->c->scan_type.sign,
this_attr->c->scan_type.realbits,
this_attr->c->scan_type.storagebits,
this_attr->c->scan_type.shift);
scan_type->sign,
scan_type->realbits,
scan_type->storagebits,
scan_type->shift);
}
static ssize_t iio_scan_el_show(struct device *dev,
@@ -690,20 +698,27 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
return sysfs_emit(buf, "%d\n", iio_buffer_is_active(buffer));
}
static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev,
unsigned int scan_index)
static int iio_storage_bytes_for_si(struct iio_dev *indio_dev,
unsigned int scan_index)
{
const struct iio_chan_spec *ch;
const struct iio_scan_type *scan_type;
unsigned int bytes;
ch = iio_find_channel_from_si(indio_dev, scan_index);
bytes = ch->scan_type.storagebits / 8;
if (ch->scan_type.repeat > 1)
bytes *= ch->scan_type.repeat;
scan_type = iio_get_current_scan_type(indio_dev, ch);
if (IS_ERR(scan_type))
return PTR_ERR(scan_type);
bytes = scan_type->storagebits / 8;
if (scan_type->repeat > 1)
bytes *= scan_type->repeat;
return bytes;
}
static unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
{
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
@@ -721,6 +736,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
for_each_set_bit(i, mask,
indio_dev->masklength) {
length = iio_storage_bytes_for_si(indio_dev, i);
if (length < 0)
return length;
bytes = ALIGN(bytes, length);
bytes += length;
largest = max(largest, length);
@@ -728,6 +746,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
if (timestamp) {
length = iio_storage_bytes_for_timestamp(indio_dev);
if (length < 0)
return length;
bytes = ALIGN(bytes, length);
bytes += length;
largest = max(largest, length);
@@ -1007,14 +1028,22 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
indio_dev->masklength,
in_ind + 1);
while (in_ind != out_ind) {
length = iio_storage_bytes_for_si(indio_dev, in_ind);
ret = iio_storage_bytes_for_si(indio_dev, in_ind);
if (ret < 0)
goto error_clear_mux_table;
length = ret;
/* Make sure we are aligned */
in_loc = roundup(in_loc, length) + length;
in_ind = find_next_bit(indio_dev->active_scan_mask,
indio_dev->masklength,
in_ind + 1);
}
length = iio_storage_bytes_for_si(indio_dev, in_ind);
ret = iio_storage_bytes_for_si(indio_dev, in_ind);
if (ret < 0)
goto error_clear_mux_table;
length = ret;
out_loc = roundup(out_loc, length);
in_loc = roundup(in_loc, length);
ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
@@ -1025,7 +1054,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
}
/* Relies on scan_timestamp being last */
if (buffer->scan_timestamp) {
length = iio_storage_bytes_for_timestamp(indio_dev);
ret = iio_storage_bytes_for_timestamp(indio_dev);
if (ret < 0)
goto error_clear_mux_table;
length = ret;
out_loc = roundup(out_loc, length);
in_loc = roundup(in_loc, length);
ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
@@ -1592,6 +1625,22 @@ static long iio_device_buffer_ioctl(struct iio_dev *indio_dev, struct file *filp
}
}
static int iio_channel_validate_scan_type(struct device *dev, int ch,
const struct iio_scan_type *scan_type)
{
/* Verify that sample bits fit into storage */
if (scan_type->storagebits < scan_type->realbits + scan_type->shift) {
dev_err(dev,
"Channel %d storagebits (%d) < shifted realbits (%d + %d)\n",
ch, scan_type->storagebits,
scan_type->realbits,
scan_type->shift);
return -EINVAL;
}
return 0;
}
static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
struct iio_dev *indio_dev,
int index)
@@ -1616,20 +1665,38 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
if (channels) {
/* new magic */
for (i = 0; i < indio_dev->num_channels; i++) {
const struct iio_scan_type *scan_type;
if (channels[i].scan_index < 0)
continue;
/* Verify that sample bits fit into storage */
if (channels[i].scan_type.storagebits <
channels[i].scan_type.realbits +
channels[i].scan_type.shift) {
dev_err(&indio_dev->dev,
"Channel %d storagebits (%d) < shifted realbits (%d + %d)\n",
i, channels[i].scan_type.storagebits,
channels[i].scan_type.realbits,
channels[i].scan_type.shift);
ret = -EINVAL;
goto error_cleanup_dynamic;
if (channels[i].has_ext_scan_type) {
int j;
/*
* get_current_scan_type is required when using
* extended scan types.
*/
if (!indio_dev->info->get_current_scan_type) {
ret = -EINVAL;
goto error_cleanup_dynamic;
}
for (j = 0; j < channels[i].num_ext_scan_type; j++) {
scan_type = &channels[i].ext_scan_type[j];
ret = iio_channel_validate_scan_type(
&indio_dev->dev, i, scan_type);
if (ret)
goto error_cleanup_dynamic;
}
} else {
scan_type = &channels[i].scan_type;
ret = iio_channel_validate_scan_type(
&indio_dev->dev, i, scan_type);
if (ret)
goto error_cleanup_dynamic;
}
ret = iio_buffer_add_channel_sysfs(indio_dev, buffer,

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