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

The big one here is we finally have Paul Cercueil's (and others)
 DMA buffer support for IIO devices enabling high speed zero
 copy transfer of data to and from sensors supported by IIO (and for
 example USB).  This should aid with upstream support of a range of
 higher performance ADCs and DACs.
 
 Two merges from other trees
 - spi/spi_devm_optimize used for simplification in ad7944.
 - dmaengine/topic_dma_vec to enable the DMABUF series.
 
 One feature with impact outside IIO.
 - Richer set of dev_err_probe() like helpers to cover ERR_PTR() cases.
 
 New device support
 ==================
 adi,ad7173
 - Add support for AD4111, AD4112, AD4114, AD4115 and ADC4116 pseudo
   differential ADCs. Major driver rework was needed to enabled these.
 adi,ad7944
 - Use devm_spi_optimize_message() to avoid a local devm cleanup
   callback. This is the example case from the patch set, others will
   follow.
 mediatek,mt6359-auxadc
 - New driver for this ADC IP found in MT6357, MT6358 and MT6359 PMICs.
 st,accel
 - Add support for the LIS2DS12 accelerometer
 ti,ads1119
 - New driver for this 16 bit 2-differential or 4-single ended channel
   ADC.
 
 Features
 ========
 dt-bindings
 - Introduce new common-mode-channel property to help handle pseudo
   differential ADCs where we have something that looks like one side
   of differential input, but which is only suited for use with a
   slow moving reference.
 adi,adf4350
 - Support use as a clock provider.
 iio-hmwon
 - Support reading of labels from IIO devices by their consumers and
   use this in the hwmon bridge.
 
 Cleanup and minor fixes
 =======================
 Treewide
 - Use regmap_clear_bits() / regmap_set_bits() to simplify open coded
   equivalents.
 - Use devm_regulator_get_enable_read_voltage() to replace equivalent
   opencoded boilerplate. In some cases enabled complete conversion to
   devm handling and removal of explicit remove() callbacks.
 - Introduce dev_err_ptr_probe() and other variants and make use of
   of them in a couple of examples driver cleanups. Will find use in
   many more drivers soon.
 adi,ad7192
 - Introduce local struct device *dev and use dev_err_probe() to give
   more readable code.
 adi,adi-axi-adc/dac
 - Improved consistency of messages using dev_err_probe()
 adi,adis
 - Split the trigger handling into cases that needed paging and those that
   don't resulting in more readable code.
 - Use cleanup.h to simplify error paths via scoped cleanup.
 - Add adis specific lock helpers and make use of them in a number of drivers.
 adi,ad7192
 - Update maintainer (Alisa-Dariana Roman)
 adi,ad7606
 - dt-binding cleanup.
 avago,apds9306
 - Add a maintainer entry (Subhajit Ghosh)
 linear,ltc2309
 - Fix a wrong endian type.
 st,stm32-dfsdm
 - Fix a missing port property in the dt-binding.
 st,sensors
 - Relax whoami match failure to a warning print rather than probe failure.
   This enables fallback compatibles to existing parts from those that don't
   necessarily even exit yet.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAmaEXkQRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0FojAVBAAnaPB1CCyh61JkMQx815wn87looa+JRi3
 v8J/NsM64gYEwG6aNLLxrHAMFECw4GVrL4rHA5bCJFlSYioSKgs0VB7ltOJ/2258
 CsnSxgJ+4fN0468oZz63WuvrmxBsLGbPRGdE/6pkLMJiGHC0Bb/v3ngrJ/LUbAt6
 j0zAFZ2lb5+iuM8MW5vUE0AcwoQakZEg75N4jD6vHSiLvk6dAduj+R8k6z4OlER9
 MaotfjIqYieQ/4SplMcJEd63IxodKjBJacZHFu7uN8d7VWkDhNPyPrJ388GoeXP6
 CK1cTQWO7ZD2yCdY5LjXJYCAejgtiCIMtM7ghe0ZU/OuDBOFgmoaHrmi48pceF9o
 h8KeOsZIa9oF8SSZuKROTQWAwh33F6elf+IoUWYp61hJwft1BQF060rTsGfm7Qq5
 bFOPwMn+BJASC3ARtjNAI/posdAyS4Tb7fBBsDZ9bMW1Y02X/jlhDvDby1WNAcSY
 LEttjsA/naCfquXy4ng+T9sNB+sy2x92FwgEv1Z9MrnMKp5T+mX6XWQ/xhHplGGa
 VAohB/31EatglJqPS0U9mLr1cmUsBS7ItHG9bDB5mOE9wQA5yAqhEqTbe2P3sWWO
 OW43UVaS1VTd10XbY3l0Jjpwe3qsMZNt6M+JaCSizUCLQiEc0h06THcB/xgxdbad
 sTmopNgIR3Y=
 =+9tp
 -----END PGP SIGNATURE-----

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

Jonathan writes:

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

The big one here is we finally have Paul Cercueil's (and others)
DMA buffer support for IIO devices enabling high speed zero
copy transfer of data to and from sensors supported by IIO (and for
example USB).  This should aid with upstream support of a range of
higher performance ADCs and DACs.

Two merges from other trees
- spi/spi_devm_optimize used for simplification in ad7944.
- dmaengine/topic_dma_vec to enable the DMABUF series.

One feature with impact outside IIO.
- Richer set of dev_err_probe() like helpers to cover ERR_PTR() cases.

New device support
==================
adi,ad7173
- Add support for AD4111, AD4112, AD4114, AD4115 and ADC4116 pseudo
  differential ADCs. Major driver rework was needed to enabled these.
adi,ad7944
- Use devm_spi_optimize_message() to avoid a local devm cleanup
  callback. This is the example case from the patch set, others will
  follow.
mediatek,mt6359-auxadc
- New driver for this ADC IP found in MT6357, MT6358 and MT6359 PMICs.
st,accel
- Add support for the LIS2DS12 accelerometer
ti,ads1119
- New driver for this 16 bit 2-differential or 4-single ended channel
  ADC.

Features
========
dt-bindings
- Introduce new common-mode-channel property to help handle pseudo
  differential ADCs where we have something that looks like one side
  of differential input, but which is only suited for use with a
  slow moving reference.
adi,adf4350
- Support use as a clock provider.
iio-hmwon
- Support reading of labels from IIO devices by their consumers and
  use this in the hwmon bridge.

Cleanup and minor fixes
=======================
Treewide
- Use regmap_clear_bits() / regmap_set_bits() to simplify open coded
  equivalents.
- Use devm_regulator_get_enable_read_voltage() to replace equivalent
  opencoded boilerplate. In some cases enabled complete conversion to
  devm handling and removal of explicit remove() callbacks.
- Introduce dev_err_ptr_probe() and other variants and make use of
  of them in a couple of examples driver cleanups. Will find use in
  many more drivers soon.
adi,ad7192
- Introduce local struct device *dev and use dev_err_probe() to give
  more readable code.
adi,adi-axi-adc/dac
- Improved consistency of messages using dev_err_probe()
adi,adis
- Split the trigger handling into cases that needed paging and those that
  don't resulting in more readable code.
- Use cleanup.h to simplify error paths via scoped cleanup.
- Add adis specific lock helpers and make use of them in a number of drivers.
adi,ad7192
- Update maintainer (Alisa-Dariana Roman)
adi,ad7606
- dt-binding cleanup.
avago,apds9306
- Add a maintainer entry (Subhajit Ghosh)
linear,ltc2309
- Fix a wrong endian type.
st,stm32-dfsdm
- Fix a missing port property in the dt-binding.
st,sensors
- Relax whoami match failure to a warning print rather than probe failure.
  This enables fallback compatibles to existing parts from those that don't
  necessarily even exit yet.

* tag 'iio-for-6.11b' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (112 commits)
  iio: adc: ad7173: Fix uninitialized symbol is_current_chan
  iio: adc: Add support for MediaTek MT6357/8/9 Auxiliary ADC
  math.h: Add unsigned 8 bits fractional numbers type
  dt-bindings: iio: adc: Add MediaTek MT6359 PMIC AUXADC
  iio: common: scmi_iio: convert to dev_err_probe()
  iio: backend: make use of dev_err_cast_probe()
  iio: temperature: ltc2983: convert to dev_err_probe()
  dev_printk: add new dev_err_probe() helpers
  iio: xilinx-ams: Add labels
  iio: adc: ad7944: use devm_spi_optimize_message()
  Documentation: iio: Document high-speed DMABUF based API
  iio: buffer-dmaengine: Support new DMABUF based userspace API
  iio: buffer-dma: Enable support for DMABUFs
  iio: core: Add new DMABUF interface infrastructure
  MAINTAINERS: Update AD7192 driver maintainer
  iio: adc: ad7192: use devm_regulator_get_enable_read_voltage
  iio: st_sensors: relax WhoAmI check in st_sensors_verify_id()
  MAINTAINERS: Add AVAGO APDS9306
  dt-bindings: iio: adc: adi,ad7606: comment and sort the compatible names
  dt-bindings: iio: adc: adi,ad7606: add missing datasheet link
  ...
This commit is contained in:
Greg Kroah-Hartman 2024-07-04 11:04:20 +02:00
commit 14c4dc8bb6
119 changed files with 4446 additions and 1493 deletions

View File

@ -46,6 +46,17 @@ properties:
differential channels). If this and diff-channels are not present reg
shall be used instead.
common-mode-channel:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Some ADCs have differential input pins that can be used to measure
single-ended or pseudo-differential inputs. This property can be used
in addition to single-channel to signal software that this channel is
not differential but still specify two inputs.
The input pair is specified by setting single-channel to the positive
input pin and common-mode-channel to the negative pin.
settling-time-us:
description:
Time between enabling the channel and first stable readings.

View File

@ -19,7 +19,18 @@ description: |
primarily for measurement of signals close to DC but also delivers
outstanding performance with input bandwidths out to ~10kHz.
Analog Devices AD411x ADC's:
The AD411X family encompasses a series of low power, low noise, 24-bit,
sigma-delta analog-to-digital converters that offer a versatile range of
specifications. They integrate an analog front end suitable for processing
fully differential/single-ended and bipolar voltage inputs.
Datasheets for supported chips:
https://www.analog.com/media/en/technical-documentation/data-sheets/AD4111.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD4112.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD4114.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD4115.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD4116.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7172-2.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7172-4.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7173-8.pdf
@ -31,6 +42,11 @@ description: |
properties:
compatible:
enum:
- adi,ad4111
- adi,ad4112
- adi,ad4114
- adi,ad4115
- adi,ad4116
- adi,ad7172-2
- adi,ad7172-4
- adi,ad7173-8
@ -129,10 +145,56 @@ patternProperties:
maximum: 15
diff-channels:
description: |
This property is used for defining the inputs of a differential
voltage channel. The first value is the positive input and the second
value is the negative input of the channel.
Family AD411x supports a dedicated VINCOM voltage input.
To select it set the second channel to 16.
(VIN2, VINCOM) -> diff-channels = <2 16>
There are special values that can be selected besides the voltage
analog inputs:
21: REF+
22: REF
Supported only by AD7172-2, AD7172-4, AD7175-2, AD7175-8, AD7177-2,
must be paired together and can be used to monitor the power supply
of the ADC:
19: ((AVDD1 AVSS)/5)+
20: ((AVDD1 AVSS)/5)
items:
minimum: 0
maximum: 31
single-channel:
description: |
This property is used for defining a current channel or the positive
input of a voltage channel (single-ended or pseudo-differential).
Models AD4111 and AD4112 support current channels.
Example: (IIN2+, IIN2) -> single-channel = <2>
To correctly configure a current channel set the "adi,current-channel"
property to true.
To configure a single-ended/pseudo-differential channel set the
"common-mode-channel" property to the desired negative voltage input.
When used as a voltage channel, special inputs are valid as well.
minimum: 0
maximum: 31
common-mode-channel:
description:
This property is used for defining the negative input of a
single-ended or pseudo-differential voltage channel.
Special inputs are valid as well.
minimum: 0
maximum: 31
adi,reference-select:
description: |
Select the reference source to use when converting on
@ -154,9 +216,31 @@ patternProperties:
- avdd
default: refout-avss
adi,current-channel:
$ref: /schemas/types.yaml#/definitions/flag
description: |
Signal that the selected inputs are current channels.
Only available on AD4111 and AD4112.
required:
- reg
- diff-channels
allOf:
- oneOf:
- required: [single-channel]
properties:
diff-channels: false
- required: [diff-channels]
properties:
single-channel: false
adi,current-channel: false
common-mode-channel: false
- if:
required: [common-mode-channel]
then:
properties:
adi,current-channel: false
required:
- compatible
@ -166,7 +250,6 @@ allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
# Only ad7172-4, ad7173-8 and ad7175-8 support vref2
# Other models have [0-3] channel registers
- if:
properties:
compatible:
@ -187,6 +270,37 @@ allOf:
- vref
- refout-avss
- avdd
- if:
properties:
compatible:
contains:
enum:
- adi,ad4114
- adi,ad4115
- adi,ad4116
- adi,ad7173-8
- adi,ad7175-8
then:
patternProperties:
"^channel@[0-9a-f]$":
properties:
reg:
maximum: 15
- if:
properties:
compatible:
contains:
enum:
- adi,ad7172-2
- adi,ad7175-2
- adi,ad7176-2
- adi,ad7177-2
then:
patternProperties:
"^channel@[0-9a-f]$":
properties:
reg:
maximum: 3
@ -210,6 +324,34 @@ allOf:
required:
- adi,reference-select
- if:
properties:
compatible:
contains:
enum:
- adi,ad4111
- adi,ad4112
- adi,ad4114
- adi,ad4115
- adi,ad4116
then:
properties:
avdd2-supply: false
- if:
properties:
compatible:
not:
contains:
enum:
- adi,ad4111
- adi,ad4112
then:
patternProperties:
"^channel@[0-9a-f]$":
properties:
adi,current-channel: false
- if:
anyOf:
- required: [clock-names]
@ -221,6 +363,7 @@ allOf:
unevaluatedProperties: false
examples:
# Example AD7173-8 with external reference connected to REF+/REF-:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
@ -277,3 +420,50 @@ examples:
};
};
};
# Example AD4111 with current channel and single-ended channel:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,ad4111";
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-names = "rdy";
interrupt-parent = <&gpio>;
spi-max-frequency = <5000000>;
gpio-controller;
#gpio-cells = <2>;
#clock-cells = <0>;
channel@0 {
reg = <0>;
bipolar;
diff-channels = <4 5>;
};
// Single ended channel VIN2/VINCOM
channel@1 {
reg = <1>;
bipolar;
single-channel = <2>;
common-mode-channel = <16>;
};
// Current channel IN2+/IN2-
channel@2 {
reg = <2>;
single-channel = <2>;
adi,current-channel;
};
};
};

View File

@ -11,6 +11,7 @@ maintainers:
description: |
Analog Devices AD7606 Simultaneous Sampling ADC
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7605-4.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7606B.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf
@ -19,9 +20,9 @@ properties:
compatible:
enum:
- adi,ad7605-4
- adi,ad7606-8
- adi,ad7606-6
- adi,ad7606-4
- adi,ad7606-6
- adi,ad7606-8 # Referred to as AD7606 (without -8) in the datasheet
- adi,ad7606b
- adi,ad7616

View File

@ -0,0 +1,33 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/mediatek,mt6359-auxadc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MT6350 series PMIC AUXADC
maintainers:
- AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
description:
The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
in some MediaTek PMICs, performing various PMIC related measurements
such as battery and PMIC internal voltage regulators temperatures,
accessory detection resistance (usually, for a 3.5mm audio jack)
other than voltages for various PMIC internal components.
properties:
compatible:
enum:
- mediatek,mt6357-auxadc
- mediatek,mt6358-auxadc
- mediatek,mt6359-auxadc
"#io-channel-cells":
const: 1
required:
- compatible
- "#io-channel-cells"
additionalProperties: false

View File

@ -246,6 +246,10 @@ patternProperties:
From common IIO binding. Used to pipe external sigma delta
modulator or internal ADC output to DFSDM channel.
port:
$ref: /schemas/sound/audio-graph-port.yaml#
unevaluatedProperties: false
required:
- compatible
- "#sound-dai-cells"

View File

@ -0,0 +1,155 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/ti,ads1119.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments ADS1119 ADC
maintainers:
- João Paulo Gonçalves <jpaulo.silvagoncalves@gmail.com>
description:
The TI ADS1119 is a precision 16-bit ADC over I2C that offers single-ended and
differential measurements using a multiplexed input. It features a programmable
gain, a programmable sample rate, an internal oscillator and voltage reference,
and a 50/60Hz rejection filter.
properties:
compatible:
const: ti,ads1119
reg:
maxItems: 1
interrupts:
maxItems: 1
reset-gpios:
maxItems: 1
avdd-supply: true
dvdd-supply: true
vref-supply:
description:
ADC external reference voltage (VREF).
"#address-cells":
const: 1
"#size-cells":
const: 0
"#io-channel-cells":
const: 1
required:
- compatible
- reg
- "#address-cells"
- "#size-cells"
- avdd-supply
- dvdd-supply
patternProperties:
"^channel@([0-6])$":
$ref: adc.yaml
type: object
properties:
reg:
minimum: 0
maximum: 6
diff-channels:
description:
Differential input channels AIN0-AIN1, AIN2-AIN3 and AIN1-AIN2.
oneOf:
- items:
- const: 0
- const: 1
- items:
- const: 2
- const: 3
- items:
- const: 1
- const: 2
single-channel:
description:
Single-ended input channels AIN0, AIN1, AIN2 and AIN3.
minimum: 0
maximum: 3
oneOf:
- required:
- diff-channels
- required:
- single-channel
required:
- reg
unevaluatedProperties: false
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@40 {
compatible = "ti,ads1119";
reg = <0x40>;
interrupt-parent = <&gpio1>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
avdd-supply = <&reg_avdd_ads1119>;
dvdd-supply = <&reg_dvdd_ads1119>;
vref-supply = <&reg_vref_ads1119>;
#address-cells = <1>;
#size-cells = <0>;
#io-channel-cells = <1>;
channel@0 {
reg = <0>;
single-channel = <0>;
};
channel@1 {
reg = <1>;
diff-channels = <0 1>;
};
channel@2 {
reg = <2>;
single-channel = <3>;
};
channel@3 {
reg = <3>;
single-channel = <1>;
};
channel@4 {
reg = <4>;
single-channel = <2>;
};
channel@5 {
reg = <5>;
diff-channels = <1 2>;
};
channel@6 {
reg = <6>;
diff-channels = <2 3>;
};
};
};

View File

@ -28,6 +28,12 @@ properties:
clock-names:
const: clkin
'#clock-cells':
const: 0
clock-output-names:
maxItems: 1
gpios:
maxItems: 1
description: Lock detect GPIO.

View File

@ -26,6 +26,7 @@ properties:
- st,lis2dw12
- st,lis2hh12
- st,lis2dh12-accel
- st,lis2ds12
- st,lis302dl
- st,lis331dl-accel
- st,lis331dlh-accel

View File

@ -80,6 +80,10 @@ The details of these operations are:
- slave_sg: DMA a list of scatter gather buffers from/to a peripheral
- peripheral_dma_vec: DMA an array of scatter gather buffers from/to a
peripheral. Similar to slave_sg, but uses an array of dma_vec
structures instead of a scatterlist.
- dma_cyclic: Perform a cyclic DMA operation from/to a peripheral till the
operation is explicitly stopped.
@ -102,6 +106,11 @@ The details of these operations are:
unsigned int sg_len, enum dma_data_direction direction,
unsigned long flags);
struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
struct dma_chan *chan, const struct dma_vec *vecs,
size_t nents, enum dma_data_direction direction,
unsigned long flags);
struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
size_t period_len, enum dma_data_direction direction);

View File

@ -433,6 +433,12 @@ supported.
- residue: Provides the residue bytes of the transfer for those that
support residue.
- ``device_prep_peripheral_dma_vec``
- Similar to ``device_prep_slave_sg``, but it takes a pointer to a
array of ``dma_vec`` structures, which (in the long run) will replace
scatterlists.
- ``device_issue_pending``
- Takes the first transaction descriptor in the pending queue,
@ -544,6 +550,10 @@ dma_cookie_t
- Not really relevant any more since the introduction of ``virt-dma``
that abstracts it away.
dma_vec
- A small structure that contains a DMA address and length.
DMA_CTRL_ACK
- If clear, the descriptor cannot be reused by provider until the

View File

@ -464,7 +464,10 @@ SLAVE DMA ENGINE
SPI
devm_spi_alloc_master()
devm_spi_alloc_slave()
devm_spi_optimize_message()
devm_spi_register_controller()
devm_spi_register_host()
devm_spi_register_target()
WATCHDOG
devm_watchdog_register_device()

View File

@ -0,0 +1,54 @@
.. SPDX-License-Identifier: GPL-2.0
===================================
High-speed DMABUF interface for IIO
===================================
1. Overview
===========
The Industrial I/O subsystem supports access to buffers through a
file-based interface, with read() and write() access calls through the
IIO device's dev node.
It additionally supports a DMABUF based interface, where the userspace
can attach DMABUF objects (externally created) to an IIO buffer, and
subsequently use them for data transfers.
A userspace application can then use this interface to share DMABUF
objects between several interfaces, allowing it to transfer data in a
zero-copy fashion, for instance between IIO and the USB stack.
The userspace application can also memory-map the DMABUF objects, and
access the sample data directly. The advantage of doing this vs. the
read() interface is that it avoids an extra copy of the data between the
kernel and userspace. This is particularly useful for high-speed devices
which produce several megabytes or even gigabytes of data per second.
It does however increase the userspace-kernelspace synchronization
overhead, as the DMA_BUF_SYNC_START and DMA_BUF_SYNC_END IOCTLs have to
be used for data integrity.
2. User API
===========
As part of this interface, three new IOCTLs have been added. These three
IOCTLs have to be performed on the IIO buffer's file descriptor, which
can be obtained using the IIO_BUFFER_GET_FD_IOCTL() ioctl.
``IIO_BUFFER_DMABUF_ATTACH_IOCTL(int fd)``
Attach the DMABUF object, identified by its file descriptor, to the
IIO buffer. Returns zero on success, and a negative errno value on
error.
``IIO_BUFFER_DMABUF_DETACH_IOCTL(int fd)``
Detach the given DMABUF object, identified by its file descriptor,
from the IIO buffer. Returns zero on success, and a negative errno
value on error.
Note that closing the IIO buffer's file descriptor will
automatically detach all previously attached DMABUF objects.
``IIO_BUFFER_DMABUF_ENQUEUE_IOCTL(struct iio_dmabuf *iio_dmabuf)``
Enqueue a previously attached DMABUF object to the buffer queue.
Enqueued DMABUFs will be read from (if output buffer) or written to
(if input buffer) as long as the buffer is enabled.

View File

@ -9,6 +9,7 @@ Industrial I/O
iio_configfs
iio_devbuf
iio_dmabuf_api
iio_tools
Industrial I/O Kernel Drivers

View File

@ -1217,7 +1217,7 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r*
F: drivers/iio/adc/ad7091r*
ANALOG DEVICES INC AD7192 DRIVER
M: Alexandru Tachici <alexandru.tachici@analog.com>
M: Alisa-Dariana Roman <alisa.roman@analog.com>
L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
@ -3531,6 +3531,13 @@ F: include/linux/cfag12864b.h
F: include/uapi/linux/map_to_14segment.h
F: include/uapi/linux/map_to_7segment.h
AVAGO APDS9306 AMBIENT LIGHT SENSOR DRIVER
M: Subhajit Ghosh <subhajit.ghosh@tweaklogic.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml
F: drivers/iio/light/apds9306.c
AVIA HX711 ANALOG DIGITAL CONVERTER IIO DRIVER
M: Andreas Klinger <ak@it-klinger.de>
L: linux-iio@vger.kernel.org
@ -22397,6 +22404,14 @@ M: Robert Richter <rric@kernel.org>
S: Odd Fixes
F: drivers/gpio/gpio-thunderx.c
TI ADS1119 ADC DRIVER
M: Francesco Dolcini <francesco@dolcini.it>
M: João Paulo Gonçalves <jpaulo.silvagoncalves@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml
F: drivers/iio/adc/ti-ads1119.c
TI ADS7924 ADC DRIVER
M: Hugo Villeneuve <hvilleneuve@dimonoff.com>
L: linux-iio@vger.kernel.org

View File

@ -620,6 +620,45 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan,
return sg;
}
static struct dma_async_tx_descriptor *
axi_dmac_prep_peripheral_dma_vec(struct dma_chan *c, const struct dma_vec *vecs,
size_t nb, enum dma_transfer_direction direction,
unsigned long flags)
{
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
struct axi_dmac_desc *desc;
unsigned int num_sgs = 0;
struct axi_dmac_sg *dsg;
size_t i;
if (direction != chan->direction)
return NULL;
for (i = 0; i < nb; i++)
num_sgs += DIV_ROUND_UP(vecs[i].len, chan->max_length);
desc = axi_dmac_alloc_desc(chan, num_sgs);
if (!desc)
return NULL;
dsg = desc->sg;
for (i = 0; i < nb; i++) {
if (!axi_dmac_check_addr(chan, vecs[i].addr) ||
!axi_dmac_check_len(chan, vecs[i].len)) {
kfree(desc);
return NULL;
}
dsg = axi_dmac_fill_linear_sg(chan, direction, vecs[i].addr, 1,
vecs[i].len, dsg);
}
desc->cyclic = false;
return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
}
static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
struct dma_chan *c, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
@ -1061,6 +1100,7 @@ static int axi_dmac_probe(struct platform_device *pdev)
dma_dev->device_tx_status = dma_cookie_status;
dma_dev->device_issue_pending = axi_dmac_issue_pending;
dma_dev->device_prep_slave_sg = axi_dmac_prep_slave_sg;
dma_dev->device_prep_peripheral_dma_vec = axi_dmac_prep_peripheral_dma_vec;
dma_dev->device_prep_dma_cyclic = axi_dmac_prep_dma_cyclic;
dma_dev->device_prep_interleaved_dma = axi_dmac_prep_interleaved;
dma_dev->device_terminate_all = axi_dmac_terminate_all;

View File

@ -33,6 +33,17 @@ struct iio_hwmon_state {
struct attribute **attrs;
};
static ssize_t iio_hwmon_read_label(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
struct iio_hwmon_state *state = dev_get_drvdata(dev);
struct iio_channel *chan = &state->channels[sattr->index];
return iio_read_channel_label(chan, buf);
}
/*
* Assumes that IIO and hwmon operate in the same base units.
* This is supposed to be true, but needs verification for
@ -68,12 +79,13 @@ static int iio_hwmon_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct iio_hwmon_state *st;
struct sensor_device_attribute *a;
int ret, i;
int ret, i, attr = 0;
int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1, power_i = 1;
enum iio_chan_type type;
struct iio_channel *channels;
struct device *hwmon_dev;
char *sname;
void *buf;
channels = devm_iio_channel_get_all(dev);
if (IS_ERR(channels)) {
@ -85,17 +97,18 @@ static int iio_hwmon_probe(struct platform_device *pdev)
}
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
if (st == NULL)
buf = (void *)devm_get_free_pages(dev, GFP_KERNEL, 0);
if (!st || !buf)
return -ENOMEM;
st->channels = channels;
/* count how many attributes we have */
/* count how many channels we have */
while (st->channels[st->num_channels].indio_dev)
st->num_channels++;
st->attrs = devm_kcalloc(dev,
st->num_channels + 1, sizeof(*st->attrs),
2 * st->num_channels + 1, sizeof(*st->attrs),
GFP_KERNEL);
if (st->attrs == NULL)
return -ENOMEM;
@ -147,9 +160,31 @@ static int iio_hwmon_probe(struct platform_device *pdev)
a->dev_attr.show = iio_hwmon_read_val;
a->dev_attr.attr.mode = 0444;
a->index = i;
st->attrs[i] = &a->dev_attr.attr;
st->attrs[attr++] = &a->dev_attr.attr;
/* Let's see if we have a label... */
if (iio_read_channel_label(&st->channels[i], buf) < 0)
continue;
a = devm_kzalloc(dev, sizeof(*a), GFP_KERNEL);
if (a == NULL)
return -ENOMEM;
sysfs_attr_init(&a->dev_attr.attr);
a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
"%s%d_label",
prefix, n);
if (!a->dev_attr.attr.name)
return -ENOMEM;
a->dev_attr.show = iio_hwmon_read_label;
a->dev_attr.attr.mode = 0444;
a->index = i;
st->attrs[attr++] = &a->dev_attr.attr;
}
devm_free_pages(dev, (unsigned long)buf);
st->attr_group.attrs = st->attrs;
st->groups[0] = &st->attr_group;

View File

@ -14,6 +14,7 @@ if IIO
config IIO_BUFFER
bool "Enable buffer support within IIO"
select DMA_SHARED_BUFFER
help
Provide core support for various buffer based data
acquisition methods.

View File

@ -228,8 +228,8 @@ static int fxls8962af_power_off(struct fxls8962af_data *data)
static int fxls8962af_standby(struct fxls8962af_data *data)
{
return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
FXLS8962AF_SENS_CONFIG1_ACTIVE, 0);
return regmap_clear_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
FXLS8962AF_SENS_CONFIG1_ACTIVE);
}
static int fxls8962af_active(struct fxls8962af_data *data)
@ -785,9 +785,8 @@ static int fxls8962af_reset(struct fxls8962af_data *data)
unsigned int reg;
int ret;
ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
FXLS8962AF_SENS_CONFIG1_RST,
FXLS8962AF_SENS_CONFIG1_RST);
ret = regmap_set_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
FXLS8962AF_SENS_CONFIG1_RST);
if (ret)
return ret;
@ -830,9 +829,8 @@ static int fxls8962af_buffer_postenable(struct iio_dev *indio_dev)
fxls8962af_standby(data);
/* Enable buffer interrupt */
ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN,
FXLS8962AF_INT_EN_BUF_EN,
FXLS8962AF_INT_EN_BUF_EN);
ret = regmap_set_bits(data->regmap, FXLS8962AF_INT_EN,
FXLS8962AF_INT_EN_BUF_EN);
if (ret)
return ret;
@ -851,8 +849,8 @@ static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev)
fxls8962af_standby(data);
/* Disable buffer interrupt */
ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN,
FXLS8962AF_INT_EN_BUF_EN, 0);
ret = regmap_clear_bits(data->regmap, FXLS8962AF_INT_EN,
FXLS8962AF_INT_EN_BUF_EN);
if (ret)
return ret;

View File

@ -370,10 +370,7 @@ static int kxsd9_power_down(struct kxsd9_state *st)
* make sure we conserve power even if there are others users on the
* regulators.
*/
ret = regmap_update_bits(st->map,
KXSD9_REG_CTRL_B,
KXSD9_CTRL_B_ENABLE,
0);
ret = regmap_clear_bits(st->map, KXSD9_REG_CTRL_B, KXSD9_CTRL_B_ENABLE);
if (ret)
return ret;

View File

@ -1034,10 +1034,10 @@ static int msa311_chip_init(struct msa311_priv *msa311)
"failed to unmap map0/map1 interrupts\n");
/* Disable all axes by default */
err = regmap_update_bits(msa311->regs, MSA311_ODR_REG,
MSA311_GENMASK(F_X_AXIS_DIS) |
MSA311_GENMASK(F_Y_AXIS_DIS) |
MSA311_GENMASK(F_Z_AXIS_DIS), 0);
err = regmap_clear_bits(msa311->regs, MSA311_ODR_REG,
MSA311_GENMASK(F_X_AXIS_DIS) |
MSA311_GENMASK(F_Y_AXIS_DIS) |
MSA311_GENMASK(F_Z_AXIS_DIS));
if (err)
return dev_err_probe(dev, err, "can't enable all axes\n");

View File

@ -35,6 +35,7 @@
#define LIS3DHH_ACCEL_DEV_NAME "lis3dhh"
#define LIS3DE_ACCEL_DEV_NAME "lis3de"
#define LIS2DE12_ACCEL_DEV_NAME "lis2de12"
#define LIS2DS12_ACCEL_DEV_NAME "lis2ds12"
#define LIS2HH12_ACCEL_DEV_NAME "lis2hh12"
#define LIS302DL_ACCEL_DEV_NAME "lis302dl"
#define LSM303C_ACCEL_DEV_NAME "lsm303c_accel"

View File

@ -925,6 +925,87 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.multi_read_bit = true,
.bootime = 2,
},
{
.wai = 0x43,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS2DS12_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_16bit_channels,
.odr = {
.addr = 0x20,
.mask = 0xf0,
.odr_avl = {
{ .hz = 10, .value = 0x01, },
{ .hz = 50, .value = 0x02, },
{ .hz = 100, .value = 0x03, },
{ .hz = 200, .value = 0x04, },
{ .hz = 400, .value = 0x05, },
{ .hz = 800, .value = 0x06, },
},
},
.pw = {
.addr = 0x20,
.mask = 0xf0,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.enable_axis = {
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
},
.fs = {
.addr = 0x20,
.mask = 0x0c,
.fs_avl = {
[0] = {
.num = ST_ACCEL_FS_AVL_2G,
.value = 0x00,
.gain = IIO_G_TO_M_S_2(61),
},
[1] = {
.num = ST_ACCEL_FS_AVL_4G,
.value = 0x02,
.gain = IIO_G_TO_M_S_2(122),
},
[2] = {
.num = ST_ACCEL_FS_AVL_8G,
.value = 0x03,
.gain = IIO_G_TO_M_S_2(244),
},
[3] = {
.num = ST_ACCEL_FS_AVL_16G,
.value = 0x01,
.gain = IIO_G_TO_M_S_2(488),
},
},
},
.bdu = {
.addr = 0x20,
.mask = 0x01,
},
.drdy_irq = {
.int1 = {
.addr = 0x23,
.mask = 0x01,
},
.int2 = {
.addr = 0x24,
.mask = 0x01,
},
.addr_ihl = 0x22,
.mask_ihl = 0x02,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x01,
},
},
.sim = {
.addr = 0x21,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
},
{
.wai = 0x41,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,

View File

@ -102,6 +102,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lis2de12",
.data = LIS2DE12_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis2ds12",
.data = LIS2DS12_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis2hh12",
.data = LIS2HH12_ACCEL_DEV_NAME,
@ -154,6 +158,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ LIS2DW12_ACCEL_DEV_NAME },
{ LIS3DE_ACCEL_DEV_NAME },
{ LIS2DE12_ACCEL_DEV_NAME },
{ LIS2DS12_ACCEL_DEV_NAME },
{ LIS2HH12_ACCEL_DEV_NAME },
{ LIS302DL_ACCEL_DEV_NAME },
{ LSM303C_ACCEL_DEV_NAME },

View File

@ -64,6 +64,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lis2dh12-accel",
.data = LIS2DH12_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis2ds12",
.data = LIS2DS12_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis3l02dq",
.data = LIS3L02DQ_ACCEL_DEV_NAME,
@ -151,6 +155,7 @@ static const struct spi_device_id st_accel_id_table[] = {
{ LSM330_ACCEL_DEV_NAME },
{ LSM303AGR_ACCEL_DEV_NAME },
{ LIS2DH12_ACCEL_DEV_NAME },
{ LIS2DS12_ACCEL_DEV_NAME },
{ LIS3L02DQ_ACCEL_DEV_NAME },
{ LNG2DM_ACCEL_DEV_NAME },
{ H3LIS331DL_ACCEL_DEV_NAME },

View File

@ -892,6 +892,18 @@ config MCP3911
This driver can also be built as a module. If so, the module will be
called mcp3911.
config MEDIATEK_MT6359_AUXADC
tristate "MediaTek MT6359 PMIC AUXADC driver"
depends on MFD_MT6397
help
Say yes here to enable support for MediaTek MT6357, MT6358 and
MT6359 PMICs Auxiliary ADC.
This driver provides multiple channels for system monitoring,
such as battery voltage, PMIC temperature, and others.
This driver can also be built as a module. If so, the module will be
called mt6359-auxadc.
config MEDIATEK_MT6360_ADC
tristate "Mediatek MT6360 ADC driver"
depends on MFD_MT6360
@ -1351,6 +1363,18 @@ config TI_ADS1015
This driver can also be built as a module. If so, the module will be
called ti-ads1015.
config TI_ADS1119
tristate "Texas Instruments ADS1119 ADC"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
If you say yes here you get support for Texas Instruments ADS1119
ADC chip.
This driver can also be built as a module. If so, the module will be
called ti-ads1119.
config TI_ADS7924
tristate "Texas Instruments ADS7924 ADC"
depends on I2C

View File

@ -80,6 +80,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MCP3564) += mcp3564.o
obj-$(CONFIG_MCP3911) += mcp3911.o
obj-$(CONFIG_MEDIATEK_MT6359_AUXADC) += mt6359-auxadc.o
obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
@ -121,6 +122,7 @@ 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_ADS1119) += ti-ads1119.o
obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o
obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o

View File

@ -1883,8 +1883,8 @@ static int ad4130_setup(struct iio_dev *indio_dev)
if (ret)
return ret;
ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
AD4130_FIFO_CONTROL_HEADER_MASK, 0);
ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
AD4130_FIFO_CONTROL_HEADER_MASK);
if (ret)
return ret;

View File

@ -555,10 +555,18 @@ static int ad7124_disable_all(struct ad_sigma_delta *sd)
return 0;
}
static int ad7124_disable_one(struct ad_sigma_delta *sd, unsigned int chan)
{
struct ad7124_state *st = container_of(sd, struct ad7124_state, sd);
return ad7124_spi_write_mask(st, AD7124_CHANNEL(chan), AD7124_CHANNEL_EN_MSK, 0, 2);
}
static const struct ad_sigma_delta_info ad7124_sigma_delta_info = {
.set_channel = ad7124_set_channel,
.append_status = ad7124_append_status,
.disable_all = ad7124_disable_all,
.disable_one = ad7124_disable_one,
.set_mode = ad7124_set_mode,
.has_registers = true,
.addr_shift = 0,
@ -582,12 +590,6 @@ static int ad7124_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
/* After the conversion is performed, disable the channel */
ret = ad_sd_write_reg(&st->sd, AD7124_CHANNEL(chan->address), 2,
st->channels[chan->address].ain | AD7124_CHANNEL_EN(0));
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
mutex_lock(&st->cfgs_lock);

View File

@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* AD717x family SPI ADC driver
* AD717x and AD411x family SPI ADC driver
*
* Supported devices:
* AD4111/AD4112/AD4114/AD4115/AD4116
* AD7172-2/AD7172-4/AD7173-8/AD7175-2
* AD7175-8/AD7176-2/AD7177-2
*
@ -60,11 +61,19 @@
#define AD7173_CH_SETUP_AINPOS_MASK GENMASK(9, 5)
#define AD7173_CH_SETUP_AINNEG_MASK GENMASK(4, 0)
#define AD7173_NO_AINS_PER_CHANNEL 2
#define AD7173_CH_ADDRESS(pos, neg) \
(FIELD_PREP(AD7173_CH_SETUP_AINPOS_MASK, pos) | \
FIELD_PREP(AD7173_CH_SETUP_AINNEG_MASK, neg))
#define AD7173_AIN_TEMP_POS 17
#define AD7173_AIN_TEMP_NEG 18
#define AD7173_AIN_POW_MON_POS 19
#define AD7173_AIN_POW_MON_NEG 20
#define AD7173_AIN_REF_POS 21
#define AD7173_AIN_REF_NEG 22
#define AD7173_IS_REF_INPUT(x) ((x) == AD7173_AIN_REF_POS || \
(x) == AD7173_AIN_REF_NEG)
#define AD7172_2_ID 0x00d0
#define AD7175_ID 0x0cd0
@ -72,6 +81,11 @@
#define AD7175_2_ID 0x0cd0
#define AD7172_4_ID 0x2050
#define AD7173_ID 0x30d0
#define AD4111_ID AD7173_ID
#define AD4112_ID AD7173_ID
#define AD4114_ID AD7173_ID
#define AD4116_ID 0x34d0
#define AD4115_ID 0x38d0
#define AD7175_8_ID 0x3cd0
#define AD7177_ID 0x4fd0
#define AD7173_ID_MASK GENMASK(15, 4)
@ -102,6 +116,7 @@
#define AD7173_GPO12_DATA(x) BIT((x) + 0)
#define AD7173_GPO23_DATA(x) BIT((x) + 4)
#define AD4111_GPO01_DATA(x) BIT((x) + 6)
#define AD7173_GPO_DATA(x) ((x) < 2 ? AD7173_GPO12_DATA(x) : AD7173_GPO23_DATA(x))
#define AD7173_INTERFACE_DATA_STAT BIT(6)
@ -120,34 +135,45 @@
#define AD7173_VOLTAGE_INT_REF_uV 2500000
#define AD7173_TEMP_SENSIIVITY_uV_per_C 477
#define AD7177_ODR_START_VALUE 0x07
#define AD4111_SHUNT_RESISTOR_OHM 50
#define AD4111_DIVIDER_RATIO 10
#define AD4111_CURRENT_CHAN_CUTOFF 16
#define AD4111_VINCOM_INPUT 0x10
/* pin < num_voltage_in is a normal voltage input */
/* pin >= num_voltage_in_div is a voltage input without a divider */
#define AD4111_IS_VINCOM_MISMATCH(pin1, pin2) ((pin1) == AD4111_VINCOM_INPUT && \
(pin2) < st->info->num_voltage_in && \
(pin2) >= st->info->num_voltage_in_div)
#define AD7173_FILTER_ODR0_MASK GENMASK(5, 0)
#define AD7173_MAX_CONFIGS 8
enum ad7173_ids {
ID_AD7172_2,
ID_AD7172_4,
ID_AD7173_8,
ID_AD7175_2,
ID_AD7175_8,
ID_AD7176_2,
ID_AD7177_2,
};
struct ad7173_device_info {
const unsigned int *sinc5_data_rates;
unsigned int num_sinc5_data_rates;
unsigned int odr_start_value;
/*
* AD4116 has both inputs with a voltage divider and without.
* These inputs cannot be mixed in the channel configuration.
* Does not include the VINCOM input.
*/
unsigned int num_voltage_in_div;
unsigned int num_channels;
unsigned int num_configs;
unsigned int num_inputs;
unsigned int num_voltage_in;
unsigned int clock;
unsigned int id;
char *name;
bool has_current_inputs;
bool has_vincom_input;
bool has_temp;
/* ((AVDD1 AVSS)/5) */
bool has_pow_supply_monitoring;
bool has_input_buf;
bool has_int_ref;
bool has_ref2;
bool higher_gpio_bits;
u8 num_gpios;
};
@ -189,6 +215,24 @@ struct ad7173_state {
#endif
};
static unsigned int ad4115_sinc5_data_rates[] = {
24845000, 24845000, 20725000, 20725000, /* 0-3 */
15564000, 13841000, 10390000, 10390000, /* 4-7 */
4994000, 2499000, 1000000, 500000, /* 8-11 */
395500, 200000, 100000, 59890, /* 12-15 */
49920, 20000, 16660, 10000, /* 16-19 */
5000, 2500, 2500, /* 20-22 */
};
static unsigned int ad4116_sinc5_data_rates[] = {
12422360, 12422360, 12422360, 12422360, /* 0-3 */
10362690, 10362690, 7782100, 6290530, /* 4-7 */
5194800, 2496900, 1007600, 499900, /* 8-11 */
390600, 200300, 100000, 59750, /* 12-15 */
49840, 20000, 16650, 10000, /* 16-19 */
5000, 2500, 1250, /* 20-22 */
};
static const unsigned int ad7173_sinc5_data_rates[] = {
6211000, 6211000, 6211000, 6211000, 6211000, 6211000, 5181000, 4444000, /* 0-7 */
3115000, 2597000, 1007000, 503800, 381000, 200300, 100500, 59520, /* 8-15 */
@ -204,108 +248,214 @@ static const unsigned int ad7175_sinc5_data_rates[] = {
5000, /* 20 */
};
static const struct ad7173_device_info ad7173_device_info[] = {
[ID_AD7172_2] = {
.name = "ad7172-2",
.id = AD7172_2_ID,
.num_inputs = 5,
.num_channels = 4,
.num_configs = 4,
.num_gpios = 2,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
},
[ID_AD7172_4] = {
.name = "ad7172-4",
.id = AD7172_4_ID,
.num_inputs = 9,
.num_channels = 8,
.num_configs = 8,
.num_gpios = 4,
.has_temp = false,
.has_input_buf = true,
.has_ref2 = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
},
[ID_AD7173_8] = {
.name = "ad7173-8",
.id = AD7173_ID,
.num_inputs = 17,
.num_channels = 16,
.num_configs = 8,
.num_gpios = 4,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.has_ref2 = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
},
[ID_AD7175_2] = {
.name = "ad7175-2",
.id = AD7175_2_ID,
.num_inputs = 5,
.num_channels = 4,
.num_configs = 4,
.num_gpios = 2,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.clock = 16 * HZ_PER_MHZ,
.sinc5_data_rates = ad7175_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
},
[ID_AD7175_8] = {
.name = "ad7175-8",
.id = AD7175_8_ID,
.num_inputs = 17,
.num_channels = 16,
.num_configs = 8,
.num_gpios = 4,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.has_ref2 = true,
.clock = 16 * HZ_PER_MHZ,
.sinc5_data_rates = ad7175_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
},
[ID_AD7176_2] = {
.name = "ad7176-2",
.id = AD7176_ID,
.num_inputs = 5,
.num_channels = 4,
.num_configs = 4,
.num_gpios = 2,
.has_temp = false,
.has_input_buf = false,
.has_int_ref = true,
.clock = 16 * HZ_PER_MHZ,
.sinc5_data_rates = ad7175_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
},
[ID_AD7177_2] = {
.name = "ad7177-2",
.id = AD7177_ID,
.num_inputs = 5,
.num_channels = 4,
.num_configs = 4,
.num_gpios = 2,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.clock = 16 * HZ_PER_MHZ,
.odr_start_value = AD7177_ODR_START_VALUE,
.sinc5_data_rates = ad7175_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
},
static unsigned int ad4111_current_channel_config[] = {
/* Ain sel: pos neg */
0x1E8, /* 15:IIN0+ 8:IIN0 */
0x1C9, /* 14:IIN1+ 9:IIN1 */
0x1AA, /* 13:IIN2+ 10:IIN2 */
0x18B, /* 12:IIN3+ 11:IIN3 */
};
static const struct ad7173_device_info ad4111_device_info = {
.name = "ad4111",
.id = AD4111_ID,
.num_voltage_in_div = 8,
.num_channels = 16,
.num_configs = 8,
.num_voltage_in = 8,
.num_gpios = 2,
.higher_gpio_bits = true,
.has_temp = true,
.has_vincom_input = true,
.has_input_buf = true,
.has_current_inputs = true,
.has_int_ref = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
};
static const struct ad7173_device_info ad4112_device_info = {
.name = "ad4112",
.id = AD4112_ID,
.num_voltage_in_div = 8,
.num_channels = 16,
.num_configs = 8,
.num_voltage_in = 8,
.num_gpios = 2,
.higher_gpio_bits = true,
.has_vincom_input = true,
.has_temp = true,
.has_input_buf = true,
.has_current_inputs = true,
.has_int_ref = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
};
static const struct ad7173_device_info ad4114_device_info = {
.name = "ad4114",
.id = AD4114_ID,
.num_voltage_in_div = 16,
.num_channels = 16,
.num_configs = 8,
.num_voltage_in = 16,
.num_gpios = 4,
.higher_gpio_bits = true,
.has_vincom_input = true,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
};
static const struct ad7173_device_info ad4115_device_info = {
.name = "ad4115",
.id = AD4115_ID,
.num_voltage_in_div = 16,
.num_channels = 16,
.num_configs = 8,
.num_voltage_in = 16,
.num_gpios = 4,
.higher_gpio_bits = true,
.has_vincom_input = true,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.clock = 8 * HZ_PER_MHZ,
.sinc5_data_rates = ad4115_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad4115_sinc5_data_rates),
};
static const struct ad7173_device_info ad4116_device_info = {
.name = "ad4116",
.id = AD4116_ID,
.num_voltage_in_div = 11,
.num_channels = 16,
.num_configs = 8,
.num_voltage_in = 16,
.num_gpios = 4,
.higher_gpio_bits = true,
.has_vincom_input = true,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.clock = 4 * HZ_PER_MHZ,
.sinc5_data_rates = ad4116_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad4116_sinc5_data_rates),
};
static const struct ad7173_device_info ad7172_2_device_info = {
.name = "ad7172-2",
.id = AD7172_2_ID,
.num_voltage_in = 5,
.num_channels = 4,
.num_configs = 4,
.num_gpios = 2,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.has_pow_supply_monitoring = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
};
static const struct ad7173_device_info ad7172_4_device_info = {
.name = "ad7172-4",
.id = AD7172_4_ID,
.num_voltage_in = 9,
.num_channels = 8,
.num_configs = 8,
.num_gpios = 4,
.has_input_buf = true,
.has_ref2 = true,
.has_pow_supply_monitoring = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
};
static const struct ad7173_device_info ad7173_8_device_info = {
.name = "ad7173-8",
.id = AD7173_ID,
.num_voltage_in = 17,
.num_channels = 16,
.num_configs = 8,
.num_gpios = 4,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.has_ref2 = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
};
static const struct ad7173_device_info ad7175_2_device_info = {
.name = "ad7175-2",
.id = AD7175_2_ID,
.num_voltage_in = 5,
.num_channels = 4,
.num_configs = 4,
.num_gpios = 2,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.has_pow_supply_monitoring = true,
.clock = 16 * HZ_PER_MHZ,
.sinc5_data_rates = ad7175_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
};
static const struct ad7173_device_info ad7175_8_device_info = {
.name = "ad7175-8",
.id = AD7175_8_ID,
.num_voltage_in = 17,
.num_channels = 16,
.num_configs = 8,
.num_gpios = 4,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.has_ref2 = true,
.has_pow_supply_monitoring = true,
.clock = 16 * HZ_PER_MHZ,
.sinc5_data_rates = ad7175_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
};
static const struct ad7173_device_info ad7176_2_device_info = {
.name = "ad7176-2",
.id = AD7176_ID,
.num_voltage_in = 5,
.num_channels = 4,
.num_configs = 4,
.num_gpios = 2,
.has_int_ref = true,
.clock = 16 * HZ_PER_MHZ,
.sinc5_data_rates = ad7175_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
};
static const struct ad7173_device_info ad7177_2_device_info = {
.name = "ad7177-2",
.id = AD7177_ID,
.num_voltage_in = 5,
.num_channels = 4,
.num_configs = 4,
.num_gpios = 2,
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.has_pow_supply_monitoring = true,
.clock = 16 * HZ_PER_MHZ,
.odr_start_value = AD7177_ODR_START_VALUE,
.sinc5_data_rates = ad7175_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
};
static const char *const ad7173_ref_sel_str[] = {
@ -347,6 +497,15 @@ static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
return 0;
}
static int ad4111_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
unsigned int offset, unsigned int *reg,
unsigned int *mask)
{
*mask = AD4111_GPO01_DATA(offset);
*reg = base;
return 0;
}
static void ad7173_gpio_disable(void *data)
{
struct ad7173_state *st = data;
@ -379,7 +538,10 @@ static int ad7173_gpio_init(struct ad7173_state *st)
gpio_regmap.regmap = st->reg_gpiocon_regmap;
gpio_regmap.ngpio = st->info->num_gpios;
gpio_regmap.reg_set_base = AD7173_REG_GPIO;
gpio_regmap.reg_mask_xlate = ad7173_mask_xlate;
if (st->info->higher_gpio_bits)
gpio_regmap.reg_mask_xlate = ad4111_mask_xlate;
else
gpio_regmap.reg_mask_xlate = ad7173_mask_xlate;
st->gpio_regmap = devm_gpio_regmap_register(dev, &gpio_regmap);
ret = PTR_ERR_OR_ZERO(st->gpio_regmap);
@ -569,10 +731,16 @@ static int ad7173_disable_all(struct ad_sigma_delta *sd)
return 0;
}
static int ad7173_disable_one(struct ad_sigma_delta *sd, unsigned int chan)
{
return ad_sd_write_reg(sd, AD7173_REG_CH(chan), 2, 0);
}
static struct ad_sigma_delta_info ad7173_sigma_delta_info = {
.set_channel = ad7173_set_channel,
.append_status = ad7173_append_status,
.disable_all = ad7173_disable_all,
.disable_one = ad7173_disable_one,
.set_mode = ad7173_set_mode,
.has_registers = true,
.addr_shift = 0,
@ -668,25 +836,35 @@ static int ad7173_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
/* disable channel after single conversion */
ret = ad_sd_write_reg(&st->sd, AD7173_REG_CH(chan->address), 2, 0);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_TEMP) {
switch (chan->type) {
case IIO_TEMP:
temp = AD7173_VOLTAGE_INT_REF_uV * MILLI;
temp /= AD7173_TEMP_SENSIIVITY_uV_per_C;
*val = temp;
*val2 = chan->scan_type.realbits;
} else {
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_VOLTAGE:
*val = ad7173_get_ref_voltage_milli(st, ch->cfg.ref_sel);
*val2 = chan->scan_type.realbits - !!(ch->cfg.bipolar);
if (chan->channel < st->info->num_voltage_in_div)
*val *= AD4111_DIVIDER_RATIO;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CURRENT:
*val = ad7173_get_ref_voltage_milli(st, ch->cfg.ref_sel);
*val /= AD4111_SHUNT_RESISTOR_OHM;
*val2 = chan->scan_type.realbits - ch->cfg.bipolar;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
if (chan->type == IIO_TEMP) {
switch (chan->type) {
case IIO_TEMP:
/* 0 Kelvin -> raw sample */
temp = -ABSOLUTE_ZERO_MILLICELSIUS;
temp *= AD7173_TEMP_SENSIIVITY_uV_per_C;
@ -695,10 +873,14 @@ static int ad7173_read_raw(struct iio_dev *indio_dev,
AD7173_VOLTAGE_INT_REF_uV *
MILLI);
*val = -temp;
} else {
return IIO_VAL_INT;
case IIO_VOLTAGE:
case IIO_CURRENT:
*val = -BIT(chan->scan_type.realbits - 1);
return IIO_VAL_INT;
default:
return -EINVAL;
}
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
reg = st->channels[chan->address].cfg.odr;
@ -725,6 +907,21 @@ static int ad7173_write_raw(struct iio_dev *indio_dev,
return ret;
switch (info) {
/*
* This attribute sets the sampling frequency for each channel individually.
* There are no issues for raw or buffered reads of an individual channel.
*
* When multiple channels are enabled in buffered mode, the effective
* sampling rate of a channel is lowered in correlation to the number
* of channels enabled and the sampling rate of the other channels.
*
* Example: 3 channels enabled with rates CH1:6211sps CH2,CH3:10sps
* While the reading of CH1 takes only 0.16ms, the reading of CH2 and CH3
* will take 100ms each.
*
* This will cause the reading of CH1 to be actually done once every
* 200.16ms, an effective rate of 4.99sps.
*/
case IIO_CHAN_INFO_SAMP_FREQ:
freq = val * MILLI + val2 / MILLI;
for (i = st->info->odr_start_value; i < st->info->num_sinc5_data_rates - 1; i++)
@ -904,14 +1101,110 @@ static int ad7173_register_clk_provider(struct iio_dev *indio_dev)
&st->int_clk_hw);
}
static int ad4111_validate_current_ain(struct ad7173_state *st,
const unsigned int ain[AD7173_NO_AINS_PER_CHANNEL])
{
struct device *dev = &st->sd.spi->dev;
if (!st->info->has_current_inputs)
return dev_err_probe(dev, -EINVAL,
"Model %s does not support current channels\n",
st->info->name);
if (ain[0] >= ARRAY_SIZE(ad4111_current_channel_config))
return dev_err_probe(dev, -EINVAL,
"For current channels single-channel must be <[0-3]>\n");
return 0;
}
static int ad7173_validate_voltage_ain_inputs(struct ad7173_state *st,
unsigned int ain0, unsigned int ain1)
{
struct device *dev = &st->sd.spi->dev;
bool special_input0, special_input1;
/* (AVDD1-AVSS)/5 power supply monitoring */
if (ain0 == AD7173_AIN_POW_MON_POS && ain1 == AD7173_AIN_POW_MON_NEG &&
st->info->has_pow_supply_monitoring)
return 0;
special_input0 = AD7173_IS_REF_INPUT(ain0) ||
(ain0 == AD4111_VINCOM_INPUT && st->info->has_vincom_input);
special_input1 = AD7173_IS_REF_INPUT(ain1) ||
(ain1 == AD4111_VINCOM_INPUT && st->info->has_vincom_input);
if ((ain0 >= st->info->num_voltage_in && !special_input0) ||
(ain1 >= st->info->num_voltage_in && !special_input1)) {
if (ain0 == AD4111_VINCOM_INPUT || ain1 == AD4111_VINCOM_INPUT)
return dev_err_probe(dev, -EINVAL,
"VINCOM not supported for %s\n", st->info->name);
return dev_err_probe(dev, -EINVAL,
"Input pin number out of range for pair (%d %d).\n",
ain0, ain1);
}
if (AD4111_IS_VINCOM_MISMATCH(ain0, ain1) ||
AD4111_IS_VINCOM_MISMATCH(ain1, ain0))
return dev_err_probe(dev, -EINVAL,
"VINCOM must be paired with inputs having divider.\n");
if (!special_input0 && !special_input1 &&
((ain0 >= st->info->num_voltage_in_div) !=
(ain1 >= st->info->num_voltage_in_div)))
return dev_err_probe(dev, -EINVAL,
"Both inputs must either have a voltage divider or not have: (%d %d).\n",
ain0, ain1);
return 0;
}
static int ad7173_validate_reference(struct ad7173_state *st, int ref_sel)
{
struct device *dev = &st->sd.spi->dev;
int ret;
if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF && !st->info->has_int_ref)
return dev_err_probe(dev, -EINVAL,
"Internal reference is not available on current model.\n");
if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && !st->info->has_ref2)
return dev_err_probe(dev, -EINVAL,
"External reference 2 is not available on current model.\n");
ret = ad7173_get_ref_voltage_milli(st, ref_sel);
if (ret < 0)
return dev_err_probe(dev, ret, "Cannot use reference %u\n",
ref_sel);
return 0;
}
static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
{
struct ad7173_channel *chans_st_arr, *chan_st_priv;
struct ad7173_state *st = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
struct iio_chan_spec *chan_arr, *chan;
unsigned int ain[2], chan_index = 0;
int ref_sel, ret;
unsigned int ain[AD7173_NO_AINS_PER_CHANNEL], chan_index = 0;
int ref_sel, ret, num_channels;
num_channels = device_get_child_node_count(dev);
if (st->info->has_temp)
num_channels++;
if (num_channels == 0)
return dev_err_probe(dev, -ENODATA, "No channels specified\n");
if (num_channels > st->info->num_channels)
return dev_err_probe(dev, -EINVAL,
"Too many channels specified. Maximum is %d, not including temperature channel if supported.\n",
st->info->num_channels);
indio_dev->num_channels = num_channels;
st->num_channels = num_channels;
chan_arr = devm_kcalloc(dev, sizeof(*indio_dev->channels),
st->num_channels, GFP_KERNEL);
@ -941,18 +1234,41 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
}
device_for_each_child_node_scoped(dev, child) {
bool is_current_chan = false;
chan = &chan_arr[chan_index];
*chan = ad7173_channel_template;
chan_st_priv = &chans_st_arr[chan_index];
ret = fwnode_property_read_u32_array(child, "diff-channels",
ain, ARRAY_SIZE(ain));
if (ret)
return ret;
if (ret) {
ret = fwnode_property_read_u32(child, "single-channel",
ain);
if (ret)
return dev_err_probe(dev, ret,
"Channel must define one of diff-channels or single-channel.\n");
if (ain[0] >= st->info->num_inputs ||
ain[1] >= st->info->num_inputs)
return dev_err_probe(dev, -EINVAL,
"Input pin number out of range for pair (%d %d).\n",
ain[0], ain[1]);
is_current_chan = fwnode_property_read_bool(child, "adi,current-channel");
} else {
chan->differential = true;
}
if (is_current_chan) {
ret = ad4111_validate_current_ain(st, ain);
if (ret)
return ret;
} else {
if (!chan->differential) {
ret = fwnode_property_read_u32(child,
"common-mode-channel", ain + 1);
if (ret)
return dev_err_probe(dev, ret,
"common-mode-channel must be defined for single-ended channels.\n");
}
ret = ad7173_validate_voltage_ain_inputs(st, ain[0], ain[1]);
if (ret)
return ret;
}
ret = fwnode_property_match_property_string(child,
"adi,reference-select",
@ -963,32 +1279,17 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
else
ref_sel = ret;
if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF &&
!st->info->has_int_ref)
return dev_err_probe(dev, -EINVAL,
"Internal reference is not available on current model.\n");
if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && !st->info->has_ref2)
return dev_err_probe(dev, -EINVAL,
"External reference 2 is not available on current model.\n");
ret = ad7173_get_ref_voltage_milli(st, ref_sel);
if (ret < 0)
return dev_err_probe(dev, ret,
"Cannot use reference %u\n", ref_sel);
ret = ad7173_validate_reference(st, ref_sel);
if (ret)
return ret;
if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF)
st->adc_mode |= AD7173_ADC_MODE_REF_EN;
chan_st_priv->cfg.ref_sel = ref_sel;
*chan = ad7173_channel_template;
chan->address = chan_index;
chan->scan_index = chan_index;
chan->channel = ain[0];
chan->channel2 = ain[1];
chan->differential = true;
chan_st_priv->ain = AD7173_CH_ADDRESS(ain[0], ain[1]);
chan_st_priv->chan_reg = chan_index;
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
chan_st_priv->cfg.odr = 0;
@ -997,6 +1298,17 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
if (chan_st_priv->cfg.bipolar)
chan->info_mask_separate |= BIT(IIO_CHAN_INFO_OFFSET);
if (is_current_chan) {
chan->type = IIO_CURRENT;
chan->differential = false;
chan->channel2 = 0;
chan_st_priv->ain = ad4111_current_channel_config[ain[0]];
} else {
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
chan->channel2 = ain[1];
chan_st_priv->ain = AD7173_CH_ADDRESS(ain[0], ain[1]);
}
chan_index++;
}
return 0;
@ -1006,7 +1318,6 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev)
{
struct ad7173_state *st = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
unsigned int num_channels;
int ret;
st->regulators[0].supply = ad7173_ref_sel_str[AD7173_SETUP_REF_SEL_EXT_REF];
@ -1065,16 +1376,6 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev)
ad7173_sigma_delta_info.irq_line = ret;
num_channels = device_get_child_node_count(dev);
if (st->info->has_temp)
num_channels++;
if (num_channels == 0)
return dev_err_probe(dev, -ENODATA, "No channels specified\n");
indio_dev->num_channels = num_channels;
st->num_channels = num_channels;
return ad7173_fw_parse_channel_config(indio_dev);
}
@ -1134,32 +1435,35 @@ static int ad7173_probe(struct spi_device *spi)
}
static const struct of_device_id ad7173_of_match[] = {
{ .compatible = "adi,ad7172-2",
.data = &ad7173_device_info[ID_AD7172_2]},
{ .compatible = "adi,ad7172-4",
.data = &ad7173_device_info[ID_AD7172_4]},
{ .compatible = "adi,ad7173-8",
.data = &ad7173_device_info[ID_AD7173_8]},
{ .compatible = "adi,ad7175-2",
.data = &ad7173_device_info[ID_AD7175_2]},
{ .compatible = "adi,ad7175-8",
.data = &ad7173_device_info[ID_AD7175_8]},
{ .compatible = "adi,ad7176-2",
.data = &ad7173_device_info[ID_AD7176_2]},
{ .compatible = "adi,ad7177-2",
.data = &ad7173_device_info[ID_AD7177_2]},
{ .compatible = "ad4111", .data = &ad4111_device_info },
{ .compatible = "ad4112", .data = &ad4112_device_info },
{ .compatible = "ad4114", .data = &ad4114_device_info },
{ .compatible = "ad4115", .data = &ad4115_device_info },
{ .compatible = "ad4116", .data = &ad4116_device_info },
{ .compatible = "adi,ad7172-2", .data = &ad7172_2_device_info },
{ .compatible = "adi,ad7172-4", .data = &ad7172_4_device_info },
{ .compatible = "adi,ad7173-8", .data = &ad7173_8_device_info },
{ .compatible = "adi,ad7175-2", .data = &ad7175_2_device_info },
{ .compatible = "adi,ad7175-8", .data = &ad7175_8_device_info },
{ .compatible = "adi,ad7176-2", .data = &ad7176_2_device_info },
{ .compatible = "adi,ad7177-2", .data = &ad7177_2_device_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad7173_of_match);
static const struct spi_device_id ad7173_id_table[] = {
{ "ad7172-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7172_2]},
{ "ad7172-4", (kernel_ulong_t)&ad7173_device_info[ID_AD7172_4]},
{ "ad7173-8", (kernel_ulong_t)&ad7173_device_info[ID_AD7173_8]},
{ "ad7175-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7175_2]},
{ "ad7175-8", (kernel_ulong_t)&ad7173_device_info[ID_AD7175_8]},
{ "ad7176-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7176_2]},
{ "ad7177-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7177_2]},
{ "ad4111", (kernel_ulong_t)&ad4111_device_info },
{ "ad4112", (kernel_ulong_t)&ad4112_device_info },
{ "ad4114", (kernel_ulong_t)&ad4114_device_info },
{ "ad4115", (kernel_ulong_t)&ad4115_device_info },
{ "ad4116", (kernel_ulong_t)&ad4116_device_info },
{ "ad7172-2", (kernel_ulong_t)&ad7172_2_device_info },
{ "ad7172-4", (kernel_ulong_t)&ad7172_4_device_info },
{ "ad7173-8", (kernel_ulong_t)&ad7173_8_device_info },
{ "ad7175-2", (kernel_ulong_t)&ad7175_2_device_info },
{ "ad7175-8", (kernel_ulong_t)&ad7175_8_device_info },
{ "ad7176-2", (kernel_ulong_t)&ad7176_2_device_info },
{ "ad7177-2", (kernel_ulong_t)&ad7177_2_device_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7173_id_table);
@ -1177,5 +1481,5 @@ module_spi_driver(ad7173_driver);
MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafo.de>");
MODULE_AUTHOR("Dumitru Ceclan <dumitru.ceclan@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7172/AD7173/AD7175/AD7176 ADC driver");
MODULE_DESCRIPTION("Analog Devices AD7173 and similar ADC driver");
MODULE_LICENSE("GPL");

View File

@ -200,8 +200,6 @@ struct ad7192_chip_info {
struct ad7192_state {
const struct ad7192_chip_info *chip_info;
struct regulator *avdd;
struct regulator *vref;
struct clk *mclk;
u16 int_vref_mv;
u32 aincom_mv;
@ -1189,24 +1187,17 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
},
};
static void ad7192_reg_disable(void *reg)
{
regulator_disable(reg);
}
static int ad7192_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct ad7192_state *st;
struct iio_dev *indio_dev;
struct regulator *aincom;
int ret;
int ret, avdd_mv;
if (!spi->irq) {
dev_err(&spi->dev, "no IRQ?\n");
return -ENODEV;
}
if (!spi->irq)
return dev_err_probe(dev, -ENODEV, "Failed to get IRQ\n");
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@ -1219,74 +1210,49 @@ static int ad7192_probe(struct spi_device *spi)
* 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");
ret = devm_regulator_get_enable_read_voltage(dev, "aincom");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(dev, ret, "Failed to get AINCOM voltage\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");
st->aincom_mv = ret == -ENODEV ? 0 : ret / MILLI;
ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, aincom);
if (ret)
return ret;
/* AVDD can optionally be used as reference voltage */
ret = devm_regulator_get_enable_read_voltage(dev, "avdd");
if (ret == -ENODEV || ret == -EINVAL) {
int ret2;
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;
/*
* We get -EINVAL if avdd is a supply with unknown voltage. We
* still need to enable it since it is also a power supply.
*/
ret2 = devm_regulator_get_enable(dev, "avdd");
if (ret2)
return dev_err_probe(dev, ret2,
"Failed to enable AVDD supply\n");
} else if (ret < 0) {
return dev_err_probe(dev, ret, "Failed to get AVDD voltage\n");
}
st->avdd = devm_regulator_get(&spi->dev, "avdd");
if (IS_ERR(st->avdd))
return PTR_ERR(st->avdd);
avdd_mv = ret == -ENODEV || ret == -EINVAL ? 0 : ret / MILLI;
ret = regulator_enable(st->avdd);
if (ret) {
dev_err(&spi->dev, "Failed to enable specified AVdd supply\n");
ret = devm_regulator_get_enable(dev, "dvdd");
if (ret)
return dev_err_probe(dev, ret, "Failed to enable specified DVdd supply\n");
/*
* This is either REFIN1 or REFIN2 depending on adi,refin2-pins-enable.
* If this supply is not present, fall back to AVDD as reference.
*/
ret = devm_regulator_get_enable_read_voltage(dev, "vref");
if (ret == -ENODEV) {
if (avdd_mv == 0)
return dev_err_probe(dev, -ENODEV,
"No reference voltage available\n");
} else if (ret < 0) {
return ret;
}
ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->avdd);
if (ret)
return ret;
ret = devm_regulator_get_enable(&spi->dev, "dvdd");
if (ret)
return dev_err_probe(&spi->dev, ret, "Failed to enable specified DVdd supply\n");
st->vref = devm_regulator_get_optional(&spi->dev, "vref");
if (IS_ERR(st->vref)) {
if (PTR_ERR(st->vref) != -ENODEV)
return PTR_ERR(st->vref);
ret = regulator_get_voltage(st->avdd);
if (ret < 0)
return dev_err_probe(&spi->dev, ret,
"Device tree error, AVdd voltage undefined\n");
} else {
ret = regulator_enable(st->vref);
if (ret) {
dev_err(&spi->dev, "Failed to enable specified Vref supply\n");
return ret;
}
ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->vref);
if (ret)
return ret;
ret = regulator_get_voltage(st->vref);
if (ret < 0)
return dev_err_probe(&spi->dev, ret,
"Device tree error, Vref voltage undefined\n");
}
st->int_vref_mv = ret / 1000;
st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI;
st->chip_info = spi_get_device_match_data(spi);
indio_dev->name = st->chip_info->name;
@ -1305,13 +1271,13 @@ static int ad7192_probe(struct spi_device *spi)
if (ret)
return ret;
ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev);
if (ret)
return ret;
st->fclk = AD7192_INT_FREQ_MHZ;
st->mclk = devm_clk_get_optional_enabled(&spi->dev, "mclk");
st->mclk = devm_clk_get_optional_enabled(dev, "mclk");
if (IS_ERR(st->mclk))
return PTR_ERR(st->mclk);
@ -1320,18 +1286,16 @@ static int ad7192_probe(struct spi_device *spi)
if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 ||
st->clock_sel == AD7192_CLK_EXT_MCLK2) {
st->fclk = clk_get_rate(st->mclk);
if (!ad7192_valid_external_frequency(st->fclk)) {
dev_err(&spi->dev,
"External clock frequency out of bounds\n");
return -EINVAL;
}
if (!ad7192_valid_external_frequency(st->fclk))
return dev_err_probe(dev, -EINVAL,
"External clock frequency out of bounds\n");
}
ret = ad7192_setup(indio_dev, &spi->dev);
ret = ad7192_setup(indio_dev, dev);
if (ret)
return ret;
return devm_iio_device_register(&spi->dev, indio_dev);
return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id ad7192_of_match[] = {

View File

@ -23,9 +23,10 @@
#include <linux/platform_data/ad7266.h>
#define AD7266_INTERNAL_REF_MV 2500
struct ad7266_state {
struct spi_device *spi;
struct regulator *reg;
unsigned long vref_mv;
struct spi_transfer single_xfer[3];
@ -379,11 +380,6 @@ static const char * const ad7266_gpio_labels[] = {
"ad0", "ad1", "ad2",
};
static void ad7266_reg_disable(void *reg)
{
regulator_disable(reg);
}
static int ad7266_probe(struct spi_device *spi)
{
struct ad7266_platform_data *pdata = spi->dev.platform_data;
@ -398,28 +394,11 @@ static int ad7266_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
st->reg = devm_regulator_get_optional(&spi->dev, "vref");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
if (ret < 0 && ret != -ENODEV)
return ret;
ret = devm_add_action_or_reset(&spi->dev, ad7266_reg_disable, st->reg);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
return ret;
st->vref_mv = ret / 1000;
} else {
/* Any other error indicates that the regulator does exist */
if (PTR_ERR(st->reg) != -ENODEV)
return PTR_ERR(st->reg);
/* Use internal reference */
st->vref_mv = 2500;
}
st->vref_mv = ret == -ENODEV ? AD7266_INTERNAL_REF_MV : ret / 1000;
if (pdata) {
st->fixed_addr = pdata->fixed_addr;

View File

@ -17,6 +17,8 @@
#define ADI_VENDOR_ID 0x0018
#define AD7292_INTERNAL_REF_MV 1250
/* AD7292 registers definition */
#define AD7292_REG_VENDOR_ID 0x00
#define AD7292_REG_CONF_BANK 0x05
@ -79,7 +81,6 @@ static const struct iio_chan_spec ad7292_channels_diff[] = {
struct ad7292_state {
struct spi_device *spi;
struct regulator *reg;
unsigned short vref_mv;
__be16 d16 __aligned(IIO_DMA_MINALIGN);
@ -250,13 +251,6 @@ static const struct iio_info ad7292_info = {
.read_raw = ad7292_read_raw,
};
static void ad7292_regulator_disable(void *data)
{
struct ad7292_state *st = data;
regulator_disable(st->reg);
}
static int ad7292_probe(struct spi_device *spi)
{
struct ad7292_state *st;
@ -277,29 +271,11 @@ static int ad7292_probe(struct spi_device *spi)
return -EINVAL;
}
st->reg = devm_regulator_get_optional(&spi->dev, "vref");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret) {
dev_err(&spi->dev,
"Failed to enable external vref supply\n");
return ret;
}
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
if (ret < 0 && ret != -ENODEV)
return ret;
ret = devm_add_action_or_reset(&spi->dev,
ad7292_regulator_disable, st);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
return ret;
st->vref_mv = ret / 1000;
} else {
/* Use the internal voltage reference. */
st->vref_mv = 1250;
}
st->vref_mv = ret == -ENODEV ? AD7292_INTERNAL_REF_MV : ret / 1000;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;

View File

@ -152,7 +152,6 @@ struct ad7793_chip_info {
struct ad7793_state {
const struct ad7793_chip_info *chip_info;
struct regulator *reg;
u16 int_vref_mv;
u16 mode;
u16 conf;
@ -769,11 +768,6 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
},
};
static void ad7793_reg_disable(void *reg)
{
regulator_disable(reg);
}
static int ad7793_probe(struct spi_device *spi)
{
const struct ad7793_platform_data *pdata = spi->dev.platform_data;
@ -800,23 +794,11 @@ static int ad7793_probe(struct spi_device *spi)
ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info);
if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
st->reg = devm_regulator_get(&spi->dev, "refin");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "refin");
if (ret < 0)
return ret;
ret = devm_add_action_or_reset(&spi->dev, ad7793_reg_disable, st->reg);
if (ret)
return ret;
vref_mv = regulator_get_voltage(st->reg);
if (vref_mv < 0)
return vref_mv;
vref_mv /= 1000;
vref_mv = ret / 1000;
} else {
vref_mv = 1170; /* Build-in ref */
}

View File

@ -134,18 +134,12 @@ AD7944_DEFINE_CHIP_INFO(ad7985, ad7944, 16, 0);
/* fully differential */
AD7944_DEFINE_CHIP_INFO(ad7986, ad7986, 18, 1);
static void ad7944_unoptimize_msg(void *msg)
{
spi_unoptimize_message(msg);
}
static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc *adc,
const struct iio_chan_spec *chan)
{
unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns
: adc->timing_spec->conv_ns;
struct spi_transfer *xfers = adc->xfers;
int ret;
/*
* NB: can get better performance from some SPI controllers if we use
@ -175,11 +169,7 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc *
spi_message_init_with_transfers(&adc->msg, xfers, 3);
ret = spi_optimize_message(adc->spi, &adc->msg);
if (ret)
return ret;
return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg);
return devm_spi_optimize_message(dev, adc->spi, &adc->msg);
}
static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc,
@ -188,7 +178,6 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc
unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns
: adc->timing_spec->conv_ns;
struct spi_transfer *xfers = adc->xfers;
int ret;
/*
* NB: can get better performance from some SPI controllers if we use
@ -209,11 +198,7 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc
spi_message_init_with_transfers(&adc->msg, xfers, 2);
ret = spi_optimize_message(adc->spi, &adc->msg);
if (ret)
return ret;
return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg);
return devm_spi_optimize_message(dev, adc->spi, &adc->msg);
}
static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc,
@ -221,7 +206,6 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc
u32 n_chain_dev)
{
struct spi_transfer *xfers = adc->xfers;
int ret;
/*
* NB: SCLK has to be low before we toggle CS to avoid triggering the
@ -249,11 +233,7 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc
spi_message_init_with_transfers(&adc->msg, xfers, 2);
ret = spi_optimize_message(adc->spi, &adc->msg);
if (ret)
return ret;
return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg);
return devm_spi_optimize_message(dev, adc->spi, &adc->msg);
}
/**
@ -464,23 +444,17 @@ static const char * const ad7944_power_supplies[] = {
"avdd", "dvdd", "bvdd", "vio"
};
static void ad7944_ref_disable(void *ref)
{
regulator_disable(ref);
}
static int ad7944_probe(struct spi_device *spi)
{
const struct ad7944_chip_info *chip_info;
struct device *dev = &spi->dev;
struct iio_dev *indio_dev;
struct ad7944_adc *adc;
bool have_refin = false;
struct regulator *ref;
bool have_refin;
struct iio_chan_spec *chain_chan;
unsigned long *chain_scan_masks;
u32 n_chain_dev;
int ret;
int ret, ref_mv;
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
if (!indio_dev)
@ -531,47 +505,23 @@ static int ad7944_probe(struct spi_device *spi)
* - external reference: REF is connected, REFIN is not connected
*/
ref = devm_regulator_get_optional(dev, "ref");
if (IS_ERR(ref)) {
if (PTR_ERR(ref) != -ENODEV)
return dev_err_probe(dev, PTR_ERR(ref),
"failed to get REF supply\n");
ret = devm_regulator_get_enable_read_voltage(dev, "ref");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(dev, ret, "failed to get REF voltage\n");
ref = NULL;
}
ref_mv = ret == -ENODEV ? 0 : ret / 1000;
ret = devm_regulator_get_enable_optional(dev, "refin");
if (ret == 0)
have_refin = true;
else if (ret != -ENODEV)
return dev_err_probe(dev, ret,
"failed to get and enable REFIN supply\n");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(dev, ret, "failed to get REFIN voltage\n");
if (have_refin && ref)
have_refin = ret != -ENODEV;
if (have_refin && ref_mv)
return dev_err_probe(dev, -EINVAL,
"cannot have both refin and ref supplies\n");
if (ref) {
ret = regulator_enable(ref);
if (ret)
return dev_err_probe(dev, ret,
"failed to enable REF supply\n");
ret = devm_add_action_or_reset(dev, ad7944_ref_disable, ref);
if (ret)
return ret;
ret = regulator_get_voltage(ref);
if (ret < 0)
return dev_err_probe(dev, ret,
"failed to get REF voltage\n");
/* external reference */
adc->ref_mv = ret / 1000;
} else {
/* internal reference */
adc->ref_mv = AD7944_INTERNAL_REF_MV;
}
adc->ref_mv = ref_mv ?: AD7944_INTERNAL_REF_MV;
adc->cnv = devm_gpiod_get_optional(dev, "cnv", GPIOD_OUT_LOW);
if (IS_ERR(adc->cnv))

View File

@ -321,6 +321,7 @@ out:
sigma_delta->keep_cs_asserted = false;
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
ad_sigma_delta_disable_one(sigma_delta, chan->address);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->controller);
iio_device_release_direct_mode(indio_dev);

View File

@ -308,7 +308,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
st->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&axi_adc_regmap_config);
if (IS_ERR(st->regmap))
return PTR_ERR(st->regmap);
return dev_err_probe(&pdev->dev, PTR_ERR(st->regmap),
"failed to init register map\n");
expected_ver = device_get_match_data(&pdev->dev);
if (!expected_ver)
@ -316,7 +317,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
return dev_err_probe(&pdev->dev, PTR_ERR(clk),
"failed to get clock\n");
/*
* Force disable the core. Up to the frontend to enable us. And we can
@ -344,7 +346,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
ret = devm_iio_backend_register(&pdev->dev, &adi_axi_adc_generic, st);
if (ret)
return ret;
return dev_err_probe(&pdev->dev, ret,
"failed to register iio backend\n");
dev_info(&pdev->dev, "AXI ADC IP core (%d.%.2d.%c) probed\n",
ADI_AXI_PCORE_VER_MAJOR(ver),

View File

@ -108,7 +108,6 @@ struct adc_gain {
struct aspeed_adc_data {
struct device *dev;
const struct aspeed_adc_model_data *model_data;
struct regulator *regulator;
void __iomem *base;
spinlock_t clk_lock;
struct clk_hw *fixed_div_clk;
@ -404,13 +403,6 @@ static void aspeed_adc_power_down(void *data)
priv_data->base + ASPEED_REG_ENGINE_CONTROL);
}
static void aspeed_adc_reg_disable(void *data)
{
struct regulator *reg = data;
regulator_disable(reg);
}
static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
{
struct aspeed_adc_data *data = iio_priv(indio_dev);
@ -423,18 +415,14 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
}
adc_engine_control_reg_val =
readl(data->base + ASPEED_REG_ENGINE_CONTROL);
data->regulator = devm_regulator_get_optional(data->dev, "vref");
if (!IS_ERR(data->regulator)) {
ret = regulator_enable(data->regulator);
if (ret)
return ret;
ret = devm_add_action_or_reset(
data->dev, aspeed_adc_reg_disable, data->regulator);
if (ret)
return ret;
data->vref_mv = regulator_get_voltage(data->regulator);
/* Conversion from uV to mV */
data->vref_mv /= 1000;
ret = devm_regulator_get_enable_read_voltage(data->dev, "vref");
if (ret < 0 && ret != -ENODEV)
return ret;
if (ret != -ENODEV) {
data->vref_mv = ret / 1000;
if ((data->vref_mv >= 1550) && (data->vref_mv <= 2700))
writel(adc_engine_control_reg_val |
FIELD_PREP(
@ -453,8 +441,6 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
return -EOPNOTSUPP;
}
} else {
if (PTR_ERR(data->regulator) != -ENODEV)
return PTR_ERR(data->regulator);
data->vref_mv = 2500000;
of_property_read_u32(data->dev->of_node,
"aspeed,int-vref-microvolt",

View File

@ -991,9 +991,8 @@ static int axp20x_probe(struct platform_device *pdev)
regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask);
if (info->data->adc_en2_mask)
regmap_update_bits(info->regmap, AXP20X_ADC_EN2,
info->data->adc_en2_mask,
info->data->adc_en2_mask);
regmap_set_bits(info->regmap, AXP20X_ADC_EN2,
info->data->adc_en2_mask);
/* Configure ADCs rate */
info->data->adc_rate(info, 100);

View File

@ -247,8 +247,8 @@ static int axp288_adc_initialize(struct axp288_adc_info *info)
return ret;
/* Turn on the ADC for all channels except TS, leave TS as is */
return regmap_update_bits(info->regmap, AXP20X_ADC_EN1,
AXP288_ADC_EN_MASK, AXP288_ADC_EN_MASK);
return regmap_set_bits(info->regmap, AXP20X_ADC_EN1,
AXP288_ADC_EN_MASK);
}
static const struct iio_info axp288_adc_iio_info = {

View File

@ -357,8 +357,8 @@ static int iproc_adc_enable(struct iio_dev *indio_dev)
int ret;
/* Set i_amux = 3b'000, select channel 0 */
ret = regmap_update_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL,
IPROC_ADC_CHANNEL_SEL_MASK, 0);
ret = regmap_clear_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL,
IPROC_ADC_CHANNEL_SEL_MASK);
if (ret) {
dev_err(&indio_dev->dev,
"failed to write IPROC_ANALOG_CONTROL %d\n", ret);
@ -543,8 +543,8 @@ static int iproc_adc_probe(struct platform_device *pdev)
if (adc_priv->irqno < 0)
return adc_priv->irqno;
ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2,
IPROC_ADC_AUXIN_SCAN_ENA, 0);
ret = regmap_clear_bits(adc_priv->regmap, IPROC_REGCTL2,
IPROC_ADC_AUXIN_SCAN_ENA);
if (ret) {
dev_err(&pdev->dev, "failed to write IPROC_REGCTL2 %d\n", ret);
return ret;

View File

@ -129,8 +129,8 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
msecs_to_jiffies(1000));
/* Disable the interrupts */
regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS,
BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0);
regmap_clear_bits(priv->regmap, BERLIN2_SM_ADC_STATUS,
BERLIN2_SM_ADC_STATUS_INT_EN(channel));
if (ret == 0)
ret = -ETIMEDOUT;
@ -139,8 +139,8 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
return ret;
}
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_START, 0);
regmap_clear_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_START);
data = priv->data;
priv->data_available = false;
@ -180,8 +180,8 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
msecs_to_jiffies(1000));
/* Disable interrupts */
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS,
BERLIN2_SM_TSEN_STATUS_INT_EN, 0);
regmap_clear_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS,
BERLIN2_SM_TSEN_STATUS_INT_EN);
if (ret == 0)
ret = -ETIMEDOUT;
@ -190,8 +190,8 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
return ret;
}
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
BERLIN2_SM_TSEN_CTRL_START, 0);
regmap_clear_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
BERLIN2_SM_TSEN_CTRL_START);
data = priv->data;
priv->data_available = false;
@ -284,8 +284,7 @@ static const struct iio_info berlin2_adc_info = {
static void berlin2_adc_powerdown(void *regmap)
{
regmap_update_bits(regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_POWER, 0);
regmap_clear_bits(regmap, BERLIN2_SM_CTRL, BERLIN2_SM_CTRL_ADC_POWER);
}
@ -339,9 +338,8 @@ static int berlin2_adc_probe(struct platform_device *pdev)
indio_dev->num_channels = ARRAY_SIZE(berlin2_adc_channels);
/* Power up the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_POWER,
BERLIN2_SM_CTRL_ADC_POWER);
regmap_set_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_POWER);
ret = devm_add_action_or_reset(&pdev->dev, berlin2_adc_powerdown,
priv->regmap);

View File

@ -385,9 +385,8 @@ static irqreturn_t cpcap_adc_irq_thread(int irq, void *data)
struct cpcap_adc *ddata = iio_priv(indio_dev);
int error;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS,
CPCAP_BIT_ADTRIG_DIS);
error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS);
if (error)
return IRQ_NONE;
@ -424,23 +423,19 @@ static void cpcap_adc_setup_calibrate(struct cpcap_adc *ddata,
if (error)
return;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ATOX_PS_FACTOR |
CPCAP_BIT_ADC_PS_FACTOR1 |
CPCAP_BIT_ADC_PS_FACTOR0,
0);
error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ATOX_PS_FACTOR |
CPCAP_BIT_ADC_PS_FACTOR1 |
CPCAP_BIT_ADC_PS_FACTOR0);
if (error)
return;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS,
CPCAP_BIT_ADTRIG_DIS);
error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS);
if (error)
return;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ASC,
CPCAP_BIT_ASC);
error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, CPCAP_BIT_ASC);
if (error)
return;
@ -455,8 +450,8 @@ static void cpcap_adc_setup_calibrate(struct cpcap_adc *ddata,
dev_err(ddata->dev,
"Timeout waiting for calibration to complete\n");
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1,
CPCAP_BIT_CAL_MODE, 0);
error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC1,
CPCAP_BIT_CAL_MODE);
if (error)
return;
}
@ -602,26 +597,23 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata,
return;
if (req->timing == CPCAP_ADC_TIMING_IMM) {
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS,
CPCAP_BIT_ADTRIG_DIS);
error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS);
if (error)
return;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ASC,
CPCAP_BIT_ASC);
error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ASC);
if (error)
return;
} else {
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_ONESHOT,
CPCAP_BIT_ADTRIG_ONESHOT);
error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_ONESHOT);
if (error)
return;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS, 0);
error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS);
if (error)
return;
}

View File

@ -87,13 +87,13 @@ static irqreturn_t mx25_gcq_irq(int irq, void *data)
regmap_read(priv->regs, MX25_ADCQ_SR, &stats);
if (stats & MX25_ADCQ_SR_EOQ) {
regmap_update_bits(priv->regs, MX25_ADCQ_MR,
MX25_ADCQ_MR_EOQ_IRQ, MX25_ADCQ_MR_EOQ_IRQ);
regmap_set_bits(priv->regs, MX25_ADCQ_MR,
MX25_ADCQ_MR_EOQ_IRQ);
complete(&priv->completed);
}
/* Disable conversion queue run */
regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, 0);
regmap_clear_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS);
/* Acknowledge all possible irqs */
regmap_write(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR |
@ -115,11 +115,10 @@ static int mx25_gcq_get_raw_value(struct device *dev,
regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0,
MX25_ADCQ_ITEM(0, chan->channel));
regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ, 0);
regmap_clear_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ);
/* Trigger queue for one run */
regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS,
MX25_ADCQ_CR_FQS);
regmap_set_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS);
time_left = wait_for_completion_interruptible_timeout(
&priv->completed, MX25_GCQ_TIMEOUT);
@ -272,9 +271,8 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
MX25_ADCQ_CFG_REFN_MASK,
refp | refn);
}
regmap_update_bits(priv->regs, MX25_ADCQ_CR,
MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST,
MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST);
regmap_set_bits(priv->regs, MX25_ADCQ_CR,
MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST);
regmap_write(priv->regs, MX25_ADCQ_CR,
MX25_ADCQ_CR_PDMSK | MX25_ADCQ_CR_QSM_FQS);

View File

@ -80,7 +80,6 @@ struct hx711_data {
struct device *dev;
struct gpio_desc *gpiod_pd_sck;
struct gpio_desc *gpiod_dout;
struct regulator *reg_avdd;
int gain_set; /* gain set on device */
int gain_chan_a; /* gain for channel A */
struct mutex lock;
@ -465,10 +464,8 @@ static int hx711_probe(struct platform_device *pdev)
int i;
indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx711_data));
if (!indio_dev) {
dev_err(dev, "failed to allocate IIO device\n");
return -ENOMEM;
}
if (!indio_dev)
return dev_err_probe(dev, -ENOMEM, "failed to allocate IIO device\n");
hx711_data = iio_priv(indio_dev);
hx711_data->dev = dev;
@ -480,28 +477,20 @@ static int hx711_probe(struct platform_device *pdev)
* in the driver it is an output
*/
hx711_data->gpiod_pd_sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
if (IS_ERR(hx711_data->gpiod_pd_sck)) {
dev_err(dev, "failed to get sck-gpiod: err=%ld\n",
PTR_ERR(hx711_data->gpiod_pd_sck));
return PTR_ERR(hx711_data->gpiod_pd_sck);
}
if (IS_ERR(hx711_data->gpiod_pd_sck))
return dev_err_probe(dev, PTR_ERR(hx711_data->gpiod_pd_sck),
"failed to get sck-gpiod\n");
/*
* DOUT stands for serial data output of HX711
* for the driver it is an input
*/
hx711_data->gpiod_dout = devm_gpiod_get(dev, "dout", GPIOD_IN);
if (IS_ERR(hx711_data->gpiod_dout)) {
dev_err(dev, "failed to get dout-gpiod: err=%ld\n",
PTR_ERR(hx711_data->gpiod_dout));
return PTR_ERR(hx711_data->gpiod_dout);
}
if (IS_ERR(hx711_data->gpiod_dout))
return dev_err_probe(dev, PTR_ERR(hx711_data->gpiod_dout),
"failed to get dout-gpiod\n");
hx711_data->reg_avdd = devm_regulator_get(dev, "avdd");
if (IS_ERR(hx711_data->reg_avdd))
return PTR_ERR(hx711_data->reg_avdd);
ret = regulator_enable(hx711_data->reg_avdd);
ret = devm_regulator_get_enable_read_voltage(dev, "avdd");
if (ret < 0)
return ret;
@ -517,9 +506,6 @@ static int hx711_probe(struct platform_device *pdev)
* approximately to fit into a 32 bit number:
* 1 LSB = (AVDD * 100) / GAIN / 1678 [10^-9 mV]
*/
ret = regulator_get_voltage(hx711_data->reg_avdd);
if (ret < 0)
goto error_regulator;
/* we need 10^-9 mV */
ret *= 100;
@ -547,51 +533,24 @@ static int hx711_probe(struct platform_device *pdev)
hx711_data->data_ready_delay_ns =
1000000000 / hx711_data->clock_frequency;
platform_set_drvdata(pdev, indio_dev);
indio_dev->name = "hx711";
indio_dev->info = &hx711_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = hx711_chan_spec;
indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec);
ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
hx711_trigger, NULL);
if (ret < 0) {
dev_err(dev, "setup of iio triggered buffer failed\n");
goto error_regulator;
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
hx711_trigger, NULL);
if (ret < 0)
return dev_err_probe(dev, ret,
"setup of iio triggered buffer failed\n");
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(dev, "Couldn't register the device\n");
goto error_buffer;
}
ret = devm_iio_device_register(dev, indio_dev);
if (ret < 0)
return dev_err_probe(dev, ret, "Couldn't register the device\n");
return 0;
error_buffer:
iio_triggered_buffer_cleanup(indio_dev);
error_regulator:
regulator_disable(hx711_data->reg_avdd);
return ret;
}
static void hx711_remove(struct platform_device *pdev)
{
struct hx711_data *hx711_data;
struct iio_dev *indio_dev;
indio_dev = platform_get_drvdata(pdev);
hx711_data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(hx711_data->reg_avdd);
}
static const struct of_device_id of_hx711_match[] = {
@ -603,7 +562,6 @@ MODULE_DEVICE_TABLE(of, of_hx711_match);
static struct platform_driver hx711_driver = {
.probe = hx711_probe,
.remove_new = hx711_remove,
.driver = {
.name = "hx711-gpio",
.of_match_table = of_hx711_match,

View File

@ -1046,8 +1046,7 @@ static void ina2xx_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
/* Powerdown */
ret = regmap_update_bits(chip->regmap, INA2XX_CONFIG,
INA2XX_MODE_MASK, 0);
ret = regmap_clear_bits(chip->regmap, INA2XX_CONFIG, INA2XX_MODE_MASK);
if (ret)
dev_warn(&client->dev, "Failed to power down device (%pe)\n",
ERR_PTR(ret));

View File

@ -81,8 +81,8 @@ static int mrfld_adc_single_conv(struct iio_dev *indio_dev,
reinit_completion(&adc->completion);
regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0);
regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0);
regmap_clear_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL);
regmap_clear_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC);
ret = regmap_read_poll_timeout(regmap, BCOVE_GPADCREQ, req,
!(req & BCOVE_GPADCREQ_BUSY),

View File

@ -16,6 +16,7 @@
#include <linux/regulator/consumer.h>
#define LTC2309_ADC_RESOLUTION 12
#define LTC2309_INTERNAL_REF_MV 4096
#define LTC2309_DIN_CH_MASK GENMASK(7, 4)
#define LTC2309_DIN_SDN BIT(7)
@ -29,14 +30,12 @@
* struct ltc2309 - internal device data structure
* @dev: Device reference
* @client: I2C reference
* @vref: External reference source
* @lock: Lock to serialize data access
* @vref_mv: Internal voltage reference
*/
struct ltc2309 {
struct device *dev;
struct i2c_client *client;
struct regulator *vref;
struct mutex lock; /* serialize data access */
int vref_mv;
};
@ -104,7 +103,7 @@ static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309,
unsigned long address, int *val)
{
int ret;
u16 buf;
__be16 buf;
u8 din;
din = FIELD_PREP(LTC2309_DIN_CH_MASK, address & 0x0f) |
@ -157,11 +156,6 @@ static const struct iio_info ltc2309_info = {
.read_raw = ltc2309_read_raw,
};
static void ltc2309_regulator_disable(void *regulator)
{
regulator_disable(regulator);
}
static int ltc2309_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
@ -175,7 +169,6 @@ static int ltc2309_probe(struct i2c_client *client)
ltc2309 = iio_priv(indio_dev);
ltc2309->dev = &indio_dev->dev;
ltc2309->client = client;
ltc2309->vref_mv = 4096; /* Default to the internal ref */
indio_dev->name = "ltc2309";
indio_dev->modes = INDIO_DIRECT_MODE;
@ -183,36 +176,12 @@ static int ltc2309_probe(struct i2c_client *client)
indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels);
indio_dev->info = &ltc2309_info;
ltc2309->vref = devm_regulator_get_optional(&client->dev, "vref");
if (IS_ERR(ltc2309->vref)) {
ret = PTR_ERR(ltc2309->vref);
if (ret == -ENODEV)
ltc2309->vref = NULL;
else
return ret;
}
ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(ltc2309->dev, ret,
"failed to get vref voltage\n");
if (ltc2309->vref) {
ret = regulator_enable(ltc2309->vref);
if (ret)
return dev_err_probe(ltc2309->dev, ret,
"failed to enable vref\n");
ret = devm_add_action_or_reset(ltc2309->dev,
ltc2309_regulator_disable,
ltc2309->vref);
if (ret) {
return dev_err_probe(ltc2309->dev, ret,
"failed to add regulator_disable action: %d\n",
ret);
}
ret = regulator_get_voltage(ltc2309->vref);
if (ret < 0)
return ret;
ltc2309->vref_mv = ret / 1000;
}
ltc2309->vref_mv = ret == -ENODEV ? LTC2309_INTERNAL_REF_MV : ret / 1000;
mutex_init(&ltc2309->lock);

View File

@ -1561,18 +1561,12 @@ static const struct of_device_id max1363_of_match[] = {
};
MODULE_DEVICE_TABLE(of, max1363_of_match);
static void max1363_reg_disable(void *reg)
{
regulator_disable(reg);
}
static int max1363_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
struct max1363_state *st;
struct iio_dev *indio_dev;
struct regulator *vref;
indio_dev = devm_iio_device_alloc(&client->dev,
sizeof(struct max1363_state));
@ -1589,26 +1583,12 @@ static int max1363_probe(struct i2c_client *client)
st->chip_info = i2c_get_match_data(client);
st->client = client;
st->vref_uv = st->chip_info->int_vref_mv * 1000;
vref = devm_regulator_get_optional(&client->dev, "vref");
if (!IS_ERR(vref)) {
int vref_uv;
ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref");
if (ret < 0 && ret != -ENODEV)
return ret;
ret = regulator_enable(vref);
if (ret)
return ret;
ret = devm_add_action_or_reset(&client->dev, max1363_reg_disable, vref);
if (ret)
return ret;
st->vref = vref;
vref_uv = regulator_get_voltage(vref);
if (vref_uv <= 0)
return -EINVAL;
st->vref_uv = vref_uv;
}
st->vref_uv = ret == -ENODEV ? st->chip_info->int_vref_mv * 1000 : ret;
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
st->send = i2c_master_send;

View File

@ -546,35 +546,31 @@ static void meson_sar_adc_start_sample_engine(struct iio_dev *indio_dev)
reinit_completion(&priv->done);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_FIFO_IRQ_EN,
MESON_SAR_ADC_REG0_FIFO_IRQ_EN);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_FIFO_IRQ_EN);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE,
MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_SAMPLING_START,
MESON_SAR_ADC_REG0_SAMPLING_START);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_SAMPLING_START);
}
static void meson_sar_adc_stop_sample_engine(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_FIFO_IRQ_EN, 0);
regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_FIFO_IRQ_EN);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_SAMPLING_STOP,
MESON_SAR_ADC_REG0_SAMPLING_STOP);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_SAMPLING_STOP);
/* wait until all modules are stopped */
meson_sar_adc_wait_busy_clear(indio_dev);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0);
regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
}
static int meson_sar_adc_lock(struct iio_dev *indio_dev)
@ -586,9 +582,8 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
if (priv->param->has_bl30_integration) {
/* prevent BL30 from using the SAR ADC while we are using it */
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY);
udelay(1);
@ -614,8 +609,8 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
if (priv->param->has_bl30_integration)
/* allow BL30 to use the SAR ADC again */
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY);
mutex_unlock(&priv->lock);
}
@ -869,17 +864,16 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
* disable this bit as seems to be only relevant for Meson6 (based
* on the vendor driver), which we don't support at the moment.
*/
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0);
regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL);
/* disable all channels by default */
regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY,
MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY);
regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3,
MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG3,
MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY);
/* delay between two samples = (10+1) * 1uS */
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
@ -914,21 +908,17 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK,
regval);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW);
/*
* set up the input channel muxes in MESON_SAR_ADC_AUX_SW
@ -944,12 +934,10 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
regmap_write(priv->regmap, MESON_SAR_ADC_AUX_SW, regval);
if (priv->temperature_sensor_calibrated) {
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_REVE1,
MESON_SAR_ADC_DELTA_10_TS_REVE1);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_REVE0,
MESON_SAR_ADC_DELTA_10_TS_REVE0);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_REVE1);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_REVE0);
/*
* set bits [3:0] of the TSC (temperature sensor coefficient)
@ -976,10 +964,10 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
regval);
}
} else {
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_REVE1, 0);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_REVE0, 0);
regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_REVE1);
regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_REVE0);
}
regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN,
@ -1062,9 +1050,8 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
meson_sar_adc_set_bandgap(indio_dev, true);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
MESON_SAR_ADC_REG3_ADC_EN,
MESON_SAR_ADC_REG3_ADC_EN);
regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG3,
MESON_SAR_ADC_REG3_ADC_EN);
udelay(5);
@ -1079,8 +1066,8 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
return 0;
err_adc_clk:
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
MESON_SAR_ADC_REG3_ADC_EN, 0);
regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3,
MESON_SAR_ADC_REG3_ADC_EN);
meson_sar_adc_set_bandgap(indio_dev, false);
regulator_disable(priv->vref);
err_vref:
@ -1104,8 +1091,8 @@ static void meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
clk_disable_unprepare(priv->adc_clk);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
MESON_SAR_ADC_REG3_ADC_EN, 0);
regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3,
MESON_SAR_ADC_REG3_ADC_EN);
meson_sar_adc_set_bandgap(indio_dev, false);

View File

@ -131,9 +131,8 @@ static int mp2629_adc_probe(struct platform_device *pdev)
info->dev = dev;
platform_set_drvdata(pdev, indio_dev);
ret = regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_START | MP2629_ADC_CONTINUOUS,
MP2629_ADC_START | MP2629_ADC_CONTINUOUS);
ret = regmap_set_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_START | MP2629_ADC_CONTINUOUS);
if (ret) {
dev_err(dev, "adc enable fail: %d\n", ret);
return ret;
@ -163,10 +162,9 @@ fail_map_unregister:
iio_map_array_unregister(indio_dev);
fail_disable:
regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_CONTINUOUS, 0);
regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_START, 0);
regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_CONTINUOUS);
regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, MP2629_ADC_START);
return ret;
}
@ -180,10 +178,9 @@ static void mp2629_adc_remove(struct platform_device *pdev)
iio_map_array_unregister(indio_dev);
regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_CONTINUOUS, 0);
regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_START, 0);
regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_CONTINUOUS);
regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, MP2629_ADC_START);
}
static const struct of_device_id mp2629_adc_of_match[] = {

View File

@ -0,0 +1,606 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* MediaTek MT6359 PMIC AUXADC IIO driver
*
* Copyright (c) 2021 MediaTek Inc.
* Copyright (c) 2024 Collabora Ltd
* Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/types.h>
#include <linux/iio/iio.h>
#include <linux/mfd/mt6397/core.h>
#include <dt-bindings/iio/adc/mediatek,mt6357-auxadc.h>
#include <dt-bindings/iio/adc/mediatek,mt6358-auxadc.h>
#include <dt-bindings/iio/adc/mediatek,mt6359-auxadc.h>
#define AUXADC_AVG_TIME_US 10
#define AUXADC_POLL_DELAY_US 100
#define AUXADC_TIMEOUT_US 32000
#define AUXADC_VOLT_FULL 1800
#define IMP_STOP_DELAY_US 150
#define IMP_POLL_DELAY_US 1000
/* For PMIC_RG_RESET_VAL and MT6358_IMP0_CLEAR, the bits specific purpose is unknown. */
#define PMIC_RG_RESET_VAL (BIT(0) | BIT(3))
#define PMIC_AUXADC_RDY_BIT BIT(15)
#define MT6357_IMP_ADC_NUM 30
#define MT6358_IMP_ADC_NUM 28
#define MT6358_DCM_CK_SW_EN GENMASK(1, 0)
#define MT6358_IMP0_CLEAR (BIT(14) | BIT(7))
#define MT6358_IMP0_IRQ_RDY BIT(8)
#define MT6358_IMP1_AUTOREPEAT_EN BIT(15)
#define MT6359_IMP0_CONV_EN BIT(0)
#define MT6359_IMP1_IRQ_RDY BIT(15)
enum mtk_pmic_auxadc_regs {
PMIC_AUXADC_ADC0,
PMIC_AUXADC_DCM_CON,
PMIC_AUXADC_IMP0,
PMIC_AUXADC_IMP1,
PMIC_AUXADC_IMP3,
PMIC_AUXADC_RQST0,
PMIC_AUXADC_RQST1,
PMIC_HK_TOP_WKEY,
PMIC_HK_TOP_RST_CON0,
PMIC_FGADC_R_CON0,
PMIC_AUXADC_REGS_MAX
};
enum mtk_pmic_auxadc_channels {
PMIC_AUXADC_CHAN_BATADC,
PMIC_AUXADC_CHAN_ISENSE,
PMIC_AUXADC_CHAN_VCDT,
PMIC_AUXADC_CHAN_BAT_TEMP,
PMIC_AUXADC_CHAN_BATID,
PMIC_AUXADC_CHAN_CHIP_TEMP,
PMIC_AUXADC_CHAN_VCORE_TEMP,
PMIC_AUXADC_CHAN_VPROC_TEMP,
PMIC_AUXADC_CHAN_VGPU_TEMP,
PMIC_AUXADC_CHAN_ACCDET,
PMIC_AUXADC_CHAN_VDCXO,
PMIC_AUXADC_CHAN_TSX_TEMP,
PMIC_AUXADC_CHAN_HPOFS_CAL,
PMIC_AUXADC_CHAN_DCXO_TEMP,
PMIC_AUXADC_CHAN_VBIF,
PMIC_AUXADC_CHAN_IBAT,
PMIC_AUXADC_CHAN_VBAT,
PMIC_AUXADC_CHAN_MAX
};
/**
* struct mt6359_auxadc - Main driver structure
* @dev: Device pointer
* @regmap: Regmap from SoC PMIC Wrapper
* @chip_info: PMIC specific chip info
* @lock: Mutex to serialize AUXADC reading vs configuration
* @timed_out: Signals whether the last read timed out
*/
struct mt6359_auxadc {
struct device *dev;
struct regmap *regmap;
const struct mtk_pmic_auxadc_info *chip_info;
struct mutex lock;
bool timed_out;
};
/**
* struct mtk_pmic_auxadc_chan - PMIC AUXADC channel data
* @req_idx: Request register number
* @req_mask: Bitmask to activate a channel
* @num_samples: Number of AUXADC samples for averaging
* @r_ratio: Resistance ratio fractional
*/
struct mtk_pmic_auxadc_chan {
u8 req_idx;
u16 req_mask;
u16 num_samples;
struct u8_fract r_ratio;
};
/**
* struct mtk_pmic_auxadc_info - PMIC specific chip info
* @model_name: PMIC model name
* @channels: IIO specification of ADC channels
* @num_channels: Number of ADC channels
* @desc: PMIC AUXADC channel data
* @regs: List of PMIC specific registers
* @sec_unlock_key: Security unlock key for HK_TOP writes
* @imp_adc_num: ADC channel for battery impedance readings
* @read_imp: Callback to read impedance channels
*/
struct mtk_pmic_auxadc_info {
const char *model_name;
const struct iio_chan_spec *channels;
u8 num_channels;
const struct mtk_pmic_auxadc_chan *desc;
const u16 *regs;
u16 sec_unlock_key;
u8 imp_adc_num;
int (*read_imp)(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat);
};
#define MTK_PMIC_ADC_CHAN(_ch_idx, _req_idx, _req_bit, _samples, _rnum, _rdiv) \
[PMIC_AUXADC_CHAN_##_ch_idx] = { \
.req_idx = _req_idx, \
.req_mask = BIT(_req_bit), \
.num_samples = _samples, \
.r_ratio = { _rnum, _rdiv } \
}
#define MTK_PMIC_IIO_CHAN(_model, _name, _ch_idx, _adc_idx, _nbits, _ch_type) \
{ \
.type = _ch_type, \
.channel = _model##_AUXADC_##_ch_idx, \
.address = _adc_idx, \
.scan_index = PMIC_AUXADC_CHAN_##_ch_idx, \
.datasheet_name = __stringify(_name), \
.scan_type = { \
.sign = 'u', \
.realbits = _nbits, \
.storagebits = 16, \
.endianness = IIO_CPU \
}, \
.indexed = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) \
}
static const struct iio_chan_spec mt6357_auxadc_channels[] = {
MTK_PMIC_IIO_CHAN(MT6357, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
MTK_PMIC_IIO_CHAN(MT6357, isense, ISENSE, 1, 12, IIO_CURRENT),
MTK_PMIC_IIO_CHAN(MT6357, cdt_v, VCDT, 2, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6357, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6357, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6357, acc_det, ACCDET, 5, 12, IIO_RESISTANCE),
MTK_PMIC_IIO_CHAN(MT6357, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE),
MTK_PMIC_IIO_CHAN(MT6357, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6357, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE),
MTK_PMIC_IIO_CHAN(MT6357, dcxo_temp, DCXO_TEMP, 36, 15, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6357, vcore_temp, VCORE_TEMP, 40, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6357, vproc_temp, VPROC_TEMP, 41, 12, IIO_TEMP),
/* Battery impedance channels */
MTK_PMIC_IIO_CHAN(MT6357, batt_v, VBAT, 0, 15, IIO_VOLTAGE),
};
static const struct mtk_pmic_auxadc_chan mt6357_auxadc_ch_desc[] = {
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
MTK_PMIC_ADC_CHAN(ISENSE, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1),
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 1, 1),
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 1, 1),
MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 5, 8, 1, 1),
MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 6, 8, 1, 1),
/* Battery impedance channels */
MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 3, 1),
};
static const u16 mt6357_auxadc_regs[] = {
[PMIC_HK_TOP_RST_CON0] = 0x0f90,
[PMIC_AUXADC_DCM_CON] = 0x122e,
[PMIC_AUXADC_ADC0] = 0x1088,
[PMIC_AUXADC_IMP0] = 0x119c,
[PMIC_AUXADC_IMP1] = 0x119e,
[PMIC_AUXADC_RQST0] = 0x110e,
[PMIC_AUXADC_RQST1] = 0x1114,
};
static const struct iio_chan_spec mt6358_auxadc_channels[] = {
MTK_PMIC_IIO_CHAN(MT6358, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
MTK_PMIC_IIO_CHAN(MT6358, cdt_v, VCDT, 2, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6358, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6358, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6358, acc_det, ACCDET, 5, 12, IIO_RESISTANCE),
MTK_PMIC_IIO_CHAN(MT6358, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE),
MTK_PMIC_IIO_CHAN(MT6358, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6358, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE),
MTK_PMIC_IIO_CHAN(MT6358, dcxo_temp, DCXO_TEMP, 10, 15, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6358, bif_v, VBIF, 11, 12, IIO_VOLTAGE),
MTK_PMIC_IIO_CHAN(MT6358, vcore_temp, VCORE_TEMP, 38, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6358, vproc_temp, VPROC_TEMP, 39, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6358, vgpu_temp, VGPU_TEMP, 40, 12, IIO_TEMP),
/* Battery impedance channels */
MTK_PMIC_IIO_CHAN(MT6358, batt_v, VBAT, 0, 15, IIO_VOLTAGE),
};
static const struct mtk_pmic_auxadc_chan mt6358_auxadc_ch_desc[] = {
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1),
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 2, 1),
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2),
MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 2, 1),
MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1),
MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1),
MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1),
/* Battery impedance channels */
MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2),
};
static const u16 mt6358_auxadc_regs[] = {
[PMIC_HK_TOP_RST_CON0] = 0x0f90,
[PMIC_AUXADC_DCM_CON] = 0x1260,
[PMIC_AUXADC_ADC0] = 0x1088,
[PMIC_AUXADC_IMP0] = 0x1208,
[PMIC_AUXADC_IMP1] = 0x120a,
[PMIC_AUXADC_RQST0] = 0x1108,
[PMIC_AUXADC_RQST1] = 0x110a,
};
static const struct iio_chan_spec mt6359_auxadc_channels[] = {
MTK_PMIC_IIO_CHAN(MT6359, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
MTK_PMIC_IIO_CHAN(MT6359, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6359, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6359, acc_det, ACCDET, 5, 12, IIO_RESISTANCE),
MTK_PMIC_IIO_CHAN(MT6359, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE),
MTK_PMIC_IIO_CHAN(MT6359, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6359, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE),
MTK_PMIC_IIO_CHAN(MT6359, dcxo_temp, DCXO_TEMP, 10, 15, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6359, bif_v, VBIF, 11, 12, IIO_VOLTAGE),
MTK_PMIC_IIO_CHAN(MT6359, vcore_temp, VCORE_TEMP, 30, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6359, vproc_temp, VPROC_TEMP, 31, 12, IIO_TEMP),
MTK_PMIC_IIO_CHAN(MT6359, vgpu_temp, VGPU_TEMP, 32, 12, IIO_TEMP),
/* Battery impedance channels */
MTK_PMIC_IIO_CHAN(MT6359, batt_v, VBAT, 0, 15, IIO_VOLTAGE),
MTK_PMIC_IIO_CHAN(MT6359, batt_i, IBAT, 0, 15, IIO_CURRENT),
};
static const struct mtk_pmic_auxadc_chan mt6359_auxadc_ch_desc[] = {
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 7, 2),
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 5, 2),
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2),
MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 5, 2),
MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1),
MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1),
MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1),
/* Battery impedance channels */
MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2),
MTK_PMIC_ADC_CHAN(IBAT, 0, 0, 128, 7, 2),
};
static const u16 mt6359_auxadc_regs[] = {
[PMIC_FGADC_R_CON0] = 0x0d88,
[PMIC_HK_TOP_WKEY] = 0x0fb4,
[PMIC_HK_TOP_RST_CON0] = 0x0f90,
[PMIC_AUXADC_RQST0] = 0x1108,
[PMIC_AUXADC_RQST1] = 0x110a,
[PMIC_AUXADC_ADC0] = 0x1088,
[PMIC_AUXADC_IMP0] = 0x1208,
[PMIC_AUXADC_IMP1] = 0x120a,
[PMIC_AUXADC_IMP3] = 0x120e,
};
static void mt6358_stop_imp_conv(struct mt6359_auxadc *adc_dev)
{
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
struct regmap *regmap = adc_dev->regmap;
regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6358_IMP0_CLEAR);
regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6358_IMP0_CLEAR);
regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN);
regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN);
}
static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev)
{
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
struct regmap *regmap = adc_dev->regmap;
u32 val;
int ret;
regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN);
regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN);
ret = regmap_read_poll_timeout(adc_dev->regmap, cinfo->regs[PMIC_AUXADC_IMP0],
val, val & MT6358_IMP0_IRQ_RDY,
IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US);
if (ret) {
mt6358_stop_imp_conv(adc_dev);
return ret;
}
return 0;
}
static int mt6358_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
{
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
struct regmap *regmap = adc_dev->regmap;
u16 reg_adc0 = cinfo->regs[PMIC_AUXADC_ADC0];
u32 val_v;
int ret;
ret = mt6358_start_imp_conv(adc_dev);
if (ret)
return ret;
/* Read the params before stopping */
regmap_read(regmap, reg_adc0 + (cinfo->imp_adc_num << 1), &val_v);
mt6358_stop_imp_conv(adc_dev);
if (vbat)
*vbat = val_v;
if (ibat)
*ibat = 0;
return 0;
}
static int mt6359_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
{
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
struct regmap *regmap = adc_dev->regmap;
u32 val, val_v, val_i;
int ret;
/* Start conversion */
regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6359_IMP0_CONV_EN);
ret = regmap_read_poll_timeout(regmap, cinfo->regs[PMIC_AUXADC_IMP1],
val, val & MT6359_IMP1_IRQ_RDY,
IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US);
/* Stop conversion regardless of the result */
regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], 0);
if (ret)
return ret;
/* If it succeeded, wait for the registers to be populated */
fsleep(IMP_STOP_DELAY_US);
ret = regmap_read(regmap, cinfo->regs[PMIC_AUXADC_IMP3], &val_v);
if (ret)
return ret;
ret = regmap_read(regmap, cinfo->regs[PMIC_FGADC_R_CON0], &val_i);
if (ret)
return ret;
if (vbat)
*vbat = val_v;
if (ibat)
*ibat = val_i;
return 0;
}
static const struct mtk_pmic_auxadc_info mt6357_chip_info = {
.model_name = "MT6357",
.channels = mt6357_auxadc_channels,
.num_channels = ARRAY_SIZE(mt6357_auxadc_channels),
.desc = mt6357_auxadc_ch_desc,
.regs = mt6357_auxadc_regs,
.imp_adc_num = MT6357_IMP_ADC_NUM,
.read_imp = mt6358_read_imp,
};
static const struct mtk_pmic_auxadc_info mt6358_chip_info = {
.model_name = "MT6358",
.channels = mt6358_auxadc_channels,
.num_channels = ARRAY_SIZE(mt6358_auxadc_channels),
.desc = mt6358_auxadc_ch_desc,
.regs = mt6358_auxadc_regs,
.imp_adc_num = MT6358_IMP_ADC_NUM,
.read_imp = mt6358_read_imp,
};
static const struct mtk_pmic_auxadc_info mt6359_chip_info = {
.model_name = "MT6359",
.channels = mt6359_auxadc_channels,
.num_channels = ARRAY_SIZE(mt6359_auxadc_channels),
.desc = mt6359_auxadc_ch_desc,
.regs = mt6359_auxadc_regs,
.sec_unlock_key = 0x6359,
.read_imp = mt6359_read_imp,
};
static void mt6359_auxadc_reset(struct mt6359_auxadc *adc_dev)
{
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
struct regmap *regmap = adc_dev->regmap;
/* Unlock HK_TOP writes */
if (cinfo->sec_unlock_key)
regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], cinfo->sec_unlock_key);
/* Assert ADC reset */
regmap_set_bits(regmap, cinfo->regs[PMIC_HK_TOP_RST_CON0], PMIC_RG_RESET_VAL);
/* De-assert ADC reset. No wait required, as pwrap takes care of that for us. */
regmap_clear_bits(regmap, cinfo->regs[PMIC_HK_TOP_RST_CON0], PMIC_RG_RESET_VAL);
/* Lock HK_TOP writes again */
if (cinfo->sec_unlock_key)
regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], 0);
}
static int mt6359_auxadc_read_adc(struct mt6359_auxadc *adc_dev,
const struct iio_chan_spec *chan, int *out)
{
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
struct regmap *regmap = adc_dev->regmap;
u32 val;
int ret;
/* Request to start sampling for ADC channel */
ret = regmap_write(regmap, cinfo->regs[desc->req_idx], desc->req_mask);
if (ret)
return ret;
/* Wait until all samples are averaged */
fsleep(desc->num_samples * AUXADC_AVG_TIME_US);
ret = regmap_read_poll_timeout(regmap,
cinfo->regs[PMIC_AUXADC_ADC0] + (chan->address << 1),
val, val & PMIC_AUXADC_RDY_BIT,
AUXADC_POLL_DELAY_US, AUXADC_TIMEOUT_US);
if (ret)
return ret;
/* Stop sampling */
regmap_write(regmap, cinfo->regs[desc->req_idx], 0);
*out = val & GENMASK(chan->scan_type.realbits - 1, 0);
return 0;
}
static int mt6359_auxadc_read_label(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, char *label)
{
return sysfs_emit(label, "%s\n", chan->datasheet_name);
}
static int mt6359_auxadc_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
int *val, int *val2, long mask)
{
struct mt6359_auxadc *adc_dev = iio_priv(indio_dev);
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
int ret;
if (mask == IIO_CHAN_INFO_SCALE) {
*val = desc->r_ratio.numerator * AUXADC_VOLT_FULL;
if (desc->r_ratio.denominator > 1) {
*val2 = desc->r_ratio.denominator;
return IIO_VAL_FRACTIONAL;
}
return IIO_VAL_INT;
}
scoped_guard(mutex, &adc_dev->lock) {
switch (chan->scan_index) {
case PMIC_AUXADC_CHAN_IBAT:
ret = adc_dev->chip_info->read_imp(adc_dev, NULL, val);
break;
case PMIC_AUXADC_CHAN_VBAT:
ret = adc_dev->chip_info->read_imp(adc_dev, val, NULL);
break;
default:
ret = mt6359_auxadc_read_adc(adc_dev, chan, val);
break;
}
}
if (ret) {
/*
* If we get more than one timeout, it's possible that the
* AUXADC is stuck: perform a full reset to recover it.
*/
if (ret == -ETIMEDOUT) {
if (adc_dev->timed_out) {
dev_warn(adc_dev->dev, "Resetting stuck ADC!\r\n");
mt6359_auxadc_reset(adc_dev);
}
adc_dev->timed_out = true;
}
return ret;
}
adc_dev->timed_out = false;
return IIO_VAL_INT;
}
static const struct iio_info mt6359_auxadc_iio_info = {
.read_label = mt6359_auxadc_read_label,
.read_raw = mt6359_auxadc_read_raw,
};
static int mt6359_auxadc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device *mt6397_mfd_dev = dev->parent;
struct mt6359_auxadc *adc_dev;
struct iio_dev *indio_dev;
struct regmap *regmap;
int ret;
/* Regmap is from SoC PMIC Wrapper, parent of the mt6397 MFD */
regmap = dev_get_regmap(mt6397_mfd_dev->parent, NULL);
if (!regmap)
return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc_dev));
if (!indio_dev)
return -ENOMEM;
adc_dev = iio_priv(indio_dev);
adc_dev->regmap = regmap;
adc_dev->dev = dev;
adc_dev->chip_info = device_get_match_data(dev);
if (!adc_dev->chip_info)
return -EINVAL;
mutex_init(&adc_dev->lock);
mt6359_auxadc_reset(adc_dev);
indio_dev->name = adc_dev->chip_info->model_name;
indio_dev->info = &mt6359_auxadc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = adc_dev->chip_info->channels;
indio_dev->num_channels = adc_dev->chip_info->num_channels;
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
return dev_err_probe(dev, ret, "failed to register iio device\n");
return 0;
}
static const struct of_device_id mt6359_auxadc_of_match[] = {
{ .compatible = "mediatek,mt6357-auxadc", .data = &mt6357_chip_info },
{ .compatible = "mediatek,mt6358-auxadc", .data = &mt6358_chip_info },
{ .compatible = "mediatek,mt6359-auxadc", .data = &mt6359_chip_info },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mt6359_auxadc_of_match);
static struct platform_driver mt6359_auxadc_driver = {
.driver = {
.name = "mt6359-auxadc",
.of_match_table = mt6359_auxadc_of_match,
},
.probe = mt6359_auxadc_probe,
};
module_platform_driver(mt6359_auxadc_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
MODULE_DESCRIPTION("MediaTek MT6359 PMIC AUXADC Driver");

View File

@ -358,15 +358,15 @@ static int rradc_enable_continuous_mode(struct rradc_chip *chip)
int ret;
/* Clear channel log */
ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_LOG,
RR_ADC_LOG_CLR_CTRL, RR_ADC_LOG_CLR_CTRL);
ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_LOG,
RR_ADC_LOG_CLR_CTRL);
if (ret < 0) {
dev_err(chip->dev, "log ctrl update to clear failed:%d\n", ret);
return ret;
}
ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_LOG,
RR_ADC_LOG_CLR_CTRL, 0);
ret = regmap_clear_bits(chip->regmap, chip->base + RR_ADC_LOG,
RR_ADC_LOG_CLR_CTRL);
if (ret < 0) {
dev_err(chip->dev, "log ctrl update to not clear failed:%d\n",
ret);
@ -374,9 +374,8 @@ static int rradc_enable_continuous_mode(struct rradc_chip *chip)
}
/* Switch to continuous mode */
ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_CTL,
RR_ADC_CTL_CONTINUOUS_SEL,
RR_ADC_CTL_CONTINUOUS_SEL);
ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_CTL,
RR_ADC_CTL_CONTINUOUS_SEL);
if (ret < 0)
dev_err(chip->dev, "Update to continuous mode failed:%d\n",
ret);
@ -389,8 +388,8 @@ static int rradc_disable_continuous_mode(struct rradc_chip *chip)
int ret;
/* Switch to non continuous mode */
ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_CTL,
RR_ADC_CTL_CONTINUOUS_SEL, 0);
ret = regmap_clear_bits(chip->regmap, chip->base + RR_ADC_CTL,
RR_ADC_CTL_CONTINUOUS_SEL);
if (ret < 0)
dev_err(chip->dev, "Update to non-continuous mode failed:%d\n",
ret);
@ -434,8 +433,8 @@ static int rradc_read_status_in_cont_mode(struct rradc_chip *chip,
return -EINVAL;
}
ret = regmap_update_bits(chip->regmap, chip->base + chan->trigger_addr,
chan->trigger_mask, chan->trigger_mask);
ret = regmap_set_bits(chip->regmap, chip->base + chan->trigger_addr,
chan->trigger_mask);
if (ret < 0) {
dev_err(chip->dev,
"Failed to apply trigger for channel '%s' ret=%d\n",
@ -469,8 +468,8 @@ static int rradc_read_status_in_cont_mode(struct rradc_chip *chip,
rradc_disable_continuous_mode(chip);
disable_trigger:
regmap_update_bits(chip->regmap, chip->base + chan->trigger_addr,
chan->trigger_mask, 0);
regmap_clear_bits(chip->regmap, chip->base + chan->trigger_addr,
chan->trigger_mask);
return ret;
}
@ -481,17 +480,16 @@ static int rradc_prepare_batt_id_conversion(struct rradc_chip *chip,
{
int ret;
ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL,
RR_ADC_BATT_ID_CTRL_CHANNEL_CONV,
RR_ADC_BATT_ID_CTRL_CHANNEL_CONV);
ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL,
RR_ADC_BATT_ID_CTRL_CHANNEL_CONV);
if (ret < 0) {
dev_err(chip->dev, "Enabling BATT ID channel failed:%d\n", ret);
return ret;
}
ret = regmap_update_bits(chip->regmap,
chip->base + RR_ADC_BATT_ID_TRIGGER,
RR_ADC_TRIGGER_CTL, RR_ADC_TRIGGER_CTL);
ret = regmap_set_bits(chip->regmap,
chip->base + RR_ADC_BATT_ID_TRIGGER,
RR_ADC_TRIGGER_CTL);
if (ret < 0) {
dev_err(chip->dev, "BATT_ID trigger set failed:%d\n", ret);
goto out_disable_batt_id;
@ -500,12 +498,12 @@ static int rradc_prepare_batt_id_conversion(struct rradc_chip *chip,
ret = rradc_read_status_in_cont_mode(chip, chan_address);
/* Reset registers back to default values */
regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_TRIGGER,
RR_ADC_TRIGGER_CTL, 0);
regmap_clear_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_TRIGGER,
RR_ADC_TRIGGER_CTL);
out_disable_batt_id:
regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL,
RR_ADC_BATT_ID_CTRL_CHANNEL_CONV, 0);
regmap_clear_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL,
RR_ADC_BATT_ID_CTRL_CHANNEL_CONV);
return ret;
}
@ -965,9 +963,9 @@ static int rradc_probe(struct platform_device *pdev)
if (batt_id_delay >= 0) {
batt_id_delay = FIELD_PREP(BATT_ID_SETTLE_MASK, batt_id_delay);
ret = regmap_update_bits(chip->regmap,
chip->base + RR_ADC_BATT_ID_CFG,
batt_id_delay, batt_id_delay);
ret = regmap_set_bits(chip->regmap,
chip->base + RR_ADC_BATT_ID_CFG,
batt_id_delay);
if (ret < 0) {
dev_err(chip->dev,
"BATT_ID settling time config failed:%d\n",

View File

@ -137,9 +137,8 @@ static int rn5t618_adc_read(struct iio_dev *iio_dev,
init_completion(&adc->conv_completion);
/* single conversion */
ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
RN5T618_ADCCNT3_GODONE,
RN5T618_ADCCNT3_GODONE);
ret = regmap_set_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
RN5T618_ADCCNT3_GODONE);
if (ret < 0)
return ret;

View File

@ -508,13 +508,13 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
}
}
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
SC27XX_ADC_EN, SC27XX_ADC_EN);
ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_CTL,
SC27XX_ADC_EN);
if (ret)
goto regulator_restore;
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR,
SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR);
ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR,
SC27XX_ADC_IRQ_CLR);
if (ret)
goto disable_adc;
@ -537,8 +537,8 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
if (ret)
goto disable_adc;
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
SC27XX_ADC_CHN_RUN, SC27XX_ADC_CHN_RUN);
ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_CTL,
SC27XX_ADC_CHN_RUN);
if (ret)
goto disable_adc;
@ -559,8 +559,8 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
value &= SC27XX_ADC_DATA_MASK;
disable_adc:
regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
SC27XX_ADC_EN, 0);
regmap_clear_bits(data->regmap, data->base + SC27XX_ADC_CTL,
SC27XX_ADC_EN);
regulator_restore:
if ((data->var_data->set_volref) && (channel == 30 || channel == 31)) {
ret_volref = regulator_set_voltage(data->volref,
@ -765,15 +765,14 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
{
int ret;
ret = regmap_update_bits(data->regmap, data->var_data->module_en,
SC27XX_MODULE_ADC_EN, SC27XX_MODULE_ADC_EN);
ret = regmap_set_bits(data->regmap, data->var_data->module_en,
SC27XX_MODULE_ADC_EN);
if (ret)
return ret;
/* Enable ADC work clock and controller clock */
ret = regmap_update_bits(data->regmap, data->var_data->clk_en,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN);
ret = regmap_set_bits(data->regmap, data->var_data->clk_en,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN);
if (ret)
goto disable_adc;
@ -789,11 +788,11 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
return 0;
disable_clk:
regmap_update_bits(data->regmap, data->var_data->clk_en,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0);
regmap_clear_bits(data->regmap, data->var_data->clk_en,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN);
disable_adc:
regmap_update_bits(data->regmap, data->var_data->module_en,
SC27XX_MODULE_ADC_EN, 0);
regmap_clear_bits(data->regmap, data->var_data->module_en,
SC27XX_MODULE_ADC_EN);
return ret;
}
@ -803,11 +802,11 @@ static void sc27xx_adc_disable(void *_data)
struct sc27xx_adc_data *data = _data;
/* Disable ADC work clock and controller clock */
regmap_update_bits(data->regmap, data->var_data->clk_en,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0);
regmap_clear_bits(data->regmap, data->var_data->clk_en,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN);
regmap_update_bits(data->regmap, data->var_data->module_en,
SC27XX_MODULE_ADC_EN, 0);
regmap_clear_bits(data->regmap, data->var_data->module_en,
SC27XX_MODULE_ADC_EN);
}
static const struct sc27xx_adc_variant_data sc2731_data = {

View File

@ -759,8 +759,7 @@ static int stm32_dfsdm_start_conv(struct iio_dev *indio_dev,
return 0;
filter_unconfigure:
regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
DFSDM_CR1_CFG_MASK, 0);
regmap_clear_bits(regmap, DFSDM_CR1(adc->fl_id), DFSDM_CR1_CFG_MASK);
stop_channels:
stm32_dfsdm_stop_channel(indio_dev);
@ -774,8 +773,7 @@ static void stm32_dfsdm_stop_conv(struct iio_dev *indio_dev)
stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id);
regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
DFSDM_CR1_CFG_MASK, 0);
regmap_clear_bits(regmap, DFSDM_CR1(adc->fl_id), DFSDM_CR1_CFG_MASK);
stm32_dfsdm_stop_channel(indio_dev);
}
@ -951,16 +949,14 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
if (adc->nconv == 1 && !indio_dev->trig) {
/* Enable regular DMA transfer*/
ret = regmap_update_bits(adc->dfsdm->regmap,
DFSDM_CR1(adc->fl_id),
DFSDM_CR1_RDMAEN_MASK,
DFSDM_CR1_RDMAEN_MASK);
ret = regmap_set_bits(adc->dfsdm->regmap,
DFSDM_CR1(adc->fl_id),
DFSDM_CR1_RDMAEN_MASK);
} else {
/* Enable injected DMA transfer*/
ret = regmap_update_bits(adc->dfsdm->regmap,
DFSDM_CR1(adc->fl_id),
DFSDM_CR1_JDMAEN_MASK,
DFSDM_CR1_JDMAEN_MASK);
ret = regmap_set_bits(adc->dfsdm->regmap,
DFSDM_CR1(adc->fl_id),
DFSDM_CR1_JDMAEN_MASK);
}
if (ret < 0)
@ -981,8 +977,8 @@ static void stm32_dfsdm_adc_dma_stop(struct iio_dev *indio_dev)
if (!adc->dma_chan)
return;
regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id),
DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK, 0);
regmap_clear_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id),
DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK);
dmaengine_terminate_all(adc->dma_chan);
}
@ -1305,9 +1301,8 @@ static irqreturn_t stm32_dfsdm_irq(int irq, void *arg)
if (status & DFSDM_ISR_ROVRF_MASK) {
if (int_en & DFSDM_CR2_ROVRIE_MASK)
dev_warn(&indio_dev->dev, "Overrun detected\n");
regmap_update_bits(regmap, DFSDM_ICR(adc->fl_id),
DFSDM_ICR_CLRROVRF_MASK,
DFSDM_ICR_CLRROVRF_MASK);
regmap_set_bits(regmap, DFSDM_ICR(adc->fl_id),
DFSDM_ICR_CLRROVRF_MASK);
}
return IRQ_HANDLED;

View File

@ -58,7 +58,6 @@
struct adc108s102_state {
struct spi_device *spi;
struct regulator *reg;
u32 va_millivolt;
/* SPI transfer used by triggered buffer handler*/
struct spi_transfer ring_xfer;
@ -216,11 +215,6 @@ static const struct iio_info adc108s102_info = {
.update_scan_mode = &adc108s102_update_scan_mode,
};
static void adc108s102_reg_disable(void *reg)
{
regulator_disable(reg);
}
static int adc108s102_probe(struct spi_device *spi)
{
struct adc108s102_state *st;
@ -236,25 +230,9 @@ static int adc108s102_probe(struct spi_device *spi)
if (ACPI_COMPANION(&spi->dev)) {
st->va_millivolt = ADC108S102_VA_MV_ACPI_DEFAULT;
} else {
st->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret < 0) {
dev_err(&spi->dev, "Cannot enable vref regulator\n");
return ret;
}
ret = devm_add_action_or_reset(&spi->dev, adc108s102_reg_disable,
st->reg);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0) {
dev_err(&spi->dev, "vref get voltage failed\n");
return ret;
}
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
if (ret < 0)
return dev_err_probe(&spi->dev, ret, "failed get vref voltage\n");
st->va_millivolt = ret / 1000;
}

View File

@ -0,0 +1,825 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Texas Instruments ADS1119 ADC driver.
*
* Copyright 2024 Toradex
*/
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/units.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#define ADS1119_CMD_RESET 0x06
#define ADS1119_CMD_POWERDOWN 0x02
#define ADS1119_CMD_START_SYNC 0x08
#define ADS1119_CMD_RDATA 0x10
#define ADS1119_CMD_RREG_CONFIG 0x20
#define ADS1119_CMD_RREG_STATUS 0x24
#define ADS1119_CMD_WREG 0x40
#define ADS1119_CMD_RREG(reg) (0x20 | (reg) << 2)
/* Config register */
#define ADS1119_REG_CONFIG 0x00
#define ADS1119_CONFIG_VREF_FIELD BIT(0)
#define ADS1119_CONFIG_CM_FIELD BIT(1)
#define ADS1119_CONFIG_DR_FIELD GENMASK(3, 2)
#define ADS1119_CONFIG_GAIN_FIELD BIT(4)
#define ADS1119_CONFIG_MUX_FIELD GENMASK(7, 5)
#define ADS1119_VREF_INTERNAL 0
#define ADS1119_VREF_EXTERNAL 1
#define ADS1119_VREF_INTERNAL_VAL 2048000
#define ADS1119_CM_SINGLE 0
#define ADS1119_CM_CONTINUOUS 1
#define ADS1119_DR_20_SPS 0
#define ADS1119_DR_90_SPS 1
#define ADS1119_DR_330_SPS 2
#define ADS1119_DR_1000_SPS 3
#define ADS1119_GAIN_1 0
#define ADS1119_GAIN_4 1
#define ADS1119_MUX_AIN0_AIN1 0
#define ADS1119_MUX_AIN2_AIN3 1
#define ADS1119_MUX_AIN1_AIN2 2
#define ADS1119_MUX_AIN0 3
#define ADS1119_MUX_AIN1 4
#define ADS1119_MUX_AIN2 5
#define ADS1119_MUX_AIN3 6
#define ADS1119_MUX_SHORTED 7
/* Status register */
#define ADS1119_REG_STATUS 0x01
#define ADS1119_STATUS_DRDY_FIELD BIT(7)
#define ADS1119_DEFAULT_GAIN 1
#define ADS1119_DEFAULT_DATARATE 20
#define ADS1119_SUSPEND_DELAY 2000
/* Timeout based on the minimum sample rate of 20 SPS (50000us) */
#define ADS1119_MAX_DRDY_TIMEOUT 85000
#define ADS1119_MAX_CHANNELS 7
#define ADS1119_MAX_SINGLE_CHANNELS 4
struct ads1119_channel_config {
int gain;
int datarate;
int mux;
};
struct ads1119_state {
struct completion completion;
struct i2c_client *client;
struct gpio_desc *reset_gpio;
struct iio_trigger *trig;
struct ads1119_channel_config *channels_cfg;
unsigned int num_channels_cfg;
unsigned int cached_config;
int vref_uV;
};
static const char * const ads1119_power_supplies[] = {
"avdd", "dvdd"
};
static const int ads1119_available_datarates[] = {
20, 90, 330, 1000,
};
static const int ads1119_available_gains[] = {
1, 1,
1, 4,
};
static int ads1119_upd_cfg_reg(struct ads1119_state *st, unsigned int fields,
unsigned int val)
{
unsigned int config = st->cached_config;
int ret;
config &= ~fields;
config |= val;
ret = i2c_smbus_write_byte_data(st->client, ADS1119_CMD_WREG, config);
if (ret)
return ret;
st->cached_config = config;
return 0;
}
static bool ads1119_data_ready(struct ads1119_state *st)
{
int status;
status = i2c_smbus_read_byte_data(st->client, ADS1119_CMD_RREG_STATUS);
if (status < 0)
return false;
return FIELD_GET(ADS1119_STATUS_DRDY_FIELD, status);
}
static int ads1119_reset(struct ads1119_state *st)
{
st->cached_config = 0;
if (!st->reset_gpio)
return i2c_smbus_write_byte(st->client, ADS1119_CMD_RESET);
gpiod_set_value_cansleep(st->reset_gpio, 1);
udelay(1);
gpiod_set_value_cansleep(st->reset_gpio, 0);
udelay(1);
return 0;
}
static int ads1119_set_conv_mode(struct ads1119_state *st, bool continuous)
{
unsigned int mode;
if (continuous)
mode = ADS1119_CM_CONTINUOUS;
else
mode = ADS1119_CM_SINGLE;
return ads1119_upd_cfg_reg(st, ADS1119_CONFIG_CM_FIELD,
FIELD_PREP(ADS1119_CONFIG_CM_FIELD, mode));
}
static int ads1119_get_hw_gain(int gain)
{
if (gain == 4)
return ADS1119_GAIN_4;
else
return ADS1119_GAIN_1;
}
static int ads1119_get_hw_datarate(int datarate)
{
switch (datarate) {
case 90:
return ADS1119_DR_90_SPS;
case 330:
return ADS1119_DR_330_SPS;
case 1000:
return ADS1119_DR_1000_SPS;
case 20:
default:
return ADS1119_DR_20_SPS;
}
}
static int ads1119_configure_channel(struct ads1119_state *st, int mux,
int gain, int datarate)
{
int ret;
ret = ads1119_upd_cfg_reg(st, ADS1119_CONFIG_MUX_FIELD,
FIELD_PREP(ADS1119_CONFIG_MUX_FIELD, mux));
if (ret)
return ret;
ret = ads1119_upd_cfg_reg(st, ADS1119_CONFIG_GAIN_FIELD,
FIELD_PREP(ADS1119_CONFIG_GAIN_FIELD,
ads1119_get_hw_gain(gain)));
if (ret)
return ret;
return ads1119_upd_cfg_reg(st, ADS1119_CONFIG_DR_FIELD,
FIELD_PREP(ADS1119_CONFIG_DR_FIELD,
ads1119_get_hw_datarate(datarate)));
}
static int ads1119_poll_data_ready(struct ads1119_state *st,
struct iio_chan_spec const *chan)
{
unsigned int datarate = st->channels_cfg[chan->address].datarate;
unsigned long wait_time;
bool data_ready;
/* Poll 5 times more than the data rate */
wait_time = DIV_ROUND_CLOSEST(MICRO, 5 * datarate);
return read_poll_timeout(ads1119_data_ready, data_ready,
data_ready, wait_time,
ADS1119_MAX_DRDY_TIMEOUT, false, st);
}
static int ads1119_read_data(struct ads1119_state *st,
struct iio_chan_spec const *chan,
unsigned int *val)
{
unsigned int timeout;
int ret = 0;
timeout = msecs_to_jiffies(ADS1119_MAX_DRDY_TIMEOUT);
if (!st->client->irq) {
ret = ads1119_poll_data_ready(st, chan);
if (ret)
return ret;
} else if (!wait_for_completion_timeout(&st->completion, timeout)) {
return -ETIMEDOUT;
}
ret = i2c_smbus_read_word_swapped(st->client, ADS1119_CMD_RDATA);
if (ret < 0)
return ret;
*val = ret;
return 0;
}
static int ads1119_single_conversion(struct ads1119_state *st,
struct iio_chan_spec const *chan,
int *val,
bool calib_offset)
{
struct device *dev = &st->client->dev;
int mux = st->channels_cfg[chan->address].mux;
int gain = st->channels_cfg[chan->address].gain;
int datarate = st->channels_cfg[chan->address].datarate;
unsigned int sample;
int ret;
if (calib_offset)
mux = ADS1119_MUX_SHORTED;
ret = pm_runtime_resume_and_get(dev);
if (ret)
goto pdown;
ret = ads1119_configure_channel(st, mux, gain, datarate);
if (ret)
goto pdown;
ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
if (ret)
goto pdown;
ret = ads1119_read_data(st, chan, &sample);
if (ret)
goto pdown;
*val = sign_extend32(sample, chan->scan_type.realbits - 1);
ret = IIO_VAL_INT;
pdown:
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
static int ads1119_validate_datarate(struct ads1119_state *st, int datarate)
{
switch (datarate) {
case 20:
case 90:
case 330:
case 1000:
return datarate;
default:
return -EINVAL;
}
}
static int ads1119_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
*type = IIO_VAL_FRACTIONAL;
*vals = ads1119_available_gains;
*length = ARRAY_SIZE(ads1119_available_gains);
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_SAMP_FREQ:
*type = IIO_VAL_INT;
*vals = ads1119_available_datarates;
*length = ARRAY_SIZE(ads1119_available_datarates);
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
static int ads1119_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct ads1119_state *st = iio_priv(indio_dev);
unsigned int index = chan->address;
if (index >= st->num_channels_cfg)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
return ads1119_single_conversion(st, chan, val, false);
unreachable();
case IIO_CHAN_INFO_OFFSET:
iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
return ads1119_single_conversion(st, chan, val, true);
unreachable();
case IIO_CHAN_INFO_SCALE:
*val = st->vref_uV / 1000;
*val /= st->channels_cfg[index].gain;
*val2 = chan->scan_type.realbits - 1;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = st->channels_cfg[index].datarate;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int ads1119_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
{
struct ads1119_state *st = iio_priv(indio_dev);
unsigned int index = chan->address;
int ret;
if (index >= st->num_channels_cfg)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
ret = MICRO / ((val * MICRO) + val2);
if (ret != 1 && ret != 4)
return -EINVAL;
st->channels_cfg[index].gain = ret;
return 0;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = ads1119_validate_datarate(st, val);
if (ret < 0)
return ret;
st->channels_cfg[index].datarate = ret;
return 0;
default:
return -EINVAL;
}
}
static int ads1119_debugfs_reg_access(struct iio_dev *indio_dev,
unsigned int reg, unsigned int writeval,
unsigned int *readval)
{
struct ads1119_state *st = iio_priv(indio_dev);
int ret;
if (reg > ADS1119_REG_STATUS)
return -EINVAL;
if (readval) {
ret = i2c_smbus_read_byte_data(st->client,
ADS1119_CMD_RREG(reg));
if (ret < 0)
return ret;
*readval = ret;
return 0;
}
if (reg > ADS1119_REG_CONFIG)
return -EINVAL;
return i2c_smbus_write_byte_data(st->client, ADS1119_CMD_WREG,
writeval);
}
static const struct iio_info ads1119_info = {
.read_avail = ads1119_read_avail,
.read_raw = ads1119_read_raw,
.write_raw = ads1119_write_raw,
.debugfs_reg_access = ads1119_debugfs_reg_access,
};
static int ads1119_triggered_buffer_preenable(struct iio_dev *indio_dev)
{
struct ads1119_state *st = iio_priv(indio_dev);
struct device *dev = &st->client->dev;
unsigned int index;
int ret;
index = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
ret = ads1119_set_conv_mode(st, true);
if (ret)
return ret;
ret = ads1119_configure_channel(st,
st->channels_cfg[index].mux,
st->channels_cfg[index].gain,
st->channels_cfg[index].datarate);
if (ret)
return ret;
ret = pm_runtime_resume_and_get(dev);
if (ret)
return ret;
return i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
}
static int ads1119_triggered_buffer_postdisable(struct iio_dev *indio_dev)
{
struct ads1119_state *st = iio_priv(indio_dev);
struct device *dev = &st->client->dev;
int ret;
ret = ads1119_set_conv_mode(st, false);
if (ret)
return ret;
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
}
static const struct iio_buffer_setup_ops ads1119_buffer_setup_ops = {
.preenable = ads1119_triggered_buffer_preenable,
.postdisable = ads1119_triggered_buffer_postdisable,
.validate_scan_mask = &iio_validate_scan_mask_onehot,
};
static const struct iio_trigger_ops ads1119_trigger_ops = {
.validate_device = &iio_trigger_validate_own_device,
};
static irqreturn_t ads1119_irq_handler(int irq, void *dev_id)
{
struct iio_dev *indio_dev = dev_id;
struct ads1119_state *st = iio_priv(indio_dev);
if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev))
iio_trigger_poll(indio_dev->trig);
else
complete(&st->completion);
return IRQ_HANDLED;
}
static irqreturn_t ads1119_trigger_handler(int irq, void *private)
{
struct iio_poll_func *pf = private;
struct iio_dev *indio_dev = pf->indio_dev;
struct ads1119_state *st = iio_priv(indio_dev);
struct {
unsigned int sample;
s64 timestamp __aligned(8);
} scan;
unsigned int index;
int ret;
if (!iio_trigger_using_own(indio_dev)) {
index = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
ret = ads1119_poll_data_ready(st, &indio_dev->channels[index]);
if (ret) {
dev_err(&st->client->dev,
"Failed to poll data on trigger (%d)\n", ret);
goto done;
}
}
ret = i2c_smbus_read_word_swapped(st->client, ADS1119_CMD_RDATA);
if (ret < 0) {
dev_err(&st->client->dev,
"Failed to read data on trigger (%d)\n", ret);
goto done;
}
scan.sample = ret;
iio_push_to_buffers_with_timestamp(indio_dev, &scan,
iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ads1119_init(struct ads1119_state *st, bool vref_external)
{
int ret;
ret = ads1119_reset(st);
if (ret)
return ret;
if (vref_external)
return ads1119_upd_cfg_reg(st,
ADS1119_CONFIG_VREF_FIELD,
FIELD_PREP(ADS1119_CONFIG_VREF_FIELD,
ADS1119_VREF_EXTERNAL));
return 0;
}
static int ads1119_map_analog_inputs_mux(int ain_pos, int ain_neg,
bool differential)
{
if (ain_pos >= ADS1119_MAX_SINGLE_CHANNELS)
return -EINVAL;
if (!differential)
return ADS1119_MUX_AIN0 + ain_pos;
if (ain_pos == 0 && ain_neg == 1)
return ADS1119_MUX_AIN0_AIN1;
else if (ain_pos == 1 && ain_neg == 2)
return ADS1119_MUX_AIN1_AIN2;
else if (ain_pos == 2 && ain_neg == 3)
return ADS1119_MUX_AIN2_AIN3;
return -EINVAL;
}
static int ads1119_alloc_and_config_channels(struct iio_dev *indio_dev)
{
const struct iio_chan_spec ads1119_channel =
(const struct iio_chan_spec) {
.type = IIO_VOLTAGE,
.indexed = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SAMP_FREQ),
.info_mask_shared_by_all_available =
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
};
const struct iio_chan_spec ads1119_ts = IIO_CHAN_SOFT_TIMESTAMP(0);
struct ads1119_state *st = iio_priv(indio_dev);
struct iio_chan_spec *iio_channels, *chan;
struct device *dev = &st->client->dev;
unsigned int num_channels, i;
bool differential;
u32 ain[2];
int ret;
st->num_channels_cfg = device_get_child_node_count(dev);
if (st->num_channels_cfg > ADS1119_MAX_CHANNELS)
return dev_err_probe(dev, -EINVAL,
"Too many channels %d, max is %d\n",
st->num_channels_cfg,
ADS1119_MAX_CHANNELS);
st->channels_cfg = devm_kcalloc(dev, st->num_channels_cfg,
sizeof(*st->channels_cfg), GFP_KERNEL);
if (!st->channels_cfg)
return -ENOMEM;
/* Allocate one more iio channel for the timestamp */
num_channels = st->num_channels_cfg + 1;
iio_channels = devm_kcalloc(dev, num_channels, sizeof(*iio_channels),
GFP_KERNEL);
if (!iio_channels)
return -ENOMEM;
i = 0;
device_for_each_child_node_scoped(dev, child) {
chan = &iio_channels[i];
differential = fwnode_property_present(child, "diff-channels");
if (differential)
ret = fwnode_property_read_u32_array(child,
"diff-channels",
ain, 2);
else
ret = fwnode_property_read_u32(child, "single-channel",
&ain[0]);
if (ret)
return dev_err_probe(dev, ret,
"Failed to get channel property\n");
ret = ads1119_map_analog_inputs_mux(ain[0], ain[1],
differential);
if (ret < 0)
return dev_err_probe(dev, ret,
"Invalid channel value\n");
st->channels_cfg[i].mux = ret;
st->channels_cfg[i].gain = ADS1119_DEFAULT_GAIN;
st->channels_cfg[i].datarate = ADS1119_DEFAULT_DATARATE;
*chan = ads1119_channel;
chan->channel = ain[0];
chan->address = i;
chan->scan_index = i;
if (differential) {
chan->channel2 = ain[1];
chan->differential = 1;
}
dev_dbg(dev, "channel: index %d, mux %d\n", i,
st->channels_cfg[i].mux);
i++;
}
iio_channels[i] = ads1119_ts;
iio_channels[i].address = i;
iio_channels[i].scan_index = i;
indio_dev->channels = iio_channels;
indio_dev->num_channels = num_channels;
return 0;
}
static void ads1119_powerdown(void *data)
{
struct ads1119_state *st = data;
i2c_smbus_write_byte(st->client, ADS1119_CMD_POWERDOWN);
}
static int ads1119_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct ads1119_state *st;
struct device *dev = &client->dev;
bool vref_external = true;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return dev_err_probe(dev, -ENOMEM,
"Failed to allocate IIO device\n");
st = iio_priv(indio_dev);
st->client = client;
indio_dev->name = "ads1119";
indio_dev->info = &ads1119_info;
indio_dev->modes = INDIO_DIRECT_MODE;
i2c_set_clientdata(client, indio_dev);
ret = devm_regulator_bulk_get_enable(dev,
ARRAY_SIZE(ads1119_power_supplies),
ads1119_power_supplies);
if (ret)
return dev_err_probe(dev, ret,
"Failed to get and enable supplies\n");
st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "vref");
if (st->vref_uV == -ENODEV) {
vref_external = false;
st->vref_uV = ADS1119_VREF_INTERNAL_VAL;
} else if (st->vref_uV < 0) {
return dev_err_probe(dev, st->vref_uV, "Failed to get vref\n");
}
st->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(st->reset_gpio))
return dev_err_probe(dev, PTR_ERR(st->reset_gpio),
"Failed to get reset gpio\n");
ret = ads1119_alloc_and_config_channels(indio_dev);
if (ret)
return ret;
init_completion(&st->completion);
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
ads1119_trigger_handler,
&ads1119_buffer_setup_ops);
if (ret)
return dev_err_probe(dev, ret, "Failed to setup IIO buffer\n");
if (client->irq > 0) {
ret = devm_request_threaded_irq(dev, client->irq,
ads1119_irq_handler,
NULL, IRQF_TRIGGER_FALLING,
"ads1119", indio_dev);
if (ret)
return dev_err_probe(dev, ret,
"Failed to allocate irq\n");
st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
iio_device_id(indio_dev));
if (!st->trig)
return dev_err_probe(dev, -ENOMEM,
"Failed to allocate IIO trigger\n");
st->trig->ops = &ads1119_trigger_ops;
iio_trigger_set_drvdata(st->trig, indio_dev);
ret = devm_iio_trigger_register(dev, st->trig);
if (ret)
return dev_err_probe(dev, ret,
"Failed to register IIO trigger\n");
}
ret = ads1119_init(st, vref_external);
if (ret)
return dev_err_probe(dev, ret,
"Failed to initialize device\n");
pm_runtime_set_autosuspend_delay(dev, ADS1119_SUSPEND_DELAY);
pm_runtime_use_autosuspend(dev);
pm_runtime_mark_last_busy(dev);
pm_runtime_set_active(dev);
ret = devm_pm_runtime_enable(dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to enable pm runtime\n");
ret = devm_add_action_or_reset(dev, ads1119_powerdown, st);
if (ret)
return dev_err_probe(dev, ret,
"Failed to add powerdown action\n");
return devm_iio_device_register(dev, indio_dev);
}
static int ads1119_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct ads1119_state *st = iio_priv(indio_dev);
return i2c_smbus_write_byte(st->client, ADS1119_CMD_POWERDOWN);
}
/*
* The ADS1119 does not require a resume function because it automatically
* powers on after a reset.
* After a power down command, the ADS1119 can still communicate but turns off
* its analog parts. To resume from power down, the device will power up again
* upon receiving a start/sync command.
*/
static DEFINE_RUNTIME_DEV_PM_OPS(ads1119_pm_ops, ads1119_runtime_suspend,
NULL, NULL);
static const struct of_device_id __maybe_unused ads1119_of_match[] = {
{ .compatible = "ti,ads1119" },
{ }
};
MODULE_DEVICE_TABLE(of, ads1119_of_match);
static const struct i2c_device_id ads1119_id[] = {
{ "ads1119", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ads1119_id);
static struct i2c_driver ads1119_driver = {
.driver = {
.name = "ads1119",
.of_match_table = ads1119_of_match,
.pm = pm_ptr(&ads1119_pm_ops),
},
.probe = ads1119_probe,
.id_table = ads1119_id,
};
module_i2c_driver(ads1119_driver);
MODULE_AUTHOR("João Paulo Gonçalves <joao.goncalves@toradex.com>");
MODULE_DESCRIPTION("Texas Instruments ADS1119 ADC Driver");
MODULE_LICENSE("GPL");

View File

@ -65,7 +65,6 @@ struct ads8688_state {
struct mutex lock;
const struct ads8688_chip_info *chip_info;
struct spi_device *spi;
struct regulator *reg;
unsigned int vref_mv;
enum ads8688_range range[8];
union {
@ -423,28 +422,16 @@ static int ads8688_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
st->reg = devm_regulator_get_optional(&spi->dev, "vref");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
if (ret < 0 && ret != -ENODEV)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
goto err_regulator_disable;
st->vref_mv = ret / 1000;
} else {
/* Use internal reference */
st->vref_mv = ADS8688_VREF_MV;
}
st->vref_mv = ret == -ENODEV ? ADS8688_VREF_MV : ret / 1000;
st->chip_info = &ads8688_chip_info_tbl[spi_get_device_id(spi)->driver_data];
spi->mode = SPI_MODE_1;
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
indio_dev->name = spi_get_device_id(spi)->name;
@ -457,38 +444,13 @@ static int ads8688_probe(struct spi_device *spi)
mutex_init(&st->lock);
ret = iio_triggered_buffer_setup(indio_dev, NULL, ads8688_trigger_handler, NULL);
if (ret < 0) {
dev_err(&spi->dev, "iio triggered buffer setup failed\n");
goto err_regulator_disable;
}
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
ads8688_trigger_handler, NULL);
if (ret < 0)
return dev_err_probe(&spi->dev, ret,
"iio triggered buffer setup failed\n");
ret = iio_device_register(indio_dev);
if (ret)
goto err_buffer_cleanup;
return 0;
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
err_regulator_disable:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
}
static void ads8688_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ads8688_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ads8688_id[] = {
@ -511,7 +473,6 @@ static struct spi_driver ads8688_driver = {
.of_match_table = ads8688_of_match,
},
.probe = ads8688_probe,
.remove = ads8688_remove,
.id_table = ads8688_id,
};
module_spi_driver(ads8688_driver);

View File

@ -222,7 +222,7 @@ enum ams_ps_pl_seq {
#define PL_SEQ(x) (AMS_PS_SEQ_MAX + (x))
#define AMS_CTRL_SEQ_BASE (AMS_PS_SEQ_MAX * 3)
#define AMS_CHAN_TEMP(_scan_index, _addr) { \
#define AMS_CHAN_TEMP(_scan_index, _addr, _name) { \
.type = IIO_TEMP, \
.indexed = 1, \
.address = (_addr), \
@ -232,9 +232,10 @@ enum ams_ps_pl_seq {
.event_spec = ams_temp_events, \
.scan_index = _scan_index, \
.num_event_specs = ARRAY_SIZE(ams_temp_events), \
.datasheet_name = _name, \
}
#define AMS_CHAN_VOLTAGE(_scan_index, _addr, _alarm) { \
#define AMS_CHAN_VOLTAGE(_scan_index, _addr, _alarm, _name) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.address = (_addr), \
@ -243,21 +244,24 @@ enum ams_ps_pl_seq {
.event_spec = (_alarm) ? ams_voltage_events : NULL, \
.scan_index = _scan_index, \
.num_event_specs = (_alarm) ? ARRAY_SIZE(ams_voltage_events) : 0, \
.datasheet_name = _name, \
}
#define AMS_PS_CHAN_TEMP(_scan_index, _addr) \
AMS_CHAN_TEMP(PS_SEQ(_scan_index), _addr)
#define AMS_PS_CHAN_VOLTAGE(_scan_index, _addr) \
AMS_CHAN_VOLTAGE(PS_SEQ(_scan_index), _addr, true)
#define AMS_PS_CHAN_TEMP(_scan_index, _addr, _name) \
AMS_CHAN_TEMP(PS_SEQ(_scan_index), _addr, _name)
#define AMS_PS_CHAN_VOLTAGE(_scan_index, _addr, _name) \
AMS_CHAN_VOLTAGE(PS_SEQ(_scan_index), _addr, true, _name)
#define AMS_PL_CHAN_TEMP(_scan_index, _addr) \
AMS_CHAN_TEMP(PL_SEQ(_scan_index), _addr)
#define AMS_PL_CHAN_VOLTAGE(_scan_index, _addr, _alarm) \
AMS_CHAN_VOLTAGE(PL_SEQ(_scan_index), _addr, _alarm)
#define AMS_PL_CHAN_TEMP(_scan_index, _addr, _name) \
AMS_CHAN_TEMP(PL_SEQ(_scan_index), _addr, _name)
#define AMS_PL_CHAN_VOLTAGE(_scan_index, _addr, _alarm, _name) \
AMS_CHAN_VOLTAGE(PL_SEQ(_scan_index), _addr, _alarm, _name)
#define AMS_PL_AUX_CHAN_VOLTAGE(_auxno) \
AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(_auxno)), AMS_REG_VAUX(_auxno), false)
#define AMS_CTRL_CHAN_VOLTAGE(_scan_index, _addr) \
AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(AMS_SEQ(_scan_index))), _addr, false)
AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(_auxno)), AMS_REG_VAUX(_auxno), false, \
"VAUX" #_auxno)
#define AMS_CTRL_CHAN_VOLTAGE(_scan_index, _addr, _name) \
AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(AMS_SEQ(_scan_index))), _addr, false, \
_name)
/**
* struct ams - This structure contains necessary state for xilinx-ams to operate
@ -505,6 +509,12 @@ static int ams_init_device(struct ams *ams)
return 0;
}
static int ams_read_label(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, char *label)
{
return sysfs_emit(label, "%s\n", chan->datasheet_name);
}
static int ams_enable_single_channel(struct ams *ams, unsigned int offset)
{
u8 channel_num;
@ -1116,37 +1126,37 @@ static const struct iio_event_spec ams_voltage_events[] = {
};
static const struct iio_chan_spec ams_ps_channels[] = {
AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP),
AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP_REMOTE, AMS_TEMP_REMOTE),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS),
AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP, "Temp_LPD"),
AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP_REMOTE, AMS_TEMP_REMOTE, "Temp_FPD"),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, "VCC_PSINTLP"),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, "VCC_PSINTFP"),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, "VCC_PSAUX"),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, "VCC_PSDDR"),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, "VCC_PSIO3"),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, "VCC_PSIO0"),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, "VCC_PSIO1"),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, "VCC_PSIO2"),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, "PS_MGTRAVCC"),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, "PS_MGTRAVTT"),
AMS_PS_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, "VCC_PSADC"),
};
static const struct iio_chan_spec ams_pl_channels[] = {
AMS_PL_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, true),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, true),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFP, AMS_VREFP, false),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFN, AMS_VREFN, false),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, true),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, true),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, true),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, true),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, true),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VP_VN, AMS_VP_VN, false),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, true),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, true),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, true),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, true),
AMS_PL_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP, "Temp_PL"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, true, "VCCINT"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, true, "VCCAUX"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFP, AMS_VREFP, false, "VREFP"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFN, AMS_VREFN, false, "VREFN"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, true, "VCCBRAM"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, true, "VCC_PSINTLP"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, true, "VCC_PSINTFP"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, true, "VCC_PSAUX"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, true, "VCCAMS"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VP_VN, AMS_VP_VN, false, "VP_VN"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, true, "VUser0"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, true, "VUser1"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, true, "VUser2"),
AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, true, "VUser3"),
AMS_PL_AUX_CHAN_VOLTAGE(0),
AMS_PL_AUX_CHAN_VOLTAGE(1),
AMS_PL_AUX_CHAN_VOLTAGE(2),
@ -1166,13 +1176,13 @@ static const struct iio_chan_spec ams_pl_channels[] = {
};
static const struct iio_chan_spec ams_ctrl_channels[] = {
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSPLL, AMS_VCC_PSPLL0),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSBATT, AMS_VCC_PSPLL3),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCINT, AMS_VCCINT),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCBRAM, AMS_VCCBRAM),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCAUX, AMS_VCCAUX),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_PSDDRPLL, AMS_PSDDRPLL),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_INTDDR, AMS_PSINTFPDDR),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSPLL, AMS_VCC_PSPLL0, "VCC_PSPLL"),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSBATT, AMS_VCC_PSPLL3, "VCC_PSBATT"),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCINT, AMS_VCCINT, "VCCINT"),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCBRAM, AMS_VCCBRAM, "VCCBRAM"),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCAUX, AMS_VCCAUX, "VCCAUX"),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_PSDDRPLL, AMS_PSDDRPLL, "VCC_PSDDR_PLL"),
AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_INTDDR, AMS_PSINTFPDDR, "VCC_PSINTFP_DDR"),
};
static int ams_get_ext_chan(struct fwnode_handle *chan_node,
@ -1336,6 +1346,7 @@ static int ams_parse_firmware(struct iio_dev *indio_dev)
}
static const struct iio_info iio_ams_info = {
.read_label = ams_read_label,
.read_raw = &ams_read_raw,
.read_event_config = &ams_read_event_config,
.write_event_config = &ams_write_event_config,

View File

@ -4,6 +4,8 @@
* Author: Lars-Peter Clausen <lars@metafoo.de>
*/
#include <linux/atomic.h>
#include <linux/cleanup.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
@ -14,6 +16,8 @@
#include <linux/poll.h>
#include <linux/iio/buffer_impl.h>
#include <linux/iio/buffer-dma.h>
#include <linux/dma-buf.h>
#include <linux/dma-fence.h>
#include <linux/dma-mapping.h>
#include <linux/sizes.h>
@ -94,13 +98,18 @@ static void iio_buffer_block_release(struct kref *kref)
{
struct iio_dma_buffer_block *block = container_of(kref,
struct iio_dma_buffer_block, kref);
struct iio_dma_buffer_queue *queue = block->queue;
WARN_ON(block->state != IIO_BLOCK_STATE_DEAD);
WARN_ON(block->fileio && block->state != IIO_BLOCK_STATE_DEAD);
dma_free_coherent(block->queue->dev, PAGE_ALIGN(block->size),
block->vaddr, block->phys_addr);
if (block->fileio) {
dma_free_coherent(queue->dev, PAGE_ALIGN(block->size),
block->vaddr, block->phys_addr);
} else {
atomic_dec(&queue->num_dmabufs);
}
iio_buffer_put(&block->queue->buffer);
iio_buffer_put(&queue->buffer);
kfree(block);
}
@ -163,7 +172,7 @@ static struct iio_dma_buffer_queue *iio_buffer_to_queue(struct iio_buffer *buf)
}
static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block(
struct iio_dma_buffer_queue *queue, size_t size)
struct iio_dma_buffer_queue *queue, size_t size, bool fileio)
{
struct iio_dma_buffer_block *block;
@ -171,13 +180,16 @@ static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block(
if (!block)
return NULL;
block->vaddr = dma_alloc_coherent(queue->dev, PAGE_ALIGN(size),
&block->phys_addr, GFP_KERNEL);
if (!block->vaddr) {
kfree(block);
return NULL;
if (fileio) {
block->vaddr = dma_alloc_coherent(queue->dev, PAGE_ALIGN(size),
&block->phys_addr, GFP_KERNEL);
if (!block->vaddr) {
kfree(block);
return NULL;
}
}
block->fileio = fileio;
block->size = size;
block->state = IIO_BLOCK_STATE_DONE;
block->queue = queue;
@ -186,6 +198,9 @@ static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block(
iio_buffer_get(&queue->buffer);
if (!fileio)
atomic_inc(&queue->num_dmabufs);
return block;
}
@ -218,13 +233,20 @@ void iio_dma_buffer_block_done(struct iio_dma_buffer_block *block)
{
struct iio_dma_buffer_queue *queue = block->queue;
unsigned long flags;
bool cookie;
cookie = dma_fence_begin_signalling();
spin_lock_irqsave(&queue->list_lock, flags);
_iio_dma_buffer_block_done(block);
spin_unlock_irqrestore(&queue->list_lock, flags);
if (!block->fileio)
iio_buffer_signal_dmabuf_done(block->fence, 0);
iio_buffer_block_put_atomic(block);
iio_dma_buffer_queue_wake(queue);
dma_fence_end_signalling(cookie);
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_block_done);
@ -243,17 +265,27 @@ void iio_dma_buffer_block_list_abort(struct iio_dma_buffer_queue *queue,
{
struct iio_dma_buffer_block *block, *_block;
unsigned long flags;
bool cookie;
cookie = dma_fence_begin_signalling();
spin_lock_irqsave(&queue->list_lock, flags);
list_for_each_entry_safe(block, _block, list, head) {
list_del(&block->head);
block->bytes_used = 0;
_iio_dma_buffer_block_done(block);
if (!block->fileio)
iio_buffer_signal_dmabuf_done(block->fence, -EINTR);
iio_buffer_block_put_atomic(block);
}
spin_unlock_irqrestore(&queue->list_lock, flags);
if (queue->fileio.enabled)
queue->fileio.enabled = false;
iio_dma_buffer_queue_wake(queue);
dma_fence_end_signalling(cookie);
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_block_list_abort);
@ -273,6 +305,16 @@ static bool iio_dma_block_reusable(struct iio_dma_buffer_block *block)
}
}
static bool iio_dma_buffer_can_use_fileio(struct iio_dma_buffer_queue *queue)
{
/*
* Note that queue->num_dmabufs cannot increase while the queue is
* locked, it can only decrease, so it does not race against
* iio_dma_buffer_alloc_block().
*/
return queue->fileio.enabled || !atomic_read(&queue->num_dmabufs);
}
/**
* iio_dma_buffer_request_update() - DMA buffer request_update callback
* @buffer: The buffer which to request an update
@ -299,6 +341,12 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer)
mutex_lock(&queue->lock);
queue->fileio.enabled = iio_dma_buffer_can_use_fileio(queue);
/* If DMABUFs were created, disable fileio interface */
if (!queue->fileio.enabled)
goto out_unlock;
/* Allocations are page aligned */
if (PAGE_ALIGN(queue->fileio.block_size) == PAGE_ALIGN(size))
try_reuse = true;
@ -339,7 +387,7 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer)
}
if (!block) {
block = iio_dma_buffer_alloc_block(queue, size);
block = iio_dma_buffer_alloc_block(queue, size, true);
if (!block) {
ret = -ENOMEM;
goto out_unlock;
@ -412,8 +460,12 @@ static void iio_dma_buffer_submit_block(struct iio_dma_buffer_queue *queue,
block->state = IIO_BLOCK_STATE_ACTIVE;
iio_buffer_block_get(block);
ret = queue->ops->submit(queue, block);
if (ret) {
if (!block->fileio)
iio_buffer_signal_dmabuf_done(block->fence, ret);
/*
* This is a bit of a problem and there is not much we can do
* other then wait for the buffer to be disabled and re-enabled
@ -646,6 +698,110 @@ size_t iio_dma_buffer_usage(struct iio_buffer *buf)
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_usage);
struct iio_dma_buffer_block *
iio_dma_buffer_attach_dmabuf(struct iio_buffer *buffer,
struct dma_buf_attachment *attach)
{
struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
struct iio_dma_buffer_block *block;
guard(mutex)(&queue->lock);
/*
* If the buffer is enabled and in fileio mode new blocks can't be
* allocated.
*/
if (queue->fileio.enabled)
return ERR_PTR(-EBUSY);
block = iio_dma_buffer_alloc_block(queue, attach->dmabuf->size, false);
if (!block)
return ERR_PTR(-ENOMEM);
/* Free memory that might be in use for fileio mode */
iio_dma_buffer_fileio_free(queue);
return block;
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_attach_dmabuf);
void iio_dma_buffer_detach_dmabuf(struct iio_buffer *buffer,
struct iio_dma_buffer_block *block)
{
block->state = IIO_BLOCK_STATE_DEAD;
iio_buffer_block_put_atomic(block);
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_detach_dmabuf);
static int iio_dma_can_enqueue_block(struct iio_dma_buffer_block *block)
{
struct iio_dma_buffer_queue *queue = block->queue;
/* If in fileio mode buffers can't be enqueued. */
if (queue->fileio.enabled)
return -EBUSY;
switch (block->state) {
case IIO_BLOCK_STATE_QUEUED:
return -EPERM;
case IIO_BLOCK_STATE_ACTIVE:
case IIO_BLOCK_STATE_DEAD:
return -EBUSY;
case IIO_BLOCK_STATE_DONE:
break;
}
return 0;
}
int iio_dma_buffer_enqueue_dmabuf(struct iio_buffer *buffer,
struct iio_dma_buffer_block *block,
struct dma_fence *fence,
struct sg_table *sgt,
size_t size, bool cyclic)
{
struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
bool cookie;
int ret;
WARN_ON(!mutex_is_locked(&queue->lock));
cookie = dma_fence_begin_signalling();
ret = iio_dma_can_enqueue_block(block);
if (ret < 0)
goto out_end_signalling;
block->bytes_used = size;
block->cyclic = cyclic;
block->sg_table = sgt;
block->fence = fence;
iio_dma_buffer_enqueue(queue, block);
out_end_signalling:
dma_fence_end_signalling(cookie);
return ret;
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_enqueue_dmabuf);
void iio_dma_buffer_lock_queue(struct iio_buffer *buffer)
{
struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
mutex_lock(&queue->lock);
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_lock_queue);
void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer)
{
struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
mutex_unlock(&queue->lock);
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_unlock_queue);
/**
* iio_dma_buffer_set_bytes_per_datum() - DMA buffer set_bytes_per_datum callback
* @buffer: Buffer to set the bytes-per-datum for

View File

@ -65,25 +65,62 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue,
iio_buffer_to_dmaengine_buffer(&queue->buffer);
struct dma_async_tx_descriptor *desc;
enum dma_transfer_direction dma_dir;
struct scatterlist *sgl;
struct dma_vec *vecs;
size_t max_size;
dma_cookie_t cookie;
size_t len_total;
unsigned int i;
int nents;
max_size = min(block->size, dmaengine_buffer->max_size);
max_size = round_down(max_size, dmaengine_buffer->align);
if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) {
block->bytes_used = max_size;
if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN)
dma_dir = DMA_DEV_TO_MEM;
} else {
else
dma_dir = DMA_MEM_TO_DEV;
if (block->sg_table) {
sgl = block->sg_table->sgl;
nents = sg_nents_for_len(sgl, block->bytes_used);
if (nents < 0)
return nents;
vecs = kmalloc_array(nents, sizeof(*vecs), GFP_ATOMIC);
if (!vecs)
return -ENOMEM;
len_total = block->bytes_used;
for (i = 0; i < nents; i++) {
vecs[i].addr = sg_dma_address(sgl);
vecs[i].len = min(sg_dma_len(sgl), len_total);
len_total -= vecs[i].len;
sgl = sg_next(sgl);
}
desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan,
vecs, nents, dma_dir,
DMA_PREP_INTERRUPT);
kfree(vecs);
} else {
max_size = min(block->size, dmaengine_buffer->max_size);
max_size = round_down(max_size, dmaengine_buffer->align);
if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN)
block->bytes_used = max_size;
if (!block->bytes_used || block->bytes_used > max_size)
return -EINVAL;
desc = dmaengine_prep_slave_single(dmaengine_buffer->chan,
block->phys_addr,
block->bytes_used,
dma_dir,
DMA_PREP_INTERRUPT);
}
if (!block->bytes_used || block->bytes_used > max_size)
return -EINVAL;
desc = dmaengine_prep_slave_single(dmaengine_buffer->chan,
block->phys_addr, block->bytes_used, dma_dir,
DMA_PREP_INTERRUPT);
if (!desc)
return -ENOMEM;
@ -133,6 +170,13 @@ static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = {
.space_available = iio_dma_buffer_usage,
.release = iio_dmaengine_buffer_release,
.enqueue_dmabuf = iio_dma_buffer_enqueue_dmabuf,
.attach_dmabuf = iio_dma_buffer_attach_dmabuf,
.detach_dmabuf = iio_dma_buffer_detach_dmabuf,
.lock_queue = iio_dma_buffer_lock_queue,
.unlock_queue = iio_dma_buffer_unlock_queue,
.modes = INDIO_BUFFER_HARDWARE,
.flags = INDIO_BUFFER_FLAG_FIXED_WATERMARK,
};

View File

@ -626,12 +626,10 @@ scmi_alloc_iiodev(struct scmi_device *sdev,
SCMI_PROTOCOL_SENSOR, SCMI_EVENT_SENSOR_UPDATE,
&sensor->sensor_info->id,
&sensor->sensor_update_nb);
if (ret) {
dev_err(&iiodev->dev,
"Error in registering sensor update notifier for sensor %s err %d",
sensor->sensor_info->name, ret);
return ERR_PTR(ret);
}
if (ret)
return dev_err_ptr_probe(&iiodev->dev, ret,
"Error in registering sensor update notifier for sensor %s\n",
sensor->sensor_info->name);
scmi_iio_set_timestamp_channel(&iio_channels[i], i);
iiodev->channels = iio_channels;
@ -653,10 +651,9 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev)
return -ENODEV;
sensor_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_SENSOR, &ph);
if (IS_ERR(sensor_ops)) {
dev_err(dev, "SCMI device has no sensor interface\n");
return PTR_ERR(sensor_ops);
}
if (IS_ERR(sensor_ops))
return dev_err_probe(dev, PTR_ERR(sensor_ops),
"SCMI device has no sensor interface\n");
nr_sensors = sensor_ops->count_get(ph);
if (!nr_sensors) {
@ -667,8 +664,8 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev)
for (i = 0; i < nr_sensors; i++) {
sensor_info = sensor_ops->info_get(ph, i);
if (!sensor_info) {
dev_err(dev, "SCMI sensor %d has missing info\n", i);
return -EINVAL;
return dev_err_probe(dev, -EINVAL,
"SCMI sensor %d has missing info\n", i);
}
/* This driver only supports 3-axis accel and gyro, skipping other sensors */
@ -683,29 +680,25 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev)
scmi_iio_dev = scmi_alloc_iiodev(sdev, sensor_ops, ph,
sensor_info);
if (IS_ERR(scmi_iio_dev)) {
dev_err(dev,
"failed to allocate IIO device for sensor %s: %ld\n",
sensor_info->name, PTR_ERR(scmi_iio_dev));
return PTR_ERR(scmi_iio_dev);
return dev_err_probe(dev, PTR_ERR(scmi_iio_dev),
"failed to allocate IIO device for sensor %s\n",
sensor_info->name);
}
err = devm_iio_kfifo_buffer_setup(&scmi_iio_dev->dev,
scmi_iio_dev,
&scmi_iio_buffer_ops);
if (err < 0) {
dev_err(dev,
"IIO buffer setup error at sensor %s: %d\n",
sensor_info->name, err);
return err;
return dev_err_probe(dev, err,
"IIO buffer setup error at sensor %s\n",
sensor_info->name);
}
err = devm_iio_device_register(dev, scmi_iio_dev);
if (err) {
dev_err(dev,
"IIO device registration failed at sensor %s: %d\n",
sensor_info->name, err);
return err;
}
if (err)
return dev_err_probe(dev, err,
"IIO device registration failed at sensor %s\n",
sensor_info->name);
}
return err;
}

View File

@ -606,10 +606,9 @@ int st_sensors_verify_id(struct iio_dev *indio_dev)
}
if (sdata->sensor_settings->wai != wai) {
dev_err(&indio_dev->dev,
dev_warn(&indio_dev->dev,
"%s: WhoAmI mismatch (0x%x).\n",
indio_dev->name, wai);
return -EINVAL;
}
}

View File

@ -857,15 +857,9 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
return 0;
}
static void ad3552r_reg_disable(void *reg)
{
regulator_disable(reg);
}
static int ad3552r_configure_device(struct ad3552r_desc *dac)
{
struct device *dev = &dac->spi->dev;
struct regulator *vref;
int err, cnt = 0, voltage, delta = 100000;
u32 vals[2], val, ch;
@ -874,30 +868,16 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac),
"Error getting gpio ldac");
vref = devm_regulator_get_optional(dev, "vref");
if (IS_ERR(vref)) {
if (PTR_ERR(vref) != -ENODEV)
return dev_err_probe(dev, PTR_ERR(vref),
"Error getting vref");
voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
if (voltage < 0 && voltage != -ENODEV)
return dev_err_probe(dev, voltage, "Error getting vref voltage\n");
if (voltage == -ENODEV) {
if (device_property_read_bool(dev, "adi,vref-out-en"))
val = AD3552R_INTERNAL_VREF_PIN_2P5V;
else
val = AD3552R_INTERNAL_VREF_PIN_FLOATING;
} else {
err = regulator_enable(vref);
if (err) {
dev_err(dev, "Failed to enable external vref supply\n");
return err;
}
err = devm_add_action_or_reset(dev, ad3552r_reg_disable, vref);
if (err) {
regulator_disable(vref);
return err;
}
voltage = regulator_get_voltage(vref);
if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
dev_warn(dev, "vref-supply must be 2.5V");
return -EINVAL;

View File

@ -545,7 +545,8 @@ static int axi_dac_probe(struct platform_device *pdev)
clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
return dev_err_probe(&pdev->dev, PTR_ERR(clk),
"failed to get clock\n");
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
@ -555,7 +556,8 @@ static int axi_dac_probe(struct platform_device *pdev)
st->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&axi_dac_regmap_config);
if (IS_ERR(st->regmap))
return PTR_ERR(st->regmap);
return dev_err_probe(&pdev->dev, PTR_ERR(st->regmap),
"failed to init register map\n");
/*
* Force disable the core. Up to the frontend to enable us. And we can
@ -601,7 +603,8 @@ static int axi_dac_probe(struct platform_device *pdev)
mutex_init(&st->lock);
ret = devm_iio_backend_register(&pdev->dev, &axi_dac_generic, st);
if (ret)
return ret;
return dev_err_probe(&pdev->dev, ret,
"failed to register iio backend\n");
dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n",
ADI_AXI_PCORE_VER_MAJOR(ver),

View File

@ -860,9 +860,8 @@ static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref)
/* bring device out of reset */
gpiod_set_value_cansleep(gpio, 0);
} else {
ret = regmap_update_bits(st->regmap, LTC2688_CMD_CONFIG,
LTC2688_CONFIG_RST,
LTC2688_CONFIG_RST);
ret = regmap_set_bits(st->regmap, LTC2688_CMD_CONFIG,
LTC2688_CONFIG_RST);
if (ret)
return ret;
}

View File

@ -200,9 +200,8 @@ static int stm32_dac_core_resume(struct device *dev)
if (priv->common.hfsel) {
/* restore hfsel (maybe lost under low power state) */
ret = regmap_update_bits(priv->common.regmap, STM32_DAC_CR,
STM32H7_DAC_CR_HFSEL,
STM32H7_DAC_CR_HFSEL);
ret = regmap_set_bits(priv->common.regmap, STM32_DAC_CR,
STM32H7_DAC_CR_HFSEL);
if (ret)
return ret;
}

View File

@ -19,6 +19,7 @@
#include <linux/gpio/consumer.h>
#include <asm/div64.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@ -36,6 +37,9 @@ struct adf4350_state {
struct gpio_desc *lock_detect_gpiod;
struct adf4350_platform_data *pdata;
struct clk *clk;
struct clk *clkout;
const char *clk_out_name;
struct clk_hw hw;
unsigned long clkin;
unsigned long chspc; /* Channel Spacing */
unsigned long fpfd; /* Phase Frequency Detector */
@ -61,6 +65,8 @@ struct adf4350_state {
__be32 val __aligned(IIO_DMA_MINALIGN);
};
#define to_adf4350_state(_hw) container_of(_hw, struct adf4350_state, hw)
static struct adf4350_platform_data default_pdata = {
.channel_spacing = 10000,
.r2_user_settings = ADF4350_REG2_PD_POLARITY_POS |
@ -381,6 +387,113 @@ static const struct iio_info adf4350_info = {
.debugfs_reg_access = &adf4350_reg_access,
};
static void adf4350_clk_del_provider(void *data)
{
struct adf4350_state *st = data;
of_clk_del_provider(st->spi->dev.of_node);
}
static unsigned long adf4350_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct adf4350_state *st = to_adf4350_state(hw);
unsigned long long tmp;
tmp = (u64)(st->r0_int * st->r1_mod + st->r0_fract) * st->fpfd;
do_div(tmp, st->r1_mod * (1 << st->r4_rf_div_sel));
return tmp;
}
static int adf4350_clk_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
{
struct adf4350_state *st = to_adf4350_state(hw);
if (parent_rate == 0 || parent_rate > ADF4350_MAX_FREQ_REFIN)
return -EINVAL;
st->clkin = parent_rate;
return adf4350_set_freq(st, rate);
}
static int adf4350_clk_prepare(struct clk_hw *hw)
{
struct adf4350_state *st = to_adf4350_state(hw);
st->regs[ADF4350_REG2] &= ~ADF4350_REG2_POWER_DOWN_EN;
return adf4350_sync_config(st);
}
static void adf4350_clk_unprepare(struct clk_hw *hw)
{
struct adf4350_state *st = to_adf4350_state(hw);
st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN;
adf4350_sync_config(st);
}
static int adf4350_clk_is_enabled(struct clk_hw *hw)
{
struct adf4350_state *st = to_adf4350_state(hw);
return (st->regs[ADF4350_REG2] & ADF4350_REG2_POWER_DOWN_EN);
}
static const struct clk_ops adf4350_clk_ops = {
.recalc_rate = adf4350_clk_recalc_rate,
.set_rate = adf4350_clk_set_rate,
.prepare = adf4350_clk_prepare,
.unprepare = adf4350_clk_unprepare,
.is_enabled = adf4350_clk_is_enabled,
};
static int adf4350_clk_register(struct adf4350_state *st)
{
struct spi_device *spi = st->spi;
struct clk_init_data init;
struct clk *clk;
const char *parent_name;
int ret;
if (!device_property_present(&spi->dev, "#clock-cells"))
return 0;
if (device_property_read_string(&spi->dev, "clock-output-names", &init.name)) {
init.name = devm_kasprintf(&spi->dev, GFP_KERNEL, "%s-clk",
fwnode_get_name(dev_fwnode(&spi->dev)));
if (!init.name)
return -ENOMEM;
}
parent_name = of_clk_get_parent_name(spi->dev.of_node, 0);
if (!parent_name)
return -EINVAL;
init.ops = &adf4350_clk_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
init.flags = CLK_SET_RATE_PARENT;
st->hw.init = &init;
clk = devm_clk_register(&spi->dev, &st->hw);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = of_clk_add_provider(spi->dev.of_node, of_clk_src_simple_get, clk);
if (ret)
return ret;
st->clkout = clk;
return devm_add_action_or_reset(&spi->dev, adf4350_clk_del_provider, st);
}
static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
{
struct adf4350_platform_data *pdata;
@ -522,8 +635,6 @@ static int adf4350_probe(struct spi_device *spi)
indio_dev->info = &adf4350_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = &adf4350_chan;
indio_dev->num_channels = 1;
mutex_init(&st->lock);
@ -551,6 +662,15 @@ static int adf4350_probe(struct spi_device *spi)
return ret;
}
ret = adf4350_clk_register(st);
if (ret)
return ret;
if (!st->clkout) {
indio_dev->channels = &adf4350_chan;
indio_dev->num_channels = 1;
}
ret = devm_add_action_or_reset(&spi->dev, adf4350_power_down, indio_dev);
if (ret)
return dev_err_probe(&spi->dev, ret,

View File

@ -221,13 +221,12 @@ static ssize_t adis16136_read_frequency(struct device *dev,
unsigned int freq;
int ret;
adis_dev_lock(&adis16136->adis);
adis_dev_auto_lock(&adis16136->adis);
ret = __adis16136_get_freq(adis16136, &freq);
adis_dev_unlock(&adis16136->adis);
if (ret)
return ret;
return sprintf(buf, "%d\n", freq);
return sysfs_emit(buf, "%d\n", freq);
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
@ -251,21 +250,17 @@ static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
unsigned int freq;
int i, ret;
adis_dev_lock(&adis16136->adis);
adis_dev_auto_lock(&adis16136->adis);
ret = __adis16136_get_freq(adis16136, &freq);
if (ret)
goto out_unlock;
return ret;
for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) {
if (freq / adis16136_3db_divisors[i] >= val)
break;
}
ret = __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
out_unlock:
adis_dev_unlock(&adis16136->adis);
return ret;
return __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
}
static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
@ -275,23 +270,20 @@ static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
uint16_t val16;
int ret;
adis_dev_lock(&adis16136->adis);
adis_dev_auto_lock(&adis16136->adis);
ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT,
&val16);
if (ret)
goto err_unlock;
return ret;
ret = __adis16136_get_freq(adis16136, &freq);
if (ret)
goto err_unlock;
return ret;
*val = freq / adis16136_3db_divisors[val16 & 0x07];
err_unlock:
adis_dev_unlock(&adis16136->adis);
return ret ? ret : IIO_VAL_INT;
return IIO_VAL_INT;
}
static int adis16136_read_raw(struct iio_dev *indio_dev,

View File

@ -270,7 +270,6 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
{
struct adis16260 *adis16260 = iio_priv(indio_dev);
struct adis *adis = &adis16260->adis;
int ret;
u8 addr;
u8 t;
@ -288,7 +287,6 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
addr = adis16260_addresses[chan->scan_index][1];
return adis_write_reg_16(adis, addr, val);
case IIO_CHAN_INFO_SAMP_FREQ:
adis_dev_lock(adis);
if (spi_get_device_id(adis->spi)->driver_data)
t = 256 / val;
else
@ -298,15 +296,14 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
t = ADIS16260_SMPL_PRD_DIV_MASK;
else if (t > 0)
t--;
if (t >= 0x0A)
adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;
else
adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
ret = __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
adis_dev_unlock(adis);
return ret;
adis_dev_auto_scoped_lock(adis) {
if (t >= 0x0A)
adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;
else
adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
return __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
}
unreachable();
}
return -EINVAL;
}

View File

@ -285,8 +285,8 @@ static int bmg160_chip_init(struct bmg160_data *data)
data->slope_thres = val;
/* Set default interrupt mode */
ret = regmap_update_bits(data->regmap, BMG160_REG_INT_EN_1,
BMG160_INT1_BIT_OD, 0);
ret = regmap_clear_bits(data->regmap, BMG160_REG_INT_EN_1,
BMG160_INT1_BIT_OD);
if (ret < 0) {
dev_err(dev, "Error updating bits in reg_int_en_1\n");
return ret;

View File

@ -197,8 +197,8 @@ static int mpu3050_start_sampling(struct mpu3050 *mpu3050)
int i;
/* Reset */
ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM,
MPU3050_PWR_MGM_RESET, MPU3050_PWR_MGM_RESET);
ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM,
MPU3050_PWR_MGM_RESET);
if (ret)
return ret;
@ -513,12 +513,9 @@ static irqreturn_t mpu3050_trigger_handler(int irq, void *p)
"FIFO overflow! Emptying and resetting FIFO\n");
fifo_overflow = true;
/* Reset and enable the FIFO */
ret = regmap_update_bits(mpu3050->map,
MPU3050_USR_CTRL,
MPU3050_USR_CTRL_FIFO_EN |
MPU3050_USR_CTRL_FIFO_RST,
MPU3050_USR_CTRL_FIFO_EN |
MPU3050_USR_CTRL_FIFO_RST);
ret = regmap_set_bits(mpu3050->map, MPU3050_USR_CTRL,
MPU3050_USR_CTRL_FIFO_EN |
MPU3050_USR_CTRL_FIFO_RST);
if (ret) {
dev_info(mpu3050->dev, "error resetting FIFO\n");
goto out_trigger_unlock;
@ -799,10 +796,8 @@ static int mpu3050_hw_init(struct mpu3050 *mpu3050)
u64 otp;
/* Reset */
ret = regmap_update_bits(mpu3050->map,
MPU3050_PWR_MGM,
MPU3050_PWR_MGM_RESET,
MPU3050_PWR_MGM_RESET);
ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM,
MPU3050_PWR_MGM_RESET);
if (ret)
return ret;
@ -872,8 +867,8 @@ static int mpu3050_power_up(struct mpu3050 *mpu3050)
msleep(200);
/* Take device out of sleep mode */
ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM,
MPU3050_PWR_MGM_SLEEP, 0);
ret = regmap_clear_bits(mpu3050->map, MPU3050_PWR_MGM,
MPU3050_PWR_MGM_SLEEP);
if (ret) {
regulator_bulk_disable(ARRAY_SIZE(mpu3050->regs), mpu3050->regs);
dev_err(mpu3050->dev, "error setting power mode\n");
@ -895,8 +890,8 @@ static int mpu3050_power_down(struct mpu3050 *mpu3050)
* then we would be wasting power unless we go to sleep mode
* first.
*/
ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM,
MPU3050_PWR_MGM_SLEEP, MPU3050_PWR_MGM_SLEEP);
ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM,
MPU3050_PWR_MGM_SLEEP);
if (ret)
dev_err(mpu3050->dev, "error putting to sleep\n");
@ -997,11 +992,9 @@ static int mpu3050_drdy_trigger_set_state(struct iio_trigger *trig,
return ret;
/* Reset and enable the FIFO */
ret = regmap_update_bits(mpu3050->map, MPU3050_USR_CTRL,
MPU3050_USR_CTRL_FIFO_EN |
MPU3050_USR_CTRL_FIFO_RST,
MPU3050_USR_CTRL_FIFO_EN |
MPU3050_USR_CTRL_FIFO_RST);
ret = regmap_set_bits(mpu3050->map, MPU3050_USR_CTRL,
MPU3050_USR_CTRL_FIFO_EN |
MPU3050_USR_CTRL_FIFO_RST);
if (ret)
return ret;

View File

@ -422,9 +422,8 @@ static int afe4403_suspend(struct device *dev)
struct afe4403_data *afe = iio_priv(indio_dev);
int ret;
ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2,
AFE440X_CONTROL2_PDN_AFE,
AFE440X_CONTROL2_PDN_AFE);
ret = regmap_set_bits(afe->regmap, AFE440X_CONTROL2,
AFE440X_CONTROL2_PDN_AFE);
if (ret)
return ret;
@ -449,8 +448,8 @@ static int afe4403_resume(struct device *dev)
return ret;
}
ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2,
AFE440X_CONTROL2_PDN_AFE, 0);
ret = regmap_clear_bits(afe->regmap, AFE440X_CONTROL2,
AFE440X_CONTROL2_PDN_AFE);
if (ret)
return ret;

View File

@ -430,9 +430,8 @@ static int afe4404_suspend(struct device *dev)
struct afe4404_data *afe = iio_priv(indio_dev);
int ret;
ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2,
AFE440X_CONTROL2_PDN_AFE,
AFE440X_CONTROL2_PDN_AFE);
ret = regmap_set_bits(afe->regmap, AFE440X_CONTROL2,
AFE440X_CONTROL2_PDN_AFE);
if (ret)
return ret;
@ -457,8 +456,8 @@ static int afe4404_resume(struct device *dev)
return ret;
}
ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2,
AFE440X_CONTROL2_PDN_AFE, 0);
ret = regmap_clear_bits(afe->regmap, AFE440X_CONTROL2,
AFE440X_CONTROL2_PDN_AFE);
if (ret)
return ret;

View File

@ -363,9 +363,8 @@ static int max30100_get_temp(struct max30100_data *data, int *val)
int ret;
/* start acquisition */
ret = regmap_update_bits(data->regmap, MAX30100_REG_MODE_CONFIG,
MAX30100_REG_MODE_CONFIG_TEMP_EN,
MAX30100_REG_MODE_CONFIG_TEMP_EN);
ret = regmap_set_bits(data->regmap, MAX30100_REG_MODE_CONFIG,
MAX30100_REG_MODE_CONFIG_TEMP_EN);
if (ret)
return ret;

View File

@ -448,9 +448,8 @@ static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
}
/* start acquisition */
ret = regmap_update_bits(data->regmap, MAX30102_REG_TEMP_CONFIG,
MAX30102_REG_TEMP_CONFIG_TEMP_EN,
MAX30102_REG_TEMP_CONFIG_TEMP_EN);
ret = regmap_set_bits(data->regmap, MAX30102_REG_TEMP_CONFIG,
MAX30102_REG_TEMP_CONFIG_TEMP_EN);
if (ret)
goto out;

View File

@ -34,6 +34,10 @@ void iio_device_ioctl_handler_register(struct iio_dev *indio_dev,
struct iio_ioctl_handler *h);
void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h);
ssize_t do_iio_read_channel_label(struct iio_dev *indio_dev,
const struct iio_chan_spec *c,
char *buf);
int __iio_add_chan_devattr(const char *postfix,
struct iio_chan_spec const *chan,
ssize_t (*func)(struct device *dev,

View File

@ -466,17 +466,17 @@ int adis_single_conversion(struct iio_dev *indio_dev,
unsigned int uval;
int ret;
mutex_lock(&adis->state_lock);
guard(mutex)(&adis->state_lock);
ret = __adis_read_reg(adis, chan->address, &uval,
chan->scan_type.storagebits / 8);
if (ret)
goto err_unlock;
return ret;
if (uval & error_mask) {
ret = __adis_check_status(adis);
if (ret)
goto err_unlock;
return ret;
}
if (chan->scan_type.sign == 's')
@ -484,10 +484,7 @@ int adis_single_conversion(struct iio_dev *indio_dev,
else
*val = uval & ((1 << chan->scan_type.realbits) - 1);
ret = IIO_VAL_INT;
err_unlock:
mutex_unlock(&adis->state_lock);
return ret;
return IIO_VAL_INT;
}
EXPORT_SYMBOL_NS_GPL(adis_single_conversion, IIO_ADISLIB);

View File

@ -497,41 +497,38 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long info)
{
struct adis16400_state *st = iio_priv(indio_dev);
int ret, sps;
int sps;
switch (info) {
case IIO_CHAN_INFO_CALIBBIAS:
ret = adis_write_reg_16(&st->adis,
adis16400_addresses[chan->scan_index], val);
return ret;
return adis_write_reg_16(&st->adis,
adis16400_addresses[chan->scan_index],
val);
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
/*
* Need to cache values so we can update if the frequency
* changes.
*/
adis_dev_lock(&st->adis);
st->filt_int = val;
/* Work out update to current value */
sps = st->variant->get_freq(st);
if (sps < 0) {
adis_dev_unlock(&st->adis);
return sps;
}
adis_dev_auto_scoped_lock(&st->adis) {
st->filt_int = val;
/* Work out update to current value */
sps = st->variant->get_freq(st);
if (sps < 0)
return sps;
ret = __adis16400_set_filter(indio_dev, sps,
val * 1000 + val2 / 1000);
adis_dev_unlock(&st->adis);
return ret;
return __adis16400_set_filter(indio_dev, sps,
val * 1000 + val2 / 1000);
}
unreachable();
case IIO_CHAN_INFO_SAMP_FREQ:
sps = val * 1000 + val2 / 1000;
if (sps <= 0)
return -EINVAL;
adis_dev_lock(&st->adis);
ret = st->variant->set_freq(st, sps);
adis_dev_unlock(&st->adis);
return ret;
adis_dev_auto_scoped_lock(&st->adis)
return st->variant->set_freq(st, sps);
unreachable();
default:
return -EINVAL;
}
@ -596,29 +593,30 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
*val = st->variant->temp_offset;
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
adis_dev_lock(&st->adis);
/* Need both the number of taps and the sampling frequency */
ret = __adis_read_reg_16(&st->adis,
ADIS16400_SENS_AVG,
&val16);
if (ret) {
adis_dev_unlock(&st->adis);
return ret;
adis_dev_auto_scoped_lock(&st->adis) {
/*
* Need both the number of taps and the sampling
* frequency
*/
ret = __adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG,
&val16);
if (ret)
return ret;
ret = st->variant->get_freq(st);
if (ret)
return ret;
}
ret = st->variant->get_freq(st);
adis_dev_unlock(&st->adis);
if (ret)
return ret;
ret /= adis16400_3db_divisors[val16 & 0x07];
*val = ret / 1000;
*val2 = (ret % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
adis_dev_lock(&st->adis);
ret = st->variant->get_freq(st);
adis_dev_unlock(&st->adis);
if (ret)
return ret;
adis_dev_auto_scoped_lock(&st->adis) {
ret = st->variant->get_freq(st);
if (ret)
return ret;
}
*val = ret / 1000;
*val2 = (ret % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;

View File

@ -302,30 +302,25 @@ static int adis16475_get_freq(struct adis16475 *st, u32 *freq)
u16 dec;
u32 sample_rate = st->clk_freq;
adis_dev_lock(&st->adis);
adis_dev_auto_lock(&st->adis);
if (st->sync_mode == ADIS16475_SYNC_SCALED) {
u16 sync_scale;
ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, &sync_scale);
if (ret)
goto error;
return ret;
sample_rate = st->clk_freq * sync_scale;
}
ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, &dec);
if (ret)
goto error;
adis_dev_unlock(&st->adis);
return ret;
*freq = DIV_ROUND_CLOSEST(sample_rate, dec + 1);
return 0;
error:
adis_dev_unlock(&st->adis);
return ret;
}
static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
@ -340,7 +335,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
if (!freq)
return -EINVAL;
adis_dev_lock(&st->adis);
adis_dev_auto_lock(&st->adis);
/*
* When using sync scaled mode, the input clock needs to be scaled so that we have
* an IMU sample rate between (optimally) int_clk - 100 and int_clk + 100.
@ -385,7 +380,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
sync_scale = scaled_rate / st->clk_freq;
ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, sync_scale);
if (ret)
goto error;
return ret;
sample_rate = scaled_rate;
}
@ -400,9 +395,8 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, dec);
if (ret)
goto error;
return ret;
adis_dev_unlock(&st->adis);
/*
* If decimation is used, then gyro and accel data will have meaningful
* bits on the LSB registers. This info is used on the trigger handler.
@ -410,9 +404,6 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
assign_bit(ADIS16475_LSB_DEC_MASK, &st->lsb_flag, dec);
return 0;
error:
adis_dev_unlock(&st->adis);
return ret;
}
/* The values are approximated. */
@ -541,19 +532,15 @@ static int adis16475_buffer_postdisable(struct iio_dev *indio_dev)
struct adis *adis = &st->adis;
int ret;
adis_dev_lock(&st->adis);
adis_dev_auto_lock(&st->adis);
ret = __adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL,
ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(0));
if (ret)
goto unlock;
return ret;
ret = __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD,
ADIS16575_FIFO_FLUSH_CMD);
unlock:
adis_dev_unlock(&st->adis);
return ret;
return __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD,
ADIS16575_FIFO_FLUSH_CMD);
}
static const struct iio_buffer_setup_ops adis16475_buffer_ops = {
@ -567,20 +554,18 @@ static int adis16475_set_watermark(struct iio_dev *indio_dev, unsigned int val)
int ret;
u16 wm_lvl;
adis_dev_lock(&st->adis);
adis_dev_auto_lock(&st->adis);
val = min_t(unsigned int, val, ADIS16575_MAX_FIFO_WM);
wm_lvl = ADIS16575_WM_LVL(val - 1);
ret = __adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL, ADIS16575_WM_LVL_MASK, wm_lvl);
if (ret)
goto unlock;
return ret;
st->fifo_watermark = val;
unlock:
adis_dev_unlock(&st->adis);
return ret;
return 0;
}
static const u32 adis16475_calib_regs[] = {
@ -1745,7 +1730,7 @@ static irqreturn_t adis16475_trigger_handler_with_fifo(int irq, void *p)
int ret;
u16 fifo_cnt, i;
adis_dev_lock(&st->adis);
adis_dev_auto_lock(&st->adis);
ret = __adis_read_reg_16(adis, ADIS16575_REG_FIFO_CNT, &fifo_cnt);
if (ret)
@ -1781,7 +1766,6 @@ unlock:
* reading data from registers will impact the FIFO reading.
*/
adis16475_burst32_check(st);
adis_dev_unlock(&st->adis);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;

View File

@ -345,7 +345,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
if (t == 0)
return -EINVAL;
adis_dev_lock(&st->adis);
adis_dev_auto_lock(&st->adis);
/*
* When using PPS mode, the input clock needs to be scaled so that we have an IMU
* sample rate between (optimally) 4000 and 4250. After this, we can use the
@ -388,7 +388,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
sync_scale = scaled_rate / st->clk_freq;
ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale);
if (ret)
goto error;
return ret;
sample_rate = scaled_rate;
}
@ -400,10 +400,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
if (t > st->chip_info->max_dec_rate)
t = st->chip_info->max_dec_rate;
ret = __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
error:
adis_dev_unlock(&st->adis);
return ret;
return __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
}
static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
@ -413,23 +410,21 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
int ret;
unsigned int freq, sample_rate = st->clk_freq;
adis_dev_lock(&st->adis);
adis_dev_auto_lock(&st->adis);
if (st->clk_mode == ADIS16480_CLK_PPS) {
u16 sync_scale;
ret = __adis_read_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, &sync_scale);
if (ret)
goto error;
return ret;
sample_rate = st->clk_freq * sync_scale;
}
ret = __adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
if (ret)
goto error;
adis_dev_unlock(&st->adis);
return ret;
freq = DIV_ROUND_CLOSEST(sample_rate, (t + 1));
@ -437,9 +432,6 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
*val2 = (freq % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
error:
adis_dev_unlock(&st->adis);
return ret;
}
enum {
@ -630,11 +622,11 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
offset = ad16480_filter_data[chan->scan_index][1];
enable_mask = BIT(offset + 2);
adis_dev_lock(&st->adis);
adis_dev_auto_lock(&st->adis);
ret = __adis_read_reg_16(&st->adis, reg, &val);
if (ret)
goto out_unlock;
return ret;
if (freq == 0) {
val &= ~enable_mask;
@ -656,11 +648,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
val |= enable_mask;
}
ret = __adis_write_reg_16(&st->adis, reg, val);
out_unlock:
adis_dev_unlock(&st->adis);
return ret;
return __adis_write_reg_16(&st->adis, reg, val);
}
static int adis16480_read_raw(struct iio_dev *indio_dev,
@ -1355,29 +1343,26 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
u32 crc;
bool valid;
adis_dev_lock(adis);
if (adis->current_page != 0) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = 0;
ret = spi_write(adis->spi, adis->tx, 2);
if (ret) {
dev_err(dev, "Failed to change device page: %d\n", ret);
adis_dev_unlock(adis);
goto irq_done;
adis_dev_auto_scoped_lock(adis) {
if (adis->current_page != 0) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = 0;
ret = spi_write(adis->spi, adis->tx, 2);
if (ret) {
dev_err(dev, "Failed to change device page: %d\n", ret);
goto irq_done;
}
adis->current_page = 0;
}
adis->current_page = 0;
ret = spi_sync(adis->spi, &adis->msg);
if (ret) {
dev_err(dev, "Failed to read data: %d\n", ret);
goto irq_done;
}
}
ret = spi_sync(adis->spi, &adis->msg);
if (ret) {
dev_err(dev, "Failed to read data: %d\n", ret);
adis_dev_unlock(adis);
goto irq_done;
}
adis_dev_unlock(adis);
/*
* After making the burst request, the response can have one or two
* 16-bit responses containing the BURST_ID depending on the sclk. If

View File

@ -126,6 +126,26 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
}
EXPORT_SYMBOL_NS_GPL(adis_update_scan_mode, IIO_ADISLIB);
static int adis_paging_trigger_handler(struct adis *adis)
{
int ret;
guard(mutex)(&adis->state_lock);
if (adis->current_page != 0) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = 0;
ret = spi_write(adis->spi, adis->tx, 2);
if (ret) {
dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret);
return ret;
}
adis->current_page = 0;
}
return spi_sync(adis->spi, &adis->msg);
}
static irqreturn_t adis_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
@ -133,25 +153,10 @@ static irqreturn_t adis_trigger_handler(int irq, void *p)
struct adis *adis = iio_device_get_drvdata(indio_dev);
int ret;
if (adis->data->has_paging) {
mutex_lock(&adis->state_lock);
if (adis->current_page != 0) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = 0;
ret = spi_write(adis->spi, adis->tx, 2);
if (ret) {
dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret);
mutex_unlock(&adis->state_lock);
goto irq_done;
}
adis->current_page = 0;
}
}
ret = spi_sync(adis->spi, &adis->msg);
if (adis->data->has_paging)
mutex_unlock(&adis->state_lock);
ret = adis_paging_trigger_handler(adis);
else
ret = spi_sync(adis->spi, &adis->msg);
if (ret) {
dev_err(&adis->spi->dev, "Failed to read data: %d", ret);
goto irq_done;

View File

@ -274,9 +274,8 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st)
/* restore watermark interrupt */
if (restore) {
ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN,
INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
ret = regmap_set_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
if (ret)
return ret;
}
@ -318,9 +317,8 @@ static int inv_icm42600_buffer_postenable(struct iio_dev *indio_dev)
}
/* set FIFO threshold interrupt */
ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN,
INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
ret = regmap_set_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
if (ret)
goto out_unlock;
@ -375,8 +373,8 @@ static int inv_icm42600_buffer_predisable(struct iio_dev *indio_dev)
goto out_unlock;
/* disable FIFO threshold interrupt */
ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN, 0);
ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
if (ret)
goto out_unlock;

View File

@ -496,9 +496,8 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st,
return ret;
/* sensor data in big-endian (default) */
ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN,
INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
ret = regmap_set_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
if (ret)
return ret;
@ -603,8 +602,8 @@ static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq,
return ret;
/* Deassert async reset for proper INT pin operation (cf datasheet) */
ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1,
INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0);
ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INT_CONFIG1,
INV_ICM42600_INT_CONFIG1_ASYNC_RESET);
if (ret)
return ret;

View File

@ -28,8 +28,8 @@ static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st)
INV_ICM42600_INTF_CONFIG6_MASK,
INV_ICM42600_INTF_CONFIG6_I3C_EN);
ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4,
INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0);
ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4,
INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY);
if (ret)
return ret;

View File

@ -27,8 +27,8 @@ static int inv_icm42600_spi_bus_setup(struct inv_icm42600_state *st)
if (ret)
return ret;
ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4,
INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0);
ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4,
INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY);
if (ret)
return ret;

View File

@ -561,11 +561,9 @@ struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name)
}
fwnode = fwnode_find_reference(dev_fwnode(dev), "io-backends", index);
if (IS_ERR(fwnode)) {
dev_err_probe(dev, PTR_ERR(fwnode),
"Cannot get Firmware reference\n");
return ERR_CAST(fwnode);
}
if (IS_ERR(fwnode))
return dev_err_cast_probe(dev, fwnode,
"Cannot get Firmware reference\n");
guard(mutex)(&iio_back_lock);
list_for_each_entry(back, &iio_back_list, entry) {

View File

@ -9,15 +9,20 @@
* - Better memory allocation techniques?
* - Alternative access techniques?
*/
#include <linux/atomic.h>
#include <linux/anon_inodes.h>
#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/device.h>
#include <linux/dma-buf.h>
#include <linux/dma-fence.h>
#include <linux/dma-resv.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/sched/signal.h>
@ -29,6 +34,34 @@
#include <linux/iio/buffer.h>
#include <linux/iio/buffer_impl.h>
#define DMABUF_ENQUEUE_TIMEOUT_MS 5000
MODULE_IMPORT_NS(DMA_BUF);
struct iio_dmabuf_priv {
struct list_head entry;
struct kref ref;
struct iio_buffer *buffer;
struct iio_dma_buffer_block *block;
u64 context;
/* Spinlock used for locking the dma_fence */
spinlock_t lock;
struct dma_buf_attachment *attach;
struct sg_table *sgt;
enum dma_data_direction dir;
atomic_t seqno;
};
struct iio_dma_fence {
struct dma_fence base;
struct iio_dmabuf_priv *priv;
struct work_struct work;
};
static const char * const iio_endian_prefix[] = {
[IIO_BE] = "be",
[IIO_LE] = "le",
@ -333,6 +366,8 @@ void iio_buffer_init(struct iio_buffer *buffer)
{
INIT_LIST_HEAD(&buffer->demux_list);
INIT_LIST_HEAD(&buffer->buffer_list);
INIT_LIST_HEAD(&buffer->dmabufs);
mutex_init(&buffer->dmabufs_mutex);
init_waitqueue_head(&buffer->pollq);
kref_init(&buffer->ref);
if (!buffer->watermark)
@ -1526,14 +1561,55 @@ static void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev)
kfree(iio_dev_opaque->legacy_scan_el_group.attrs);
}
static void iio_buffer_dmabuf_release(struct kref *ref)
{
struct iio_dmabuf_priv *priv = container_of(ref, struct iio_dmabuf_priv, ref);
struct dma_buf_attachment *attach = priv->attach;
struct iio_buffer *buffer = priv->buffer;
struct dma_buf *dmabuf = attach->dmabuf;
dma_resv_lock(dmabuf->resv, NULL);
dma_buf_unmap_attachment(attach, priv->sgt, priv->dir);
dma_resv_unlock(dmabuf->resv);
buffer->access->detach_dmabuf(buffer, priv->block);
dma_buf_detach(attach->dmabuf, attach);
dma_buf_put(dmabuf);
kfree(priv);
}
static void iio_buffer_dmabuf_get(struct dma_buf_attachment *attach)
{
struct iio_dmabuf_priv *priv = attach->importer_priv;
kref_get(&priv->ref);
}
static void iio_buffer_dmabuf_put(struct dma_buf_attachment *attach)
{
struct iio_dmabuf_priv *priv = attach->importer_priv;
kref_put(&priv->ref, iio_buffer_dmabuf_release);
}
static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep)
{
struct iio_dev_buffer_pair *ib = filep->private_data;
struct iio_dev *indio_dev = ib->indio_dev;
struct iio_buffer *buffer = ib->buffer;
struct iio_dmabuf_priv *priv, *tmp;
wake_up(&buffer->pollq);
guard(mutex)(&buffer->dmabufs_mutex);
/* Close all attached DMABUFs */
list_for_each_entry_safe(priv, tmp, &buffer->dmabufs, entry) {
list_del_init(&priv->entry);
iio_buffer_dmabuf_put(priv->attach);
}
kfree(ib);
clear_bit(IIO_BUSY_BIT_POS, &buffer->flags);
iio_device_put(indio_dev);
@ -1541,11 +1617,393 @@ static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep)
return 0;
}
static int iio_dma_resv_lock(struct dma_buf *dmabuf, bool nonblock)
{
if (!nonblock)
return dma_resv_lock_interruptible(dmabuf->resv, NULL);
if (!dma_resv_trylock(dmabuf->resv))
return -EBUSY;
return 0;
}
static struct dma_buf_attachment *
iio_buffer_find_attachment(struct iio_dev_buffer_pair *ib,
struct dma_buf *dmabuf, bool nonblock)
{
struct device *dev = ib->indio_dev->dev.parent;
struct iio_buffer *buffer = ib->buffer;
struct dma_buf_attachment *attach = NULL;
struct iio_dmabuf_priv *priv;
guard(mutex)(&buffer->dmabufs_mutex);
list_for_each_entry(priv, &buffer->dmabufs, entry) {
if (priv->attach->dev == dev
&& priv->attach->dmabuf == dmabuf) {
attach = priv->attach;
break;
}
}
if (attach)
iio_buffer_dmabuf_get(attach);
return attach ?: ERR_PTR(-EPERM);
}
static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib,
int __user *user_fd, bool nonblock)
{
struct iio_dev *indio_dev = ib->indio_dev;
struct iio_buffer *buffer = ib->buffer;
struct dma_buf_attachment *attach;
struct iio_dmabuf_priv *priv, *each;
struct dma_buf *dmabuf;
int err, fd;
if (!buffer->access->attach_dmabuf
|| !buffer->access->detach_dmabuf
|| !buffer->access->enqueue_dmabuf)
return -EPERM;
if (copy_from_user(&fd, user_fd, sizeof(fd)))
return -EFAULT;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
spin_lock_init(&priv->lock);
priv->context = dma_fence_context_alloc(1);
dmabuf = dma_buf_get(fd);
if (IS_ERR(dmabuf)) {
err = PTR_ERR(dmabuf);
goto err_free_priv;
}
attach = dma_buf_attach(dmabuf, indio_dev->dev.parent);
if (IS_ERR(attach)) {
err = PTR_ERR(attach);
goto err_dmabuf_put;
}
err = iio_dma_resv_lock(dmabuf, nonblock);
if (err)
goto err_dmabuf_detach;
priv->dir = buffer->direction == IIO_BUFFER_DIRECTION_IN
? DMA_FROM_DEVICE : DMA_TO_DEVICE;
priv->sgt = dma_buf_map_attachment(attach, priv->dir);
if (IS_ERR(priv->sgt)) {
err = PTR_ERR(priv->sgt);
dev_err(&indio_dev->dev, "Unable to map attachment: %d\n", err);
goto err_resv_unlock;
}
kref_init(&priv->ref);
priv->buffer = buffer;
priv->attach = attach;
attach->importer_priv = priv;
priv->block = buffer->access->attach_dmabuf(buffer, attach);
if (IS_ERR(priv->block)) {
err = PTR_ERR(priv->block);
goto err_dmabuf_unmap_attachment;
}
dma_resv_unlock(dmabuf->resv);
mutex_lock(&buffer->dmabufs_mutex);
/*
* Check whether we already have an attachment for this driver/DMABUF
* combo. If we do, refuse to attach.
*/
list_for_each_entry(each, &buffer->dmabufs, entry) {
if (each->attach->dev == indio_dev->dev.parent
&& each->attach->dmabuf == dmabuf) {
/*
* We unlocked the reservation object, so going through
* the cleanup code would mean re-locking it first.
* At this stage it is simpler to free the attachment
* using iio_buffer_dma_put().
*/
mutex_unlock(&buffer->dmabufs_mutex);
iio_buffer_dmabuf_put(attach);
return -EBUSY;
}
}
/* Otherwise, add the new attachment to our dmabufs list. */
list_add(&priv->entry, &buffer->dmabufs);
mutex_unlock(&buffer->dmabufs_mutex);
return 0;
err_dmabuf_unmap_attachment:
dma_buf_unmap_attachment(attach, priv->sgt, priv->dir);
err_resv_unlock:
dma_resv_unlock(dmabuf->resv);
err_dmabuf_detach:
dma_buf_detach(dmabuf, attach);
err_dmabuf_put:
dma_buf_put(dmabuf);
err_free_priv:
kfree(priv);
return err;
}
static int iio_buffer_detach_dmabuf(struct iio_dev_buffer_pair *ib,
int __user *user_req, bool nonblock)
{
struct iio_buffer *buffer = ib->buffer;
struct iio_dev *indio_dev = ib->indio_dev;
struct iio_dmabuf_priv *priv;
struct dma_buf *dmabuf;
int dmabuf_fd, ret = -EPERM;
if (copy_from_user(&dmabuf_fd, user_req, sizeof(dmabuf_fd)))
return -EFAULT;
dmabuf = dma_buf_get(dmabuf_fd);
if (IS_ERR(dmabuf))
return PTR_ERR(dmabuf);
guard(mutex)(&buffer->dmabufs_mutex);
list_for_each_entry(priv, &buffer->dmabufs, entry) {
if (priv->attach->dev == indio_dev->dev.parent
&& priv->attach->dmabuf == dmabuf) {
list_del(&priv->entry);
/* Unref the reference from iio_buffer_attach_dmabuf() */
iio_buffer_dmabuf_put(priv->attach);
ret = 0;
break;
}
}
dma_buf_put(dmabuf);
return ret;
}
static const char *
iio_buffer_dma_fence_get_driver_name(struct dma_fence *fence)
{
return "iio";
}
static void iio_buffer_dma_fence_release(struct dma_fence *fence)
{
struct iio_dma_fence *iio_fence =
container_of(fence, struct iio_dma_fence, base);
kfree(iio_fence);
}
static const struct dma_fence_ops iio_buffer_dma_fence_ops = {
.get_driver_name = iio_buffer_dma_fence_get_driver_name,
.get_timeline_name = iio_buffer_dma_fence_get_driver_name,
.release = iio_buffer_dma_fence_release,
};
static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib,
struct iio_dmabuf __user *iio_dmabuf_req,
bool nonblock)
{
struct iio_buffer *buffer = ib->buffer;
struct iio_dmabuf iio_dmabuf;
struct dma_buf_attachment *attach;
struct iio_dmabuf_priv *priv;
struct iio_dma_fence *fence;
struct dma_buf *dmabuf;
unsigned long timeout;
bool cookie, cyclic, dma_to_ram;
long retl;
u32 seqno;
int ret;
if (copy_from_user(&iio_dmabuf, iio_dmabuf_req, sizeof(iio_dmabuf)))
return -EFAULT;
if (iio_dmabuf.flags & ~IIO_BUFFER_DMABUF_SUPPORTED_FLAGS)
return -EINVAL;
cyclic = iio_dmabuf.flags & IIO_BUFFER_DMABUF_CYCLIC;
/* Cyclic flag is only supported on output buffers */
if (cyclic && buffer->direction != IIO_BUFFER_DIRECTION_OUT)
return -EINVAL;
dmabuf = dma_buf_get(iio_dmabuf.fd);
if (IS_ERR(dmabuf))
return PTR_ERR(dmabuf);
if (!iio_dmabuf.bytes_used || iio_dmabuf.bytes_used > dmabuf->size) {
ret = -EINVAL;
goto err_dmabuf_put;
}
attach = iio_buffer_find_attachment(ib, dmabuf, nonblock);
if (IS_ERR(attach)) {
ret = PTR_ERR(attach);
goto err_dmabuf_put;
}
priv = attach->importer_priv;
fence = kmalloc(sizeof(*fence), GFP_KERNEL);
if (!fence) {
ret = -ENOMEM;
goto err_attachment_put;
}
fence->priv = priv;
seqno = atomic_add_return(1, &priv->seqno);
/*
* The transfers are guaranteed to be processed in the order they are
* enqueued, so we can use a simple incrementing sequence number for
* the dma_fence.
*/
dma_fence_init(&fence->base, &iio_buffer_dma_fence_ops,
&priv->lock, priv->context, seqno);
ret = iio_dma_resv_lock(dmabuf, nonblock);
if (ret)
goto err_fence_put;
timeout = nonblock ? 0 : msecs_to_jiffies(DMABUF_ENQUEUE_TIMEOUT_MS);
dma_to_ram = buffer->direction == IIO_BUFFER_DIRECTION_IN;
/* Make sure we don't have writers */
retl = dma_resv_wait_timeout(dmabuf->resv,
dma_resv_usage_rw(dma_to_ram),
true, timeout);
if (retl == 0)
retl = -EBUSY;
if (retl < 0) {
ret = (int)retl;
goto err_resv_unlock;
}
if (buffer->access->lock_queue)
buffer->access->lock_queue(buffer);
ret = dma_resv_reserve_fences(dmabuf->resv, 1);
if (ret)
goto err_queue_unlock;
dma_resv_add_fence(dmabuf->resv, &fence->base,
dma_to_ram ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ);
dma_resv_unlock(dmabuf->resv);
cookie = dma_fence_begin_signalling();
ret = buffer->access->enqueue_dmabuf(buffer, priv->block, &fence->base,
priv->sgt, iio_dmabuf.bytes_used,
cyclic);
if (ret) {
/*
* DMABUF enqueue failed, but we already added the fence.
* Signal the error through the fence completion mechanism.
*/
iio_buffer_signal_dmabuf_done(&fence->base, ret);
}
if (buffer->access->unlock_queue)
buffer->access->unlock_queue(buffer);
dma_fence_end_signalling(cookie);
dma_buf_put(dmabuf);
return ret;
err_queue_unlock:
if (buffer->access->unlock_queue)
buffer->access->unlock_queue(buffer);
err_resv_unlock:
dma_resv_unlock(dmabuf->resv);
err_fence_put:
dma_fence_put(&fence->base);
err_attachment_put:
iio_buffer_dmabuf_put(attach);
err_dmabuf_put:
dma_buf_put(dmabuf);
return ret;
}
static void iio_buffer_cleanup(struct work_struct *work)
{
struct iio_dma_fence *fence =
container_of(work, struct iio_dma_fence, work);
struct iio_dmabuf_priv *priv = fence->priv;
struct dma_buf_attachment *attach = priv->attach;
dma_fence_put(&fence->base);
iio_buffer_dmabuf_put(attach);
}
void iio_buffer_signal_dmabuf_done(struct dma_fence *fence, int ret)
{
struct iio_dma_fence *iio_fence =
container_of(fence, struct iio_dma_fence, base);
bool cookie = dma_fence_begin_signalling();
/*
* Get a reference to the fence, so that it's not freed as soon as
* it's signaled.
*/
dma_fence_get(fence);
fence->error = ret;
dma_fence_signal(fence);
dma_fence_end_signalling(cookie);
/*
* The fence will be unref'd in iio_buffer_cleanup.
* It can't be done here, as the unref functions might try to lock the
* resv object, which can deadlock.
*/
INIT_WORK(&iio_fence->work, iio_buffer_cleanup);
schedule_work(&iio_fence->work);
}
EXPORT_SYMBOL_GPL(iio_buffer_signal_dmabuf_done);
static long iio_buffer_chrdev_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct iio_dev_buffer_pair *ib = filp->private_data;
void __user *_arg = (void __user *)arg;
bool nonblock = filp->f_flags & O_NONBLOCK;
switch (cmd) {
case IIO_BUFFER_DMABUF_ATTACH_IOCTL:
return iio_buffer_attach_dmabuf(ib, _arg, nonblock);
case IIO_BUFFER_DMABUF_DETACH_IOCTL:
return iio_buffer_detach_dmabuf(ib, _arg, nonblock);
case IIO_BUFFER_DMABUF_ENQUEUE_IOCTL:
return iio_buffer_enqueue_dmabuf(ib, _arg, nonblock);
default:
return -EINVAL;
}
}
static const struct file_operations iio_buffer_chrdev_fileops = {
.owner = THIS_MODULE,
.llseek = noop_llseek,
.read = iio_buffer_read,
.write = iio_buffer_write,
.unlocked_ioctl = iio_buffer_chrdev_ioctl,
.compat_ioctl = compat_ptr_ioctl,
.poll = iio_buffer_poll,
.release = iio_buffer_chrdev_release,
};
@ -1994,6 +2452,7 @@ static void iio_buffer_release(struct kref *ref)
{
struct iio_buffer *buffer = container_of(ref, struct iio_buffer, ref);
mutex_destroy(&buffer->dmabufs_mutex);
buffer->access->release(buffer);
}

View File

@ -727,20 +727,25 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
}
EXPORT_SYMBOL_GPL(iio_format_value);
ssize_t do_iio_read_channel_label(struct iio_dev *indio_dev,
const struct iio_chan_spec *c,
char *buf)
{
if (indio_dev->info->read_label)
return indio_dev->info->read_label(indio_dev, c, buf);
if (c->extend_name)
return sysfs_emit(buf, "%s\n", c->extend_name);
return -EINVAL;
}
static ssize_t iio_read_channel_label(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);
if (indio_dev->info->read_label)
return indio_dev->info->read_label(indio_dev, this_attr->c, buf);
if (this_attr->c->extend_name)
return sysfs_emit(buf, "%s\n", this_attr->c->extend_name);
return -EINVAL;
return do_iio_read_channel_label(dev_to_iio_dev(dev),
to_iio_dev_attr(attr)->c, buf);
}
static ssize_t iio_read_channel_info(struct device *dev,

View File

@ -1010,3 +1010,9 @@ ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
chan->channel, buf, len);
}
EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf)
{
return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf);
}
EXPORT_SYMBOL_GPL(iio_read_channel_label);

View File

@ -539,9 +539,8 @@ static int adux1020_write_event_config(struct iio_dev *indio_dev,
* Trigger proximity interrupt when the intensity is above
* or below threshold
*/
ret = regmap_update_bits(data->regmap, ADUX1020_REG_PROX_TYPE,
ADUX1020_PROX_TYPE,
ADUX1020_PROX_TYPE);
ret = regmap_set_bits(data->regmap, ADUX1020_REG_PROX_TYPE,
ADUX1020_PROX_TYPE);
if (ret < 0)
goto fail;
@ -748,8 +747,8 @@ static int adux1020_chip_init(struct adux1020_data *data)
dev_dbg(&client->dev, "Detected ADUX1020 with chip id: 0x%04x\n", val);
ret = regmap_update_bits(data->regmap, ADUX1020_REG_SW_RESET,
ADUX1020_SW_RESET, ADUX1020_SW_RESET);
ret = regmap_set_bits(data->regmap, ADUX1020_REG_SW_RESET,
ADUX1020_SW_RESET);
if (ret < 0)
return ret;
@ -764,8 +763,8 @@ static int adux1020_chip_init(struct adux1020_data *data)
return ret;
/* Use LED_IREF for proximity mode */
ret = regmap_update_bits(data->regmap, ADUX1020_REG_LED_CURRENT,
ADUX1020_LED_PIREF_EN, 0);
ret = regmap_clear_bits(data->regmap, ADUX1020_REG_LED_CURRENT,
ADUX1020_LED_PIREF_EN);
if (ret < 0)
return ret;

View File

@ -86,8 +86,8 @@ static int iqs621_als_init(struct iqs621_als_private *iqs621_als)
if (iqs621_als->prox_en)
event_mask |= iqs62x->dev_desc->ir_mask;
return regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
event_mask, 0);
return regmap_clear_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
event_mask);
}
static int iqs621_als_notifier(struct notifier_block *notifier,

View File

@ -550,9 +550,9 @@ static int isl29018_chip_init(struct isl29018_chip *chip)
return -ENODEV;
/* Clear brownout bit */
status = regmap_update_bits(chip->regmap,
ISL29035_REG_DEVICE_ID,
ISL29035_BOUT_MASK, 0);
status = regmap_clear_bits(chip->regmap,
ISL29035_REG_DEVICE_ID,
ISL29035_BOUT_MASK);
if (status < 0)
return status;
}

View File

@ -330,8 +330,8 @@ static int st_uvis25_suspend(struct device *dev)
struct iio_dev *iio_dev = dev_get_drvdata(dev);
struct st_uvis25_hw *hw = iio_priv(iio_dev);
return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
ST_UVIS25_REG_ODR_MASK, 0);
return regmap_clear_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
ST_UVIS25_REG_ODR_MASK);
}
static int st_uvis25_resume(struct device *dev)

View File

@ -144,8 +144,8 @@ static const struct attribute_group veml6030_event_attr_group = {
static int veml6030_als_pwr_on(struct veml6030_data *data)
{
return regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
VEML6030_ALS_SD, 0);
return regmap_clear_bits(data->regmap, VEML6030_REG_ALS_CONF,
VEML6030_ALS_SD);
}
static int veml6030_als_shut_down(struct veml6030_data *data)

View File

@ -327,10 +327,7 @@ static int ak8974_trigmeas(struct ak8974 *ak8974)
}
/* Force a measurement */
return regmap_update_bits(ak8974->map,
AK8974_CTRL3,
AK8974_CTRL3_FORCE,
AK8974_CTRL3_FORCE);
return regmap_set_bits(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_FORCE);
}
static int ak8974_await_drdy(struct ak8974 *ak8974)
@ -438,10 +435,7 @@ static int ak8974_selftest(struct ak8974 *ak8974)
}
/* Trigger self-test */
ret = regmap_update_bits(ak8974->map,
AK8974_CTRL3,
AK8974_CTRL3_SELFTEST,
AK8974_CTRL3_SELFTEST);
ret = regmap_set_bits(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_SELFTEST);
if (ret) {
dev_err(dev, "could not write CTRL3\n");
return ret;

View File

@ -186,9 +186,8 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set)
* Recharge the capacitor at VCAP pin, requested to be issued
* before a SET/RESET command.
*/
ret = regmap_update_bits(data->regmap, MMC35240_REG_CTRL0,
MMC35240_CTRL0_REFILL_BIT,
MMC35240_CTRL0_REFILL_BIT);
ret = regmap_set_bits(data->regmap, MMC35240_REG_CTRL0,
MMC35240_CTRL0_REFILL_BIT);
if (ret < 0)
return ret;
usleep_range(MMC35240_WAIT_CHARGE_PUMP, MMC35240_WAIT_CHARGE_PUMP + 1);
@ -198,8 +197,7 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set)
else
coil_bit = MMC35240_CTRL0_RESET_BIT;
return regmap_update_bits(data->regmap, MMC35240_REG_CTRL0,
coil_bit, coil_bit);
return regmap_set_bits(data->regmap, MMC35240_REG_CTRL0, coil_bit);
}

View File

@ -1645,8 +1645,8 @@ static int bmp580_nvmem_write_impl(void *priv, unsigned int offset, void *val,
goto exit;
/* Disable programming mode bit */
ret = regmap_update_bits(data->regmap, BMP580_REG_NVM_ADDR,
BMP580_NVM_PROG_EN, 0);
ret = regmap_clear_bits(data->regmap, BMP580_REG_NVM_ADDR,
BMP580_NVM_PROG_EN);
if (ret) {
dev_err(data->dev, "error resetting nvm write\n");
goto exit;

View File

@ -835,9 +835,8 @@ static int sx9324_init_compensation(struct iio_dev *indio_dev)
int ret;
/* run the compensation phase on all channels */
ret = regmap_update_bits(data->regmap, SX9324_REG_STAT2,
SX9324_REG_STAT2_COMPSTAT_MASK,
SX9324_REG_STAT2_COMPSTAT_MASK);
ret = regmap_set_bits(data->regmap, SX9324_REG_STAT2,
SX9324_REG_STAT2_COMPSTAT_MASK);
if (ret)
return ret;

View File

@ -672,9 +672,8 @@ static int sx9360_init_compensation(struct iio_dev *indio_dev)
int ret;
/* run the compensation phase on all channels */
ret = regmap_update_bits(data->regmap, SX9360_REG_STAT,
SX9360_REG_STAT_COMPSTAT_MASK,
SX9360_REG_STAT_COMPSTAT_MASK);
ret = regmap_set_bits(data->regmap, SX9360_REG_STAT,
SX9360_REG_STAT_COMPSTAT_MASK);
if (ret)
return ret;

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