Merge branch 'togreg' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git

This commit is contained in:
Stephen Rothwell 2024-12-20 14:20:08 +11:00
commit 7af5576bb3
80 changed files with 2079 additions and 2742 deletions

View File

@ -0,0 +1,23 @@
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sys_calibration
KernelVersion: 5.5
Contact: linux-iio@vger.kernel.org
Description:
This attribute, if available, initiates the system calibration procedure. This is done on a
single channel at a time. Write '1' to start the calibration.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sys_calibration_mode_available
KernelVersion: 5.5
Contact: linux-iio@vger.kernel.org
Description:
This attribute, if available, returns a list with the possible calibration modes.
There are two available options:
"zero_scale" - calibrate to zero scale
"full_scale" - calibrate to full scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sys_calibration_mode
KernelVersion: 5.5
Contact: linux-iio@vger.kernel.org
Description:
This attribute, if available, sets up the calibration mode used in the system calibration
procedure. Reading returns the current calibration mode.
Writing sets the system calibration mode.

View File

@ -19,33 +19,9 @@ Description:
the bridge can be disconnected (when it is not being used
using the bridge_switch_en attribute.
What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration
KernelVersion:
Contact: linux-iio@vger.kernel.org
Description:
Initiates the system calibration procedure. This is done on a
single channel at a time. Write '1' to start the calibration.
What: /sys/bus/iio/devices/iio:deviceX/in_voltage2-voltage2_shorted_raw
KernelVersion:
Contact: linux-iio@vger.kernel.org
Description:
Measure voltage from AIN2 pin connected to AIN(+)
and AIN(-) shorted.
What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration_mode_available
KernelVersion:
Contact: linux-iio@vger.kernel.org
Description:
Reading returns a list with the possible calibration modes.
There are two available options:
"zero_scale" - calibrate to zero scale
"full_scale" - calibrate to full scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration_mode
KernelVersion:
Contact: linux-iio@vger.kernel.org
Description:
Sets up the calibration mode used in the system calibration
procedure. Reading returns the current calibration mode.
Writing sets the system calibration mode.

View File

@ -4,23 +4,26 @@
$id: http://devicetree.org/schemas/iio/accel/kionix,kx022a.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ROHM/Kionix KX022A, KX132-1211 and KX132ACR-LBZ Accelerometers
title: ROHM/Kionix KX022A, KX132/134-1211 and KX132/134ACR-LBZ Accelerometers
maintainers:
- Matti Vaittinen <mazziesaccount@gmail.com>
description: |
KX022A, KX132ACR-LBZ and KX132-1211 are 3-axis accelerometers supporting
+/- 2G, 4G, 8G and 16G ranges, variable output data-rates and a
hardware-fifo buffering. These accelerometers can be accessed either
via I2C or SPI.
+/- 2G, 4G, 8G and 16G ranges. The KX134ACR-LBZ and KX134-1211 support
+/- 8G, 16G, 32G and 64G. All the sensors also have variable output
data-rates and a hardware-fifo buffering. These accelerometers can be
accessed either via I2C or SPI.
properties:
compatible:
enum:
- kionix,kx022a
- kionix,kx132-1211
- kionix,kx134-1211
- rohm,kx132acr-lbz
- rohm,kx134acr-lbz
reg:
maxItems: 1

View File

@ -14,12 +14,20 @@ description: |
SPI and I2C interface.
https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf
https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf
https://www.nxp.com/docs/en/data-sheet/FXLS8967AF.pdf
https://www.nxp.com/docs/en/data-sheet/FXLS8974CF.pdf
properties:
compatible:
enum:
- nxp,fxls8962af
- nxp,fxls8964af
oneOf:
- enum:
- nxp,fxls8962af
- nxp,fxls8964af
- items:
- enum:
- nxp,fxls8967af
- nxp,fxls8974cf
- const: nxp,fxls8962af
reg:
maxItems: 1
@ -38,6 +46,11 @@ properties:
drive-open-drain:
type: boolean
wakeup-source:
$ref: /schemas/types.yaml#/definitions/flag
description:
Enable wake on accelerometer event
required:
- compatible
- reg
@ -61,6 +74,7 @@ examples:
interrupt-parent = <&gpio0>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "INT1";
wakeup-source;
};
};
- |

View File

@ -19,49 +19,82 @@ description: |
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4020-4021-4022.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4001.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4003.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7685.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7686.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7687.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7688.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7690.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7691.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7693.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7942.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7946.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7980.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7982.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7983.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7984.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7988-1_7988-5.pdf
$ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
oneOf:
- const: adi,ad4000
- enum:
- adi,ad4000
- adi,ad4001
- adi,ad4002
- adi,ad4003
- adi,ad4020
- adi,adaq4001
- adi,adaq4003
- adi,ad7687
- adi,ad7691
- adi,ad7942
- adi,ad7946
- adi,ad7983
- items:
- enum:
- adi,ad4004
- adi,ad4008
- const: adi,ad4000
- const: adi,ad4001
- items:
- enum:
- adi,ad4005
- const: adi,ad4001
- const: adi,ad4002
- items:
- enum:
- adi,ad4006
- adi,ad4010
- const: adi,ad4002
- const: adi,ad4003
- items:
- enum:
- adi,ad4007
- adi,ad4011
- const: adi,ad4003
- const: adi,ad4020
- items:
- enum:
- adi,ad4021
- adi,ad4022
- const: adi,ad4020
- const: adi,adaq4001
- const: adi,adaq4003
- items:
- enum:
- adi,ad7685
- adi,ad7686
- adi,ad7980
- adi,ad7988-1
- adi,ad7988-5
- const: adi,ad7983
- items:
- enum:
- adi,ad7688
- adi,ad7693
- const: adi,ad7687
- items:
- enum:
- adi,ad7690
- adi,ad7982
- adi,ad7984
- const: adi,ad7691
reg:
maxItems: 1
@ -133,6 +166,22 @@ required:
- ref-supply
allOf:
# Single-channel PulSAR devices have SDI either tied to VIO, GND, or host CS.
- if:
properties:
compatible:
contains:
enum:
- adi,ad7687
- adi,ad7691
- adi,ad7942
- adi,ad7946
- adi,ad7983
then:
properties:
adi,sdi-pin:
enum: [ high, low, cs ]
default: cs
# The configuration register can only be accessed if SDI is connected to MOSI
- if:
required:

View File

@ -134,8 +134,9 @@ patternProperties:
description:
Describes the common mode channel for single channels. 0xFF is REFGND
and OxFE is COM. Macros are available for these values in
dt-bindings/iio/adi,ad4695.h. Values 1 to 15 correspond to INx inputs.
Only odd numbered INx inputs can be used as common mode channels.
dt-bindings/iio/adc/adi,ad4695.h. Values 1 to 15 correspond to INx
inputs. Only odd numbered INx inputs can be used as common mode
channels.
enum: [1, 3, 5, 7, 9, 11, 13, 15, 0xFE, 0xFF]
default: 0xFF
@ -209,7 +210,7 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/iio/adi,ad4695.h>
#include <dt-bindings/iio/adc/adi,ad4695.h>
spi {
#address-cells = <1>;

View File

@ -37,6 +37,17 @@ properties:
description: IRQ line for the ADC
maxItems: 1
rdy-gpios:
description:
GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but
highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its
DOUT aka MISO role) and so usually triggers a spurious interrupt. The
distinction between such a spurious event and a real one can only be done
by reading such a GPIO. (There is a register telling the same
information, but accessing that one needs a SPI transfer which then
triggers another interrupt event.)
maxItems: 1
'#address-cells':
const: 1
@ -111,6 +122,7 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
@ -121,6 +133,7 @@ examples:
spi-max-frequency = <5000000>;
interrupts = <25 2>;
interrupt-parent = <&gpio>;
rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
refin1-supply = <&adc_vref>;
clocks = <&ad7124_mclk>;
clock-names = "mclk";

View File

@ -135,6 +135,17 @@ properties:
'#clock-cells':
const: 0
rdy-gpios:
description:
GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but
highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its
DOUT aka MISO role) and so usually triggers a spurious interrupt. The
distinction between such a spurious event and a real one can only be done
by reading such a GPIO. (There is a register telling the same
information, but accessing that one needs a SPI transfer which then
triggers another interrupt event.)
maxItems: 1
patternProperties:
"^channel@[0-9a-f]$":
type: object
@ -443,6 +454,7 @@ examples:
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-names = "rdy";
interrupt-parent = <&gpio>;
rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
spi-max-frequency = <5000000>;
gpio-controller;
#gpio-cells = <2>;

View File

@ -106,6 +106,17 @@ properties:
description: see Documentation/devicetree/bindings/iio/adc/adc.yaml
type: boolean
rdy-gpios:
description:
GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but
highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its
DOUT aka MISO role) and so usually triggers a spurious interrupt. The
distinction between such a spurious event and a real one can only be done
by reading such a GPIO. (There is a register telling the same
information, but accessing that one needs a SPI transfer which then
triggers another interrupt event.)
maxItems: 1
patternProperties:
"^channel@[0-9a-f]+$":
type: object
@ -181,6 +192,7 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
@ -195,6 +207,7 @@ examples:
clock-names = "mclk";
interrupts = <25 0x2>;
interrupt-parent = <&gpio>;
rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
aincom-supply = <&aincom>;
dvdd-supply = <&dvdd>;
avdd-supply = <&avdd>;
@ -207,6 +220,7 @@ examples:
};
};
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
@ -224,6 +238,7 @@ examples:
#clock-cells = <0>;
interrupts = <25 0x2>;
interrupt-parent = <&gpio>;
rdy-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
aincom-supply = <&aincom>;
dvdd-supply = <&dvdd>;
avdd-supply = <&avdd>;

View File

@ -63,6 +63,17 @@ properties:
marked GPIO_ACTIVE_LOW.
maxItems: 1
rdy-gpios:
description:
GPIO reading the R̅D̅Y̅ line. Having such a GPIO is technically optional but
highly recommended because DOUT/R̅D̅Y̅ toggles during SPI transfers (in its
DOUT aka MISO role) and so usually triggers a spurious interrupt. The
distinction between such a spurious event and a real one can only be done
by reading such a GPIO. (There is a register telling the same
information, but accessing that one needs a SPI transfer which then
triggers another interrupt event.)
maxItems: 1
required:
- compatible
- reg

View File

@ -17,12 +17,15 @@ description: |
properties:
compatible:
items:
- enum:
- renesas,r9a07g043-adc # RZ/G2UL and RZ/Five
- renesas,r9a07g044-adc # RZ/G2L
- renesas,r9a07g054-adc # RZ/V2L
- const: renesas,rzg2l-adc
oneOf:
- items:
- enum:
- renesas,r9a07g043-adc # RZ/G2UL and RZ/Five
- renesas,r9a07g044-adc # RZ/G2L
- renesas,r9a07g054-adc # RZ/V2L
- const: renesas,rzg2l-adc
- items:
- const: renesas,r9a08g045-adc # RZ/G3S
reg:
maxItems: 1
@ -57,6 +60,9 @@ properties:
'#size-cells':
const: 0
"#io-channel-cells":
const: 1
required:
- compatible
- reg
@ -68,7 +74,7 @@ required:
- reset-names
patternProperties:
"^channel@[0-7]$":
"^channel@[0-8]$":
$ref: adc.yaml
type: object
description: |
@ -78,6 +84,8 @@ patternProperties:
reg:
description: |
The channel number.
minimum: 0
maximum: 8
required:
- reg
@ -92,18 +100,25 @@ allOf:
const: renesas,r9a07g043-adc
then:
patternProperties:
"^channel@[2-7]$": false
"^channel@[2-8]$": false
"^channel@[0-1]$":
properties:
reg:
minimum: 0
maximum: 1
else:
- if:
properties:
compatible:
contains:
enum:
- renesas,r9a07g044-adc
- renesas,r9a07g054-adc
then:
patternProperties:
"^channel@[8]$": false
"^channel@[0-7]$":
properties:
reg:
minimum: 0
maximum: 7
additionalProperties: false

View File

@ -0,0 +1,62 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/chemical/bosch,bme680.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bosch BME680 Gas sensor
maintainers:
- Vasileios Amoiridis <vassilisamir@gmail.com>
description: >
BME680 is a gas sensor which combines relative humidity, barometric pressure,
ambient temperature and gas (VOC - Volatile Organic Compounds) measurements.
https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme680-ds001.pdf
properties:
compatible:
const: bosch,bme680
reg:
maxItems: 1
vdd-supply: true
vddio-supply: true
required:
- compatible
- reg
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
co2-sensor@77 {
compatible = "bosch,bme680";
reg = <0x77>;
vddio-supply = <&vddio>;
vdd-supply = <&vdd>;
};
};
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
co2-sensor@0 {
compatible = "bosch,bme680";
reg = <0>;
spi-max-frequency = <500000>;
vddio-supply = <&vddio>;
vdd-supply = <&vdd>;
};
};

View File

@ -11,24 +11,30 @@ maintainers:
properties:
compatible:
enum:
- adi,adis16375
- adi,adis16480
- adi,adis16485
- adi,adis16488
- adi,adis16490
- adi,adis16495-1
- adi,adis16495-2
- adi,adis16495-3
- adi,adis16497-1
- adi,adis16497-2
- adi,adis16497-3
- adi,adis16545-1
- adi,adis16545-2
- adi,adis16545-3
- adi,adis16547-1
- adi,adis16547-2
- adi,adis16547-3
oneOf:
- enum:
- adi,adis16375
- adi,adis16480
- adi,adis16485
- adi,adis16486
- adi,adis16488
- adi,adis16489
- adi,adis16490
- adi,adis16495-1
- adi,adis16495-2
- adi,adis16495-3
- adi,adis16497-1
- adi,adis16497-2
- adi,adis16497-3
- adi,adis16545-1
- adi,adis16545-2
- adi,adis16545-3
- adi,adis16547-1
- adi,adis16547-2
- adi,adis16547-3
- items:
- const: adi,adis16487
- const: adi,adis16485
reg:
maxItems: 1

View File

@ -16,6 +16,7 @@ properties:
compatible:
oneOf:
- enum:
- invensense,iam20380
- invensense,iam20680
- invensense,icm20608
- invensense,icm20609

View File

@ -1,49 +0,0 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/light/rohm,bu27008.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ROHM BU27008 color sensor
maintainers:
- Matti Vaittinen <mazziesaccount@gmail.com>
description:
The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear
and IR) with four configurable channels. Red and green being always
available and two out of the rest three (blue, clear, IR) can be
selected to be simultaneously measured. Typical application is adjusting
LCD backlight of TVs, mobile phones and tablet PCs.
properties:
compatible:
const: rohm,bu27008
reg:
maxItems: 1
interrupts:
maxItems: 1
vdd-supply: true
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
light-sensor@38 {
compatible = "rohm,bu27008";
reg = <0x38>;
};
};
...

View File

@ -1,50 +0,0 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/light/rohm,bu27010.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ROHM BU27010 color sensor
maintainers:
- Matti Vaittinen <mazziesaccount@gmail.com>
description: |
The ROHM BU27010 is a sensor with 6 photodiodes (red, green, blue, clear,
IR and flickering detection) with five configurable channels. Red, green
and flickering detection being always available and two out of the rest
three (blue, clear, IR) can be selected to be simultaneously measured.
Typical application is adjusting LCD/OLED backlight of TVs, mobile phones
and tablet PCs.
properties:
compatible:
const: rohm,bu27010
reg:
maxItems: 1
interrupts:
maxItems: 1
vdd-supply: true
required:
- compatible
- reg
- vdd-supply
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
light-sensor@38 {
compatible = "rohm,bu27010";
reg = <0x38>;
vdd-supply = <&vdd>;
};
};

View File

@ -55,8 +55,6 @@ properties:
- atmel,atsha204a
# BPA-RS600: Power Supply
- blutek,bpa-rs600
# Bosch Sensortec pressure, temperature, humididty and VOC sensor
- bosch,bme680
# CM32181: Ambient Light Sensor
- capella,cm32181
# CM3232: Ambient Light Sensor

View File

@ -101,7 +101,7 @@ The macro comes from:
.. code-block::
#include <dt-bindings/iio/adi,ad4695.h>
#include <dt-bindings/iio/adc/adi,ad4695.h>
Pairing two INx pins
^^^^^^^^^^^^^^^^^^^^

View File

@ -12,7 +12,10 @@ This driver supports Analog Device's IMUs on SPI bus.
* `ADIS16375 <https://www.analog.com/ADIS16375>`_
* `ADIS16480 <https://www.analog.com/ADIS16480>`_
* `ADIS16485 <https://www.analog.com/ADIS16485>`_
* `ADIS16486 <https://www.analog.com/ADIS16486>`_
* `ADIS16487 <https://www.analog.com/ADIS16487>`_
* `ADIS16488 <https://www.analog.com/ADIS16488>`_
* `ADIS16489 <https://www.analog.com/ADIS16489>`_
* `ADIS16490 <https://www.analog.com/ADIS16490>`_
* `ADIS16495 <https://www.analog.com/ADIS16495>`_
* `ADIS16497 <https://www.analog.com/ADIS16497>`_

View File

@ -1311,7 +1311,7 @@ W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/adc/adi,ad4695.yaml
F: Documentation/iio/ad4695.rst
F: drivers/iio/adc/ad4695.c
F: include/dt-bindings/iio/adi,ad4695.h
F: include/dt-bindings/iio/adc/adi,ad4695.h
ANALOG DEVICES INC AD7091R DRIVER
M: Marcelo Schmitt <marcelo.schmitt@analog.com>
@ -20406,7 +20406,6 @@ ROHM BU270xx LIGHT SENSOR DRIVERs
M: Matti Vaittinen <mazziesaccount@gmail.com>
L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/light/rohm-bu27008.c
F: drivers/iio/light/rohm-bu27034.c
ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS

View File

@ -17,7 +17,7 @@
#include "adxl345.h"
struct adxl345_data {
struct adxl345_state {
const struct adxl345_chip_info *info;
struct regmap *regmap;
};
@ -43,7 +43,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct adxl345_data *data = iio_priv(indio_dev);
struct adxl345_state *st = iio_priv(indio_dev);
__le16 accel;
long long samp_freq_nhz;
unsigned int regval;
@ -56,7 +56,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
* ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte
* and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte
*/
ret = regmap_bulk_read(data->regmap,
ret = regmap_bulk_read(st->regmap,
ADXL345_REG_DATA_AXIS(chan->address),
&accel, sizeof(accel));
if (ret < 0)
@ -66,10 +66,10 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = data->info->uscale;
*val2 = st->info->uscale;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_CALIBBIAS:
ret = regmap_read(data->regmap,
ret = regmap_read(st->regmap,
ADXL345_REG_OFS_AXIS(chan->address), &regval);
if (ret < 0)
return ret;
@ -81,7 +81,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = regmap_read(data->regmap, ADXL345_REG_BW_RATE, &regval);
ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, &regval);
if (ret < 0)
return ret;
@ -99,7 +99,7 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct adxl345_data *data = iio_priv(indio_dev);
struct adxl345_state *st = iio_priv(indio_dev);
s64 n;
switch (mask) {
@ -108,14 +108,14 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
* 8-bit resolution at +/- 2g, that is 4x accel data scale
* factor
*/
return regmap_write(data->regmap,
return regmap_write(st->regmap,
ADXL345_REG_OFS_AXIS(chan->address),
val / 4);
case IIO_CHAN_INFO_SAMP_FREQ:
n = div_s64(val * NANOHZ_PER_HZ + val2,
ADXL345_BASE_RATE_NANO_HZ);
return regmap_update_bits(data->regmap, ADXL345_REG_BW_RATE,
return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE,
ADXL345_BW_RATE,
clamp_val(ilog2(n), 0,
ADXL345_BW_RATE));
@ -169,8 +169,7 @@ static void adxl345_powerdown(void *regmap)
}
/**
* adxl345_core_probe() - probe and setup for the adxl345 accelerometer,
* also covers the adlx375 accelerometer
* adxl345_core_probe() - Probe and setup for the accelerometer.
* @dev: Driver model representation of the device
* @regmap: Regmap instance for the device
* @setup: Setup routine to be executed right before the standard device
@ -181,7 +180,7 @@ static void adxl345_powerdown(void *regmap)
int adxl345_core_probe(struct device *dev, struct regmap *regmap,
int (*setup)(struct device*, struct regmap*))
{
struct adxl345_data *data;
struct adxl345_state *st;
struct iio_dev *indio_dev;
u32 regval;
unsigned int data_format_mask = (ADXL345_DATA_FORMAT_RANGE |
@ -190,17 +189,17 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
ADXL345_DATA_FORMAT_SELF_TEST);
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
data->regmap = regmap;
data->info = device_get_match_data(dev);
if (!data->info)
st = iio_priv(indio_dev);
st->regmap = regmap;
st->info = device_get_match_data(dev);
if (!st->info)
return -ENODEV;
indio_dev->name = data->info->name;
indio_dev->name = st->info->name;
indio_dev->info = &adxl345_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = adxl345_channels;
@ -208,12 +207,12 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
if (setup) {
/* Perform optional initial bus specific configuration */
ret = setup(dev, data->regmap);
ret = setup(dev, st->regmap);
if (ret)
return ret;
/* Enable full-resolution mode */
ret = regmap_update_bits(data->regmap, ADXL345_REG_DATA_FORMAT,
ret = regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT,
data_format_mask,
ADXL345_DATA_FORMAT_FULL_RES);
if (ret)
@ -222,14 +221,14 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
} else {
/* Enable full-resolution mode (init all data_format bits) */
ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT,
ret = regmap_write(st->regmap, ADXL345_REG_DATA_FORMAT,
ADXL345_DATA_FORMAT_FULL_RES);
if (ret)
return dev_err_probe(dev, ret,
"Failed to set data range\n");
}
ret = regmap_read(data->regmap, ADXL345_REG_DEVID, &regval);
ret = regmap_read(st->regmap, ADXL345_REG_DEVID, &regval);
if (ret < 0)
return dev_err_probe(dev, ret, "Error reading device ID\n");
@ -238,11 +237,11 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
regval, ADXL345_DEVID);
/* Enable measurement mode */
ret = adxl345_powerup(data->regmap);
ret = adxl345_powerup(st->regmap);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to enable measurement mode\n");
ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap);
ret = devm_add_action_or_reset(dev, adxl345_powerdown, st->regmap);
if (ret < 0)
return ret;

View File

@ -129,6 +129,8 @@
#define FXLS8962AF_DEVICE_ID 0x62
#define FXLS8964AF_DEVICE_ID 0x84
#define FXLS8974CF_DEVICE_ID 0x86
#define FXLS8967AF_DEVICE_ID 0x87
/* Raw temp channel offset */
#define FXLS8962AF_TEMP_CENTER_VAL 25
@ -766,6 +768,18 @@ static const struct fxls8962af_chip_info fxls_chip_info_table[] = {
.channels = fxls8962af_channels,
.num_channels = ARRAY_SIZE(fxls8962af_channels),
},
[fxls8967af] = {
.chip_id = FXLS8967AF_DEVICE_ID,
.name = "fxls8967af",
.channels = fxls8962af_channels,
.num_channels = ARRAY_SIZE(fxls8962af_channels),
},
[fxls8974cf] = {
.chip_id = FXLS8974CF_DEVICE_ID,
.name = "fxls8974cf",
.channels = fxls8962af_channels,
.num_channels = ARRAY_SIZE(fxls8962af_channels),
},
};
static const struct iio_info fxls8962af_info = {

View File

@ -30,6 +30,8 @@ static int fxls8962af_probe(struct i2c_client *client)
static const struct i2c_device_id fxls8962af_id[] = {
{ "fxls8962af", fxls8962af },
{ "fxls8964af", fxls8964af },
{ "fxls8967af", fxls8967af },
{ "fxls8974cf", fxls8974cf },
{}
};
MODULE_DEVICE_TABLE(i2c, fxls8962af_id);

View File

@ -11,6 +11,8 @@ struct device;
enum {
fxls8962af,
fxls8964af,
fxls8967af,
fxls8974cf,
};
int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq);

View File

@ -38,7 +38,9 @@ static int kx022a_i2c_probe(struct i2c_client *i2c)
static const struct i2c_device_id kx022a_i2c_id[] = {
{ .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
{ .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info },
{ .name = "kx134-1211", .driver_data = (kernel_ulong_t)&kx134_chip_info },
{ .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info },
{ .name = "kx134acr-lbz", .driver_data = (kernel_ulong_t)&kx134acr_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id);
@ -46,7 +48,9 @@ MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id);
static const struct of_device_id kx022a_of_match[] = {
{ .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
{ .compatible = "kionix,kx132-1211", .data = &kx132_chip_info },
{ .compatible = "kionix,kx134-1211", .data = &kx134_chip_info },
{ .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info },
{ .compatible = "rohm,kx134acr-lbz", .data = &kx134acr_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, kx022a_of_match);

View File

@ -38,7 +38,9 @@ static int kx022a_spi_probe(struct spi_device *spi)
static const struct spi_device_id kx022a_id[] = {
{ .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
{ .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info },
{ .name = "kx134-1211", .driver_data = (kernel_ulong_t)&kx134_chip_info },
{ .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info },
{ .name = "kx134acr-lbz", .driver_data = (kernel_ulong_t)&kx134acr_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, kx022a_id);
@ -46,7 +48,9 @@ MODULE_DEVICE_TABLE(spi, kx022a_id);
static const struct of_device_id kx022a_of_match[] = {
{ .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
{ .compatible = "kionix,kx132-1211", .data = &kx132_chip_info },
{ .compatible = "kionix,kx134-1211", .data = &kx134_chip_info },
{ .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info },
{ .compatible = "rohm,kx134acr-lbz", .data = &kx134acr_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, kx022a_of_match);

View File

@ -5,6 +5,7 @@
* ROHM/KIONIX accelerometer driver
*/
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
@ -407,11 +408,21 @@ static const int kx022a_scale_table[][2] = {
{ 0, 4788403 },
};
/* KX134ACR-LBZ ranges are (+/-) 8, 16, 32, 64 G */
static const int kx134acr_lbz_scale_table[][2] = {
{ 0, 2394202 },
{ 0, 4788403 },
{ 0, 9576807 },
{ 0, 19153613 },
};
static int kx022a_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
struct kx022a_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
*vals = (const int *)kx022a_accel_samp_freq_table;
@ -420,9 +431,8 @@ static int kx022a_read_avail(struct iio_dev *indio_dev,
*type = IIO_VAL_INT_PLUS_MICRO;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_SCALE:
*vals = (const int *)kx022a_scale_table;
*length = ARRAY_SIZE(kx022a_scale_table) *
ARRAY_SIZE(kx022a_scale_table[0]);
*vals = (const int *)data->chip_info->scale_table;
*length = data->chip_info->scale_table_size;
*type = IIO_VAL_INT_PLUS_NANO;
return IIO_AVAIL_LIST;
default:
@ -438,17 +448,17 @@ static void kx022a_reg2freq(unsigned int val, int *val1, int *val2)
*val2 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][1];
}
static void kx022a_reg2scale(unsigned int val, unsigned int *val1,
unsigned int *val2)
static void kx022a_reg2scale(struct kx022a_data *data, unsigned int val,
unsigned int *val1, unsigned int *val2)
{
val &= KX022A_MASK_GSEL;
val >>= KX022A_GSEL_SHIFT;
*val1 = kx022a_scale_table[val][0];
*val2 = kx022a_scale_table[val][1];
*val1 = data->chip_info->scale_table[val][0];
*val2 = data->chip_info->scale_table[val][1];
}
static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on)
static int __kx022a_turn_on_off(struct kx022a_data *data, bool on)
{
int ret;
@ -469,7 +479,7 @@ static int kx022a_turn_off_lock(struct kx022a_data *data)
int ret;
mutex_lock(&data->mutex);
ret = kx022a_turn_on_off_unlocked(data, false);
ret = __kx022a_turn_on_off(data, false);
if (ret)
mutex_unlock(&data->mutex);
@ -480,7 +490,7 @@ static int kx022a_turn_on_unlock(struct kx022a_data *data)
{
int ret;
ret = kx022a_turn_on_off_unlocked(data, true);
ret = __kx022a_turn_on_off(data, true);
mutex_unlock(&data->mutex);
return ret;
@ -543,11 +553,11 @@ static int kx022a_write_raw(struct iio_dev *idev,
kx022a_turn_on_unlock(data);
break;
case IIO_CHAN_INFO_SCALE:
n = ARRAY_SIZE(kx022a_scale_table);
n = data->chip_info->scale_table_size / 2;
while (n-- > 0)
if (val == kx022a_scale_table[n][0] &&
val2 == kx022a_scale_table[n][1])
if (val == data->chip_info->scale_table[n][0] &&
val2 == data->chip_info->scale_table[n][1])
break;
if (n < 0) {
ret = -EINVAL;
@ -642,7 +652,7 @@ static int kx022a_read_raw(struct iio_dev *idev,
if (ret < 0)
return ret;
kx022a_reg2scale(regval, val, val2);
kx022a_reg2scale(data, regval, val, val2);
return IIO_VAL_INT_PLUS_NANO;
}
@ -912,18 +922,19 @@ static int kx022a_fifo_disable(struct kx022a_data *data)
{
int ret = 0;
ret = kx022a_turn_off_lock(data);
guard(mutex)(&data->mutex);
ret = __kx022a_turn_on_off(data, false);
if (ret)
return ret;
ret = regmap_clear_bits(data->regmap, data->ien_reg, KX022A_MASK_WMI);
if (ret)
goto unlock_out;
return ret;
ret = regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2,
KX022A_MASK_BUF_EN);
if (ret)
goto unlock_out;
return ret;
data->state &= ~KX022A_STATE_FIFO;
@ -931,12 +942,7 @@ static int kx022a_fifo_disable(struct kx022a_data *data)
kfree(data->fifo_buffer);
return kx022a_turn_on_unlock(data);
unlock_out:
mutex_unlock(&data->mutex);
return ret;
return __kx022a_turn_on_off(data, true);
}
static int kx022a_buffer_predisable(struct iio_dev *idev)
@ -959,33 +965,29 @@ static int kx022a_fifo_enable(struct kx022a_data *data)
if (!data->fifo_buffer)
return -ENOMEM;
ret = kx022a_turn_off_lock(data);
guard(mutex)(&data->mutex);
ret = __kx022a_turn_on_off(data, false);
if (ret)
return ret;
/* Update watermark to HW */
ret = kx022a_fifo_set_wmi(data);
if (ret)
goto unlock_out;
return ret;
/* Enable buffer */
ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
KX022A_MASK_BUF_EN);
if (ret)
goto unlock_out;
return ret;
data->state |= KX022A_STATE_FIFO;
ret = regmap_set_bits(data->regmap, data->ien_reg,
KX022A_MASK_WMI);
if (ret)
goto unlock_out;
return ret;
return kx022a_turn_on_unlock(data);
unlock_out:
mutex_unlock(&data->mutex);
return ret;
return __kx022a_turn_on_off(data, true);
}
static int kx022a_buffer_postenable(struct iio_dev *idev)
@ -1053,7 +1055,7 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private)
struct kx022a_data *data = iio_priv(idev);
irqreturn_t ret = IRQ_NONE;
mutex_lock(&data->mutex);
guard(mutex)(&data->mutex);
if (data->trigger_enabled) {
iio_trigger_poll_nested(data->trig);
@ -1068,8 +1070,6 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private)
ret = IRQ_HANDLED;
}
mutex_unlock(&data->mutex);
return ret;
}
@ -1079,32 +1079,26 @@ static int kx022a_trigger_set_state(struct iio_trigger *trig,
struct kx022a_data *data = iio_trigger_get_drvdata(trig);
int ret = 0;
mutex_lock(&data->mutex);
guard(mutex)(&data->mutex);
if (data->trigger_enabled == state)
goto unlock_out;
return 0;
if (data->state & KX022A_STATE_FIFO) {
dev_warn(data->dev, "Can't set trigger when FIFO enabled\n");
ret = -EBUSY;
goto unlock_out;
return -EBUSY;
}
ret = kx022a_turn_on_off_unlocked(data, false);
ret = __kx022a_turn_on_off(data, false);
if (ret)
goto unlock_out;
return ret;
data->trigger_enabled = state;
ret = kx022a_set_drdy_irq(data, state);
if (ret)
goto unlock_out;
return ret;
ret = kx022a_turn_on_off_unlocked(data, true);
unlock_out:
mutex_unlock(&data->mutex);
return ret;
return __kx022a_turn_on_off(data, true);
}
static const struct iio_trigger_ops kx022a_trigger_ops = {
@ -1121,10 +1115,15 @@ static int kx022a_chip_init(struct kx022a_data *data)
return ret;
/*
* I've seen I2C read failures if we poll too fast after the sensor
* reset. Slight delay gives I2C block the time to recover.
* According to the power-on procedure documents, there is (at least)
* 2ms delay required after the software reset. This should be same for
* all, KX022ACR-Z, KX132-1211, KX132ACR-LBZ and KX134ACR-LBZ.
*
* https://fscdn.rohm.com/kionix/en/document/AN010_KX022ACR-Z_Power-on_Procedure_E.pdf
* https://fscdn.rohm.com/kionix/en/document/TN027-Power-On-Procedure.pdf
* https://fscdn.rohm.com/kionix/en/document/AN011_KX134ACR-LBZ_Power-on_Procedure_E.pdf
*/
msleep(1);
msleep(2);
ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val,
!(val & KX022A_MASK_SRST),
@ -1158,6 +1157,9 @@ const struct kx022a_chip_info kx022a_chip_info = {
.regmap_config = &kx022a_regmap_config,
.channels = kx022a_channels,
.num_channels = ARRAY_SIZE(kx022a_channels),
.scale_table = kx022a_scale_table,
.scale_table_size = ARRAY_SIZE(kx022a_scale_table) *
ARRAY_SIZE(kx022a_scale_table[0]),
.fifo_length = KX022A_FIFO_LENGTH,
.who = KX022A_REG_WHO,
.id = KX022A_ID,
@ -1183,6 +1185,9 @@ const struct kx022a_chip_info kx132_chip_info = {
.regmap_config = &kx132_regmap_config,
.channels = kx132_channels,
.num_channels = ARRAY_SIZE(kx132_channels),
.scale_table = kx022a_scale_table,
.scale_table_size = ARRAY_SIZE(kx022a_scale_table) *
ARRAY_SIZE(kx022a_scale_table[0]),
.fifo_length = KX132_FIFO_LENGTH,
.who = KX132_REG_WHO,
.id = KX132_ID,
@ -1204,6 +1209,35 @@ const struct kx022a_chip_info kx132_chip_info = {
};
EXPORT_SYMBOL_NS_GPL(kx132_chip_info, "IIO_KX022A");
const struct kx022a_chip_info kx134_chip_info = {
.name = "kx134-1211",
.regmap_config = &kx132_regmap_config,
.channels = kx132_channels,
.num_channels = ARRAY_SIZE(kx132_channels),
.scale_table = kx134acr_lbz_scale_table,
.scale_table_size = ARRAY_SIZE(kx134acr_lbz_scale_table) *
ARRAY_SIZE(kx134acr_lbz_scale_table[0]),
.fifo_length = KX132_FIFO_LENGTH,
.who = KX132_REG_WHO,
.id = KX134_1211_ID,
.cntl = KX132_REG_CNTL,
.cntl2 = KX132_REG_CNTL2,
.odcntl = KX132_REG_ODCNTL,
.buf_cntl1 = KX132_REG_BUF_CNTL1,
.buf_cntl2 = KX132_REG_BUF_CNTL2,
.buf_clear = KX132_REG_BUF_CLEAR,
.buf_status1 = KX132_REG_BUF_STATUS_1,
.buf_smp_lvl_mask = KX132_MASK_BUF_SMP_LVL,
.buf_read = KX132_REG_BUF_READ,
.inc1 = KX132_REG_INC1,
.inc4 = KX132_REG_INC4,
.inc5 = KX132_REG_INC5,
.inc6 = KX132_REG_INC6,
.xout_l = KX132_REG_XOUT_L,
.get_fifo_bytes_available = kx132_get_fifo_bytes_available,
};
EXPORT_SYMBOL_NS_GPL(kx134_chip_info, "IIO_KX022A");
/*
* Despite the naming, KX132ACR-LBZ is not similar to KX132-1211 but it is
* exact subset of KX022A. KX132ACR-LBZ is meant to be used for industrial
@ -1216,6 +1250,9 @@ const struct kx022a_chip_info kx132acr_chip_info = {
.regmap_config = &kx022a_regmap_config,
.channels = kx022a_channels,
.num_channels = ARRAY_SIZE(kx022a_channels),
.scale_table = kx022a_scale_table,
.scale_table_size = ARRAY_SIZE(kx022a_scale_table) *
ARRAY_SIZE(kx022a_scale_table[0]),
.fifo_length = KX022A_FIFO_LENGTH,
.who = KX022A_REG_WHO,
.id = KX132ACR_LBZ_ID,
@ -1236,6 +1273,34 @@ const struct kx022a_chip_info kx132acr_chip_info = {
};
EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, "IIO_KX022A");
const struct kx022a_chip_info kx134acr_chip_info = {
.name = "kx134acr-lbz",
.regmap_config = &kx022a_regmap_config,
.channels = kx022a_channels,
.num_channels = ARRAY_SIZE(kx022a_channels),
.scale_table = kx134acr_lbz_scale_table,
.scale_table_size = ARRAY_SIZE(kx134acr_lbz_scale_table) *
ARRAY_SIZE(kx134acr_lbz_scale_table[0]),
.fifo_length = KX022A_FIFO_LENGTH,
.who = KX022A_REG_WHO,
.id = KX134ACR_LBZ_ID,
.cntl = KX022A_REG_CNTL,
.cntl2 = KX022A_REG_CNTL2,
.odcntl = KX022A_REG_ODCNTL,
.buf_cntl1 = KX022A_REG_BUF_CNTL1,
.buf_cntl2 = KX022A_REG_BUF_CNTL2,
.buf_clear = KX022A_REG_BUF_CLEAR,
.buf_status1 = KX022A_REG_BUF_STATUS_1,
.buf_read = KX022A_REG_BUF_READ,
.inc1 = KX022A_REG_INC1,
.inc4 = KX022A_REG_INC4,
.inc5 = KX022A_REG_INC5,
.inc6 = KX022A_REG_INC6,
.xout_l = KX022A_REG_XOUT_L,
.get_fifo_bytes_available = kx022a_get_fifo_bytes_available,
};
EXPORT_SYMBOL_NS_GPL(kx134acr_chip_info, "IIO_KX022A");
int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info)
{
static const char * const regulator_names[] = {"io-vdd", "vdd"};

View File

@ -14,6 +14,7 @@
#define KX022A_REG_WHO 0x0f
#define KX022A_ID 0xc8
#define KX132ACR_LBZ_ID 0xd8
#define KX134ACR_LBZ_ID 0xcc
#define KX022A_REG_CNTL2 0x19
#define KX022A_MASK_SRST BIT(7)
@ -77,6 +78,7 @@
#define KX132_REG_WHO 0x13
#define KX132_ID 0x3d
#define KX134_1211_ID 0x46
#define KX132_FIFO_LENGTH 86
@ -135,6 +137,14 @@ struct kx022a_data;
*
* @name: name of the device
* @regmap_config: pointer to register map configuration
* @scale_table: An array of tables of scaling factors for
* a supported acceleration measurement range.
* Each table containing a single scaling
* factor consisting of two integers. The first
* value in a table is the integer part, and
* the second value is the fractional part as
* parts per billion.
* @scale_table_size: Amount of values in tables.
* @channels: pointer to iio_chan_spec array
* @num_channels: number of iio_chan_spec channels
* @fifo_length: number of 16-bit samples in a full buffer
@ -161,6 +171,8 @@ struct kx022a_data;
struct kx022a_chip_info {
const char *name;
const struct regmap_config *regmap_config;
const int (*scale_table)[2];
const int scale_table_size;
const struct iio_chan_spec *channels;
unsigned int num_channels;
unsigned int fifo_length;
@ -187,6 +199,8 @@ int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chi
extern const struct kx022a_chip_info kx022a_chip_info;
extern const struct kx022a_chip_info kx132_chip_info;
extern const struct kx022a_chip_info kx134_chip_info;
extern const struct kx022a_chip_info kx132acr_chip_info;
extern const struct kx022a_chip_info kx134acr_chip_info;
#endif

View File

@ -35,10 +35,6 @@
#define AD4000_SCALE_OPTIONS 2
#define AD4000_TQUIET1_NS 190
#define AD4000_TQUIET2_NS 60
#define AD4000_TCONV_NS 320
#define __AD4000_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access) \
{ \
.type = IIO_VOLTAGE, \
@ -49,6 +45,7 @@
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\
.scan_index = 0, \
.scan_type = { \
.sign = _sign, \
.realbits = _real_bits, \
@ -62,6 +59,12 @@
__AD4000_DIFF_CHANNEL((_sign), (_real_bits), \
((_real_bits) > 16 ? 32 : 16), (_reg_access))
#define AD4000_DIFF_CHANNELS(_sign, _real_bits, _reg_access) \
{ \
AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access), \
IIO_CHAN_SOFT_TIMESTAMP(1), \
}
#define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access)\
{ \
.type = IIO_VOLTAGE, \
@ -71,6 +74,7 @@
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\
.scan_index = 0, \
.scan_type = { \
.sign = _sign, \
.realbits = _real_bits, \
@ -84,6 +88,12 @@
__AD4000_PSEUDO_DIFF_CHANNEL((_sign), (_real_bits), \
((_real_bits) > 16 ? 32 : 16), (_reg_access))
#define AD4000_PSEUDO_DIFF_CHANNELS(_sign, _real_bits, _reg_access) \
{ \
AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access), \
IIO_CHAN_SOFT_TIMESTAMP(1), \
}
static const char * const ad4000_power_supplies[] = {
"vdd", "vio"
};
@ -108,111 +118,280 @@ static const int ad4000_gains[] = {
454, 909, 1000, 1900,
};
struct ad4000_time_spec {
int t_conv_ns;
int t_quiet2_ns;
};
/*
* Same timing specifications for all of AD4000, AD4001, ..., AD4008, AD4010,
* ADAQ4001, and ADAQ4003.
*/
static const struct ad4000_time_spec ad4000_t_spec = {
.t_conv_ns = 320,
.t_quiet2_ns = 60,
};
/* AD4020, AD4021, AD4022 */
static const struct ad4000_time_spec ad4020_t_spec = {
.t_conv_ns = 350,
.t_quiet2_ns = 60,
};
/* AD7983, AD7984 */
static const struct ad4000_time_spec ad7983_t_spec = {
.t_conv_ns = 500,
.t_quiet2_ns = 0,
};
/* AD7980, AD7982 */
static const struct ad4000_time_spec ad7980_t_spec = {
.t_conv_ns = 800,
.t_quiet2_ns = 0,
};
/* AD7946, AD7686, AD7688, AD7988-5, AD7693 */
static const struct ad4000_time_spec ad7686_t_spec = {
.t_conv_ns = 1600,
.t_quiet2_ns = 0,
};
/* AD7690 */
static const struct ad4000_time_spec ad7690_t_spec = {
.t_conv_ns = 2100,
.t_quiet2_ns = 0,
};
/* AD7942, AD7685, AD7687 */
static const struct ad4000_time_spec ad7687_t_spec = {
.t_conv_ns = 3200,
.t_quiet2_ns = 0,
};
/* AD7691 */
static const struct ad4000_time_spec ad7691_t_spec = {
.t_conv_ns = 3700,
.t_quiet2_ns = 0,
};
/* AD7988-1 */
static const struct ad4000_time_spec ad7988_1_t_spec = {
.t_conv_ns = 9500,
.t_quiet2_ns = 0,
};
struct ad4000_chip_info {
const char *dev_name;
struct iio_chan_spec chan_spec;
struct iio_chan_spec reg_access_chan_spec;
struct iio_chan_spec chan_spec[2];
struct iio_chan_spec reg_access_chan_spec[2];
const struct ad4000_time_spec *time_spec;
bool has_hardware_gain;
};
static const struct ad4000_chip_info ad4000_chip_info = {
.dev_name = "ad4000",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1),
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1),
.time_spec = &ad4000_t_spec,
};
static const struct ad4000_chip_info ad4001_chip_info = {
.dev_name = "ad4001",
.chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1),
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1),
.time_spec = &ad4000_t_spec,
};
static const struct ad4000_chip_info ad4002_chip_info = {
.dev_name = "ad4002",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1),
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1),
.time_spec = &ad4000_t_spec,
};
static const struct ad4000_chip_info ad4003_chip_info = {
.dev_name = "ad4003",
.chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
.time_spec = &ad4000_t_spec,
};
static const struct ad4000_chip_info ad4004_chip_info = {
.dev_name = "ad4004",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1),
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1),
.time_spec = &ad4000_t_spec,
};
static const struct ad4000_chip_info ad4005_chip_info = {
.dev_name = "ad4005",
.chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1),
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1),
.time_spec = &ad4000_t_spec,
};
static const struct ad4000_chip_info ad4006_chip_info = {
.dev_name = "ad4006",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1),
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1),
.time_spec = &ad4000_t_spec,
};
static const struct ad4000_chip_info ad4007_chip_info = {
.dev_name = "ad4007",
.chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
.time_spec = &ad4000_t_spec,
};
static const struct ad4000_chip_info ad4008_chip_info = {
.dev_name = "ad4008",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1),
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1),
.time_spec = &ad4000_t_spec,
};
static const struct ad4000_chip_info ad4010_chip_info = {
.dev_name = "ad4010",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1),
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1),
.time_spec = &ad4000_t_spec,
};
static const struct ad4000_chip_info ad4011_chip_info = {
.dev_name = "ad4011",
.chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
.time_spec = &ad4000_t_spec,
};
static const struct ad4000_chip_info ad4020_chip_info = {
.dev_name = "ad4020",
.chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1),
.chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1),
.time_spec = &ad4020_t_spec,
};
static const struct ad4000_chip_info ad4021_chip_info = {
.dev_name = "ad4021",
.chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1),
.chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1),
.time_spec = &ad4020_t_spec,
};
static const struct ad4000_chip_info ad4022_chip_info = {
.dev_name = "ad4022",
.chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1),
.chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1),
.time_spec = &ad4020_t_spec,
};
static const struct ad4000_chip_info adaq4001_chip_info = {
.dev_name = "adaq4001",
.chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1),
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1),
.time_spec = &ad4000_t_spec,
.has_hardware_gain = true,
};
static const struct ad4000_chip_info adaq4003_chip_info = {
.dev_name = "adaq4003",
.chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1),
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
.time_spec = &ad4000_t_spec,
.has_hardware_gain = true,
};
static const struct ad4000_chip_info ad7685_chip_info = {
.dev_name = "ad7685",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.time_spec = &ad7687_t_spec,
};
static const struct ad4000_chip_info ad7686_chip_info = {
.dev_name = "ad7686",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.time_spec = &ad7686_t_spec,
};
static const struct ad4000_chip_info ad7687_chip_info = {
.dev_name = "ad7687",
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
.time_spec = &ad7687_t_spec,
};
static const struct ad4000_chip_info ad7688_chip_info = {
.dev_name = "ad7688",
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
.time_spec = &ad7686_t_spec,
};
static const struct ad4000_chip_info ad7690_chip_info = {
.dev_name = "ad7690",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.time_spec = &ad7690_t_spec,
};
static const struct ad4000_chip_info ad7691_chip_info = {
.dev_name = "ad7691",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.time_spec = &ad7691_t_spec,
};
static const struct ad4000_chip_info ad7693_chip_info = {
.dev_name = "ad7693",
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
.time_spec = &ad7686_t_spec,
};
static const struct ad4000_chip_info ad7942_chip_info = {
.dev_name = "ad7942",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 14, 0),
.time_spec = &ad7687_t_spec,
};
static const struct ad4000_chip_info ad7946_chip_info = {
.dev_name = "ad7946",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 14, 0),
.time_spec = &ad7686_t_spec,
};
static const struct ad4000_chip_info ad7980_chip_info = {
.dev_name = "ad7980",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.time_spec = &ad7980_t_spec,
};
static const struct ad4000_chip_info ad7982_chip_info = {
.dev_name = "ad7982",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.time_spec = &ad7980_t_spec,
};
static const struct ad4000_chip_info ad7983_chip_info = {
.dev_name = "ad7983",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.time_spec = &ad7983_t_spec,
};
static const struct ad4000_chip_info ad7984_chip_info = {
.dev_name = "ad7984",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.time_spec = &ad7983_t_spec,
};
static const struct ad4000_chip_info ad7988_1_chip_info = {
.dev_name = "ad7988-1",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.time_spec = &ad7988_1_t_spec,
};
static const struct ad4000_chip_info ad7988_5_chip_info = {
.dev_name = "ad7988-5",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.time_spec = &ad7686_t_spec,
};
struct ad4000_state {
struct spi_device *spi;
struct gpio_desc *cnv_gpio;
@ -224,6 +403,7 @@ struct ad4000_state {
bool span_comp;
u16 gain_milli;
int scale_tbl[AD4000_SCALE_OPTIONS][2];
const struct ad4000_time_spec *time_spec;
/*
* DMA (thus cache coherency maintenance) requires the transfer buffers
@ -488,16 +668,15 @@ static const struct iio_info ad4000_info = {
static int ad4000_prepare_3wire_mode_message(struct ad4000_state *st,
const struct iio_chan_spec *chan)
{
unsigned int cnv_pulse_time = AD4000_TCONV_NS;
struct spi_transfer *xfers = st->xfers;
xfers[0].cs_change = 1;
xfers[0].cs_change_delay.value = cnv_pulse_time;
xfers[0].cs_change_delay.value = st->time_spec->t_conv_ns;
xfers[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
xfers[1].rx_buf = &st->scan.data;
xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits);
xfers[1].delay.value = AD4000_TQUIET2_NS;
xfers[1].delay.value = st->time_spec->t_quiet2_ns;
xfers[1].delay.unit = SPI_DELAY_UNIT_NSECS;
spi_message_init_with_transfers(&st->msg, st->xfers, 2);
@ -515,7 +694,6 @@ static int ad4000_prepare_3wire_mode_message(struct ad4000_state *st,
static int ad4000_prepare_4wire_mode_message(struct ad4000_state *st,
const struct iio_chan_spec *chan)
{
unsigned int cnv_to_sdi_time = AD4000_TCONV_NS;
struct spi_transfer *xfers = st->xfers;
/*
@ -523,7 +701,7 @@ static int ad4000_prepare_4wire_mode_message(struct ad4000_state *st,
* going low.
*/
xfers[0].cs_off = 1;
xfers[0].delay.value = cnv_to_sdi_time;
xfers[0].delay.value = st->time_spec->t_conv_ns;
xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS;
xfers[1].rx_buf = &st->scan.data;
@ -562,6 +740,7 @@ static int ad4000_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
st->spi = spi;
st->time_spec = chip->time_spec;
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4000_power_supplies),
ad4000_power_supplies);
@ -591,7 +770,7 @@ static int ad4000_probe(struct spi_device *spi)
switch (st->sdi_pin) {
case AD4000_SDI_MOSI:
indio_dev->info = &ad4000_reg_access_info;
indio_dev->channels = &chip->reg_access_chan_spec;
indio_dev->channels = chip->reg_access_chan_spec;
/*
* In "3-wire mode", the ADC SDI line must be kept high when
@ -603,7 +782,7 @@ static int ad4000_probe(struct spi_device *spi)
if (ret < 0)
return ret;
ret = ad4000_prepare_3wire_mode_message(st, indio_dev->channels);
ret = ad4000_prepare_3wire_mode_message(st, &indio_dev->channels[0]);
if (ret)
return ret;
@ -614,16 +793,16 @@ static int ad4000_probe(struct spi_device *spi)
break;
case AD4000_SDI_VIO:
indio_dev->info = &ad4000_info;
indio_dev->channels = &chip->chan_spec;
ret = ad4000_prepare_3wire_mode_message(st, indio_dev->channels);
indio_dev->channels = chip->chan_spec;
ret = ad4000_prepare_3wire_mode_message(st, &indio_dev->channels[0]);
if (ret)
return ret;
break;
case AD4000_SDI_CS:
indio_dev->info = &ad4000_info;
indio_dev->channels = &chip->chan_spec;
ret = ad4000_prepare_4wire_mode_message(st, indio_dev->channels);
indio_dev->channels = chip->chan_spec;
ret = ad4000_prepare_4wire_mode_message(st, &indio_dev->channels[0]);
if (ret)
return ret;
@ -637,7 +816,7 @@ static int ad4000_probe(struct spi_device *spi)
}
indio_dev->name = chip->dev_name;
indio_dev->num_channels = 1;
indio_dev->num_channels = 2;
ret = devm_mutex_init(dev, &st->lock);
if (ret)
@ -658,7 +837,7 @@ static int ad4000_probe(struct spi_device *spi)
}
}
ad4000_fill_scale_tbl(st, indio_dev->channels);
ad4000_fill_scale_tbl(st, &indio_dev->channels[0]);
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
&iio_pollfunc_store_time,
@ -686,6 +865,21 @@ static const struct spi_device_id ad4000_id[] = {
{ "ad4022", (kernel_ulong_t)&ad4022_chip_info },
{ "adaq4001", (kernel_ulong_t)&adaq4001_chip_info },
{ "adaq4003", (kernel_ulong_t)&adaq4003_chip_info },
{ "ad7685", (kernel_ulong_t)&ad7685_chip_info },
{ "ad7686", (kernel_ulong_t)&ad7686_chip_info },
{ "ad7687", (kernel_ulong_t)&ad7687_chip_info },
{ "ad7688", (kernel_ulong_t)&ad7688_chip_info },
{ "ad7690", (kernel_ulong_t)&ad7690_chip_info },
{ "ad7691", (kernel_ulong_t)&ad7691_chip_info },
{ "ad7693", (kernel_ulong_t)&ad7693_chip_info },
{ "ad7942", (kernel_ulong_t)&ad7942_chip_info },
{ "ad7946", (kernel_ulong_t)&ad7946_chip_info },
{ "ad7980", (kernel_ulong_t)&ad7980_chip_info },
{ "ad7982", (kernel_ulong_t)&ad7982_chip_info },
{ "ad7983", (kernel_ulong_t)&ad7983_chip_info },
{ "ad7984", (kernel_ulong_t)&ad7984_chip_info },
{ "ad7988-1", (kernel_ulong_t)&ad7988_1_chip_info },
{ "ad7988-5", (kernel_ulong_t)&ad7988_5_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad4000_id);
@ -707,6 +901,21 @@ static const struct of_device_id ad4000_of_match[] = {
{ .compatible = "adi,ad4022", .data = &ad4022_chip_info },
{ .compatible = "adi,adaq4001", .data = &adaq4001_chip_info },
{ .compatible = "adi,adaq4003", .data = &adaq4003_chip_info },
{ .compatible = "adi,ad7685", .data = &ad7685_chip_info },
{ .compatible = "adi,ad7686", .data = &ad7686_chip_info },
{ .compatible = "adi,ad7687", .data = &ad7687_chip_info },
{ .compatible = "adi,ad7688", .data = &ad7688_chip_info },
{ .compatible = "adi,ad7690", .data = &ad7690_chip_info },
{ .compatible = "adi,ad7691", .data = &ad7691_chip_info },
{ .compatible = "adi,ad7693", .data = &ad7693_chip_info },
{ .compatible = "adi,ad7942", .data = &ad7942_chip_info },
{ .compatible = "adi,ad7946", .data = &ad7946_chip_info },
{ .compatible = "adi,ad7980", .data = &ad7980_chip_info },
{ .compatible = "adi,ad7982", .data = &ad7982_chip_info },
{ .compatible = "adi,ad7983", .data = &ad7983_chip_info },
{ .compatible = "adi,ad7984", .data = &ad7984_chip_info },
{ .compatible = "adi,ad7988-1", .data = &ad7988_1_chip_info },
{ .compatible = "adi,ad7988-5", .data = &ad7988_5_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad4000_of_match);

View File

@ -30,7 +30,7 @@
#include <linux/spi/spi.h>
#include <linux/units.h>
#include <dt-bindings/iio/adi,ad4695.h>
#include <dt-bindings/iio/adc/adi,ad4695.h>
/* AD4695 registers */
#define AD4695_REG_SPI_CONFIG_A 0x0000

View File

@ -95,6 +95,10 @@
#define AD7124_MAX_CONFIGS 8
#define AD7124_MAX_CHANNELS 16
/* AD7124 input sources */
#define AD7124_INPUT_TEMPSENSOR 16
#define AD7124_INPUT_AVSS 17
enum ad7124_ids {
ID_AD7124_4,
ID_AD7124_8,
@ -360,20 +364,21 @@ static int ad7124_find_free_config_slot(struct ad7124_state *st)
return free_cfg_slot;
}
/* Only called during probe, so dev_err_probe() can be used */
static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channel_config *cfg)
{
struct device *dev = &st->sd.spi->dev;
unsigned int refsel = cfg->refsel;
switch (refsel) {
case AD7124_REFIN1:
case AD7124_REFIN2:
case AD7124_AVDD_REF:
if (IS_ERR(st->vref[refsel])) {
dev_err(&st->sd.spi->dev,
"Error, trying to use external voltage reference without a %s regulator.\n",
ad7124_ref_names[refsel]);
return PTR_ERR(st->vref[refsel]);
}
if (IS_ERR(st->vref[refsel]))
return dev_err_probe(dev, PTR_ERR(st->vref[refsel]),
"Error, trying to use external voltage reference without a %s regulator.\n",
ad7124_ref_names[refsel]);
cfg->vref_mv = regulator_get_voltage(st->vref[refsel]);
/* Conversion from uV to mV */
cfg->vref_mv /= 1000;
@ -384,8 +389,7 @@ static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channe
st->adc_control |= AD7124_ADC_CTRL_REF_EN(1);
return 0;
default:
dev_err(&st->sd.spi->dev, "Invalid reference %d\n", refsel);
return -EINVAL;
return dev_err_probe(dev, -EINVAL, "Invalid reference %d\n", refsel);
}
}
@ -571,6 +575,7 @@ static const struct ad_sigma_delta_info ad7124_sigma_delta_info = {
.data_reg = AD7124_DATA,
.num_slots = 8,
.irq_flags = IRQF_TRIGGER_FALLING,
.num_resetclks = 64,
};
static int ad7124_read_raw(struct iio_dev *indio_dev,
@ -588,26 +593,59 @@ static int ad7124_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
mutex_lock(&st->cfgs_lock);
switch (chan->type) {
case IIO_VOLTAGE:
mutex_lock(&st->cfgs_lock);
idx = st->channels[chan->address].cfg.pga_bits;
*val = st->channels[chan->address].cfg.vref_mv;
if (st->channels[chan->address].cfg.bipolar)
*val2 = chan->scan_type.realbits - 1 + idx;
else
*val2 = chan->scan_type.realbits + idx;
idx = st->channels[chan->address].cfg.pga_bits;
*val = st->channels[chan->address].cfg.vref_mv;
if (st->channels[chan->address].cfg.bipolar)
*val2 = chan->scan_type.realbits - 1 + idx;
else
*val2 = chan->scan_type.realbits + idx;
mutex_unlock(&st->cfgs_lock);
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_TEMP:
/*
* According to the data sheet
* Temperature (°C)
* = ((Conversion 0x800000)/13584) 272.5
* = (Conversion 0x800000 - 13584 * 272.5) / 13584
* = (Conversion 12090248) / 13584
* So scale with 1000/13584 to yield °mC. Reduce by 8 to
* 125/1698.
*/
*val = 125;
*val2 = 1698;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
mutex_unlock(&st->cfgs_lock);
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
mutex_lock(&st->cfgs_lock);
if (st->channels[chan->address].cfg.bipolar)
*val = -(1 << (chan->scan_type.realbits - 1));
else
*val = 0;
switch (chan->type) {
case IIO_VOLTAGE:
mutex_lock(&st->cfgs_lock);
if (st->channels[chan->address].cfg.bipolar)
*val = -(1 << (chan->scan_type.realbits - 1));
else
*val = 0;
mutex_unlock(&st->cfgs_lock);
return IIO_VAL_INT;
case IIO_TEMP:
/* see calculation above */
*val = -12090248;
return IIO_VAL_INT;
default:
return -EINVAL;
}
mutex_unlock(&st->cfgs_lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
mutex_lock(&st->cfgs_lock);
*val = st->channels[chan->address].cfg.odr;
@ -751,12 +789,14 @@ static const struct iio_info ad7124_info = {
.attrs = &ad7124_attrs_group,
};
/* Only called during probe, so dev_err_probe() can be used */
static int ad7124_soft_reset(struct ad7124_state *st)
{
struct device *dev = &st->sd.spi->dev;
unsigned int readval, timeout;
int ret;
ret = ad_sd_reset(&st->sd, 64);
ret = ad_sd_reset(&st->sd);
if (ret < 0)
return ret;
@ -765,7 +805,7 @@ static int ad7124_soft_reset(struct ad7124_state *st)
do {
ret = ad_sd_read_reg(&st->sd, AD7124_STATUS, 1, &readval);
if (ret < 0)
return ret;
return dev_err_probe(dev, ret, "Error reading status register\n");
if (!(readval & AD7124_STATUS_POR_FLAG_MSK))
return 0;
@ -774,39 +814,47 @@ static int ad7124_soft_reset(struct ad7124_state *st)
usleep_range(100, 2000);
} while (--timeout);
dev_err(&st->sd.spi->dev, "Soft reset failed\n");
return -EIO;
return dev_err_probe(dev, -EIO, "Soft reset failed\n");
}
static int ad7124_check_chip_id(struct ad7124_state *st)
{
struct device *dev = &st->sd.spi->dev;
unsigned int readval, chip_id, silicon_rev;
int ret;
ret = ad_sd_read_reg(&st->sd, AD7124_ID, 1, &readval);
if (ret < 0)
return ret;
return dev_err_probe(dev, ret, "Failure to read ID register\n");
chip_id = AD7124_DEVICE_ID_GET(readval);
silicon_rev = AD7124_SILICON_REV_GET(readval);
if (chip_id != st->chip_info->chip_id) {
dev_err(&st->sd.spi->dev,
"Chip ID mismatch: expected %u, got %u\n",
st->chip_info->chip_id, chip_id);
return -ENODEV;
}
if (chip_id != st->chip_info->chip_id)
return dev_err_probe(dev, -ENODEV,
"Chip ID mismatch: expected %u, got %u\n",
st->chip_info->chip_id, chip_id);
if (silicon_rev == 0) {
dev_err(&st->sd.spi->dev,
"Silicon revision empty. Chip may not be present\n");
return -ENODEV;
}
if (silicon_rev == 0)
return dev_err_probe(dev, -ENODEV,
"Silicon revision empty. Chip may not be present\n");
return 0;
}
/*
* Input specifiers 8 - 15 are explicitly reserved for ad7124-4
* while they are fine for ad7124-8. Values above 31 don't fit
* into the register field and so are invalid for sure.
*/
static bool ad7124_valid_input_select(unsigned int ain, const struct ad7124_chip_info *info)
{
if (ain >= info->num_inputs && ain < 16)
return false;
return ain <= FIELD_MAX(AD7124_CHANNEL_AINM_MSK);
}
static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
struct device *dev)
{
@ -815,11 +863,23 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
struct ad7124_channel *channels;
struct iio_chan_spec *chan;
unsigned int ain[2], channel = 0, tmp;
unsigned int num_channels;
int ret;
st->num_channels = device_get_child_node_count(dev);
if (!st->num_channels)
return dev_err_probe(dev, -ENODEV, "no channel children\n");
num_channels = device_get_child_node_count(dev);
/*
* The driver assigns each logical channel defined in the device tree
* statically one channel register. So only accept 16 such logical
* channels to not treat CONFIG_0 (i.e. the register following
* CHANNEL_15) as an additional channel register. The driver could be
* improved to lift this limitation.
*/
if (num_channels > AD7124_MAX_CHANNELS)
return dev_err_probe(dev, -EINVAL, "Too many channels defined\n");
/* Add one for temperature */
st->num_channels = min(num_channels + 1, AD7124_MAX_CHANNELS);
chan = devm_kcalloc(indio_dev->dev.parent, st->num_channels,
sizeof(*chan), GFP_KERNEL);
@ -838,16 +898,23 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
device_for_each_child_node_scoped(dev, child) {
ret = fwnode_property_read_u32(child, "reg", &channel);
if (ret)
return ret;
return dev_err_probe(dev, ret,
"Failed to parse reg property of %pfwP\n", child);
if (channel >= indio_dev->num_channels)
if (channel >= num_channels)
return dev_err_probe(dev, -EINVAL,
"Channel index >= number of channels\n");
"Channel index >= number of channels in %pfwP\n", child);
ret = fwnode_property_read_u32_array(child, "diff-channels",
ain, 2);
if (ret)
return ret;
return dev_err_probe(dev, ret,
"Failed to parse diff-channels property of %pfwP\n", child);
if (!ad7124_valid_input_select(ain[0], st->chip_info) ||
!ad7124_valid_input_select(ain[1], st->chip_info))
return dev_err_probe(dev, -EINVAL,
"diff-channels property of %pfwP contains invalid data\n", child);
st->channels[channel].nr = channel;
st->channels[channel].ain = AD7124_CHANNEL_AINP(ain[0]) |
@ -874,17 +941,49 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
chan[channel].channel2 = ain[1];
}
if (num_channels < AD7124_MAX_CHANNELS) {
st->channels[num_channels] = (struct ad7124_channel) {
.nr = num_channels,
.ain = AD7124_CHANNEL_AINP(AD7124_INPUT_TEMPSENSOR) |
AD7124_CHANNEL_AINM(AD7124_INPUT_AVSS),
.cfg = {
.bipolar = true,
},
};
chan[num_channels] = (struct iio_chan_spec) {
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_type = {
/*
* You might find it strange that a bipolar
* measurement yields an unsigned value, but
* this matches the device's manual.
*/
.sign = 'u',
.realbits = 24,
.storagebits = 32,
.endianness = IIO_BE,
},
.address = num_channels,
.scan_index = num_channels,
};
}
return 0;
}
static int ad7124_setup(struct ad7124_state *st)
{
struct device *dev = &st->sd.spi->dev;
unsigned int fclk, power_mode;
int i, ret;
fclk = clk_get_rate(st->mclk);
if (!fclk)
return -EINVAL;
return dev_err_probe(dev, -EINVAL, "Failed to get mclk rate\n");
/* The power mode changes the master clock frequency */
power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz,
@ -893,7 +992,7 @@ static int ad7124_setup(struct ad7124_state *st)
if (fclk != ad7124_master_clk_freq_hz[power_mode]) {
ret = clk_set_rate(st->mclk, fclk);
if (ret)
return ret;
return dev_err_probe(dev, ret, "Failed to set mclk rate\n");
}
/* Set the power mode */
@ -924,7 +1023,7 @@ static int ad7124_setup(struct ad7124_state *st)
ret = ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control);
if (ret < 0)
return ret;
return dev_err_probe(dev, ret, "Failed to setup CONTROL register\n");
return ret;
}
@ -937,13 +1036,14 @@ static void ad7124_reg_disable(void *r)
static int ad7124_probe(struct spi_device *spi)
{
const struct ad7124_chip_info *info;
struct device *dev = &spi->dev;
struct ad7124_state *st;
struct iio_dev *indio_dev;
int i, ret;
info = spi_get_device_match_data(spi);
if (!info)
return -ENODEV;
return dev_err_probe(dev, -ENODEV, "Failed to get match data\n");
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
@ -978,17 +1078,17 @@ static int ad7124_probe(struct spi_device *spi)
ret = regulator_enable(st->vref[i]);
if (ret)
return ret;
return dev_err_probe(dev, ret, "Failed to enable regulator #%d\n", i);
ret = devm_add_action_or_reset(&spi->dev, ad7124_reg_disable,
st->vref[i]);
if (ret)
return ret;
return dev_err_probe(dev, ret, "Failed to register disable handler for regulator #%d\n", i);
}
st->mclk = devm_clk_get_enabled(&spi->dev, "mclk");
if (IS_ERR(st->mclk))
return PTR_ERR(st->mclk);
return dev_err_probe(dev, PTR_ERR(st->mclk), "Failed to get mclk\n");
ret = ad7124_soft_reset(st);
if (ret < 0)
@ -1004,10 +1104,13 @@ static int ad7124_probe(struct spi_device *spi)
ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
if (ret < 0)
return ret;
return dev_err_probe(dev, ret, "Failed to setup triggers\n");
return devm_iio_device_register(&spi->dev, indio_dev);
ret = devm_iio_device_register(&spi->dev, indio_dev);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to register iio device\n");
return 0;
}
static const struct of_device_id ad7124_of_match[] = {

View File

@ -150,6 +150,11 @@
#define AD7173_FILTER_ODR0_MASK GENMASK(5, 0)
#define AD7173_MAX_CONFIGS 8
#define AD7173_MODE_CAL_INT_ZERO 0x4 /* Internal Zero-Scale Calibration */
#define AD7173_MODE_CAL_INT_FULL 0x5 /* Internal Full-Scale Calibration */
#define AD7173_MODE_CAL_SYS_ZERO 0x6 /* System Zero-Scale Calibration */
#define AD7173_MODE_CAL_SYS_FULL 0x7 /* System Full-Scale Calibration */
struct ad7173_device_info {
const unsigned int *sinc5_data_rates;
unsigned int num_sinc5_data_rates;
@ -175,6 +180,7 @@ struct ad7173_device_info {
bool has_input_buf;
bool has_int_ref;
bool has_ref2;
bool has_internal_fs_calibration;
bool higher_gpio_bits;
u8 num_gpios;
};
@ -193,9 +199,9 @@ struct ad7173_channel_config {
};
struct ad7173_channel {
unsigned int chan_reg;
unsigned int ain;
struct ad7173_channel_config cfg;
u8 syscalib_mode;
};
struct ad7173_state {
@ -273,6 +279,7 @@ static const struct ad7173_device_info ad4111_device_info = {
.has_input_buf = true,
.has_current_inputs = true,
.has_int_ref = true,
.has_internal_fs_calibration = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
@ -292,6 +299,7 @@ static const struct ad7173_device_info ad4112_device_info = {
.has_input_buf = true,
.has_current_inputs = true,
.has_int_ref = true,
.has_internal_fs_calibration = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
@ -327,6 +335,7 @@ static const struct ad7173_device_info ad4114_device_info = {
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.has_internal_fs_calibration = true,
.clock = 2 * HZ_PER_MHZ,
.sinc5_data_rates = ad7173_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
@ -344,6 +353,7 @@ static const struct ad7173_device_info ad4115_device_info = {
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.has_internal_fs_calibration = true,
.clock = 8 * HZ_PER_MHZ,
.sinc5_data_rates = ad4115_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad4115_sinc5_data_rates),
@ -361,6 +371,7 @@ static const struct ad7173_device_info ad4116_device_info = {
.has_temp = true,
.has_input_buf = true,
.has_int_ref = true,
.has_internal_fs_calibration = true,
.clock = 4 * HZ_PER_MHZ,
.sinc5_data_rates = ad4116_sinc5_data_rates,
.num_sinc5_data_rates = ARRAY_SIZE(ad4116_sinc5_data_rates),
@ -506,6 +517,105 @@ static const struct regmap_config ad7173_regmap_config = {
.read_flag_mask = BIT(6),
};
enum {
AD7173_SYSCALIB_ZERO_SCALE,
AD7173_SYSCALIB_FULL_SCALE,
};
static const char * const ad7173_syscalib_modes[] = {
[AD7173_SYSCALIB_ZERO_SCALE] = "zero_scale",
[AD7173_SYSCALIB_FULL_SCALE] = "full_scale",
};
static int ad7173_set_syscalib_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
unsigned int mode)
{
struct ad7173_state *st = iio_priv(indio_dev);
st->channels[chan->channel].syscalib_mode = mode;
return 0;
}
static int ad7173_get_syscalib_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad7173_state *st = iio_priv(indio_dev);
return st->channels[chan->channel].syscalib_mode;
}
static ssize_t ad7173_write_syscalib(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
const char *buf, size_t len)
{
struct ad7173_state *st = iio_priv(indio_dev);
bool sys_calib;
int ret, mode;
ret = kstrtobool(buf, &sys_calib);
if (ret)
return ret;
mode = st->channels[chan->channel].syscalib_mode;
if (sys_calib) {
if (mode == AD7173_SYSCALIB_ZERO_SCALE)
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_ZERO,
chan->address);
else
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_FULL,
chan->address);
}
return ret ? : len;
}
static const struct iio_enum ad7173_syscalib_mode_enum = {
.items = ad7173_syscalib_modes,
.num_items = ARRAY_SIZE(ad7173_syscalib_modes),
.set = ad7173_set_syscalib_mode,
.get = ad7173_get_syscalib_mode
};
static const struct iio_chan_spec_ext_info ad7173_calibsys_ext_info[] = {
{
.name = "sys_calibration",
.write = ad7173_write_syscalib,
.shared = IIO_SEPARATE,
},
IIO_ENUM("sys_calibration_mode", IIO_SEPARATE,
&ad7173_syscalib_mode_enum),
IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE,
&ad7173_syscalib_mode_enum),
{ }
};
static int ad7173_calibrate_all(struct ad7173_state *st, struct iio_dev *indio_dev)
{
int ret;
int i;
for (i = 0; i < st->num_channels; i++) {
if (indio_dev->channels[i].type != IIO_VOLTAGE)
continue;
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_ZERO, st->channels[i].ain);
if (ret < 0)
return ret;
if (st->info->has_internal_fs_calibration) {
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_FULL,
st->channels[i].ain);
if (ret < 0)
return ret;
}
}
return 0;
}
static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
unsigned int offset, unsigned int *reg,
unsigned int *mask)
@ -765,6 +875,7 @@ static const struct ad_sigma_delta_info ad7173_sigma_delta_info = {
.read_mask = BIT(6),
.status_ch_mask = GENMASK(3, 0),
.data_reg = AD7173_REG_DATA,
.num_resetclks = 64,
};
static int ad7173_setup(struct iio_dev *indio_dev)
@ -802,6 +913,10 @@ static int ad7173_setup(struct iio_dev *indio_dev)
if (!st->config_cnts)
return -ENOMEM;
ret = ad7173_calibrate_all(st, indio_dev);
if (ret)
return ret;
/* All channels are enabled by default after a reset */
return ad7173_disable_all(&st->sd);
}
@ -1024,6 +1139,7 @@ static const struct iio_chan_spec ad7173_channel_template = {
.storagebits = 32,
.endianness = IIO_BE,
},
.ext_info = ad7173_calibsys_ext_info,
};
static const struct iio_chan_spec ad7173_temp_iio_channel_template = {
@ -1317,7 +1433,6 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
chan->address = chan_index;
chan->scan_index = chan_index;
chan->channel = ain[0];
chan_st_priv->chan_reg = chan_index;
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
chan_st_priv->cfg.odr = 0;

View File

@ -361,6 +361,7 @@ static const struct ad_sigma_delta_info ad7192_sigma_delta_info = {
.status_ch_mask = GENMASK(3, 0),
.num_slots = 4,
.irq_flags = IRQF_TRIGGER_FALLING,
.num_resetclks = 40,
};
static const struct ad_sigma_delta_info ad7194_sigma_delta_info = {
@ -373,6 +374,7 @@ static const struct ad_sigma_delta_info ad7194_sigma_delta_info = {
.read_mask = BIT(6),
.status_ch_mask = GENMASK(3, 0),
.irq_flags = IRQF_TRIGGER_FALLING,
.num_resetclks = 40,
};
static const struct ad_sd_calib_data ad7192_calib_arr[8] = {
@ -565,7 +567,7 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev)
int i, ret, id;
/* reset the serial interface */
ret = ad_sd_reset(&st->sd, 48);
ret = ad_sd_reset(&st->sd);
if (ret < 0)
return ret;
usleep_range(500, 1000); /* Wait for at least 500us */

View File

@ -254,6 +254,7 @@ static const struct ad_sigma_delta_info ad7791_sigma_delta_info = {
.addr_shift = 4,
.read_mask = BIT(3),
.irq_flags = IRQF_TRIGGER_FALLING,
.num_resetclks = 32,
};
static int ad7791_read_raw(struct iio_dev *indio_dev,

View File

@ -206,6 +206,7 @@ static const struct ad_sigma_delta_info ad7793_sigma_delta_info = {
.addr_shift = 3,
.read_mask = BIT(6),
.irq_flags = IRQF_TRIGGER_FALLING,
.num_resetclks = 32,
};
static const struct ad_sd_calib_data ad7793_calib_arr[6] = {
@ -265,7 +266,7 @@ static int ad7793_setup(struct iio_dev *indio_dev,
return ret;
/* reset the serial interface */
ret = ad_sd_reset(&st->sd, 32);
ret = ad_sd_reset(&st->sd);
if (ret < 0)
goto out;
usleep_range(500, 2000); /* Wait for at least 500us */

View File

@ -29,8 +29,11 @@
#define AD_SD_COMM_CHAN_MASK 0x3
#define AD_SD_REG_COMM 0x00
#define AD_SD_REG_STATUS 0x00
#define AD_SD_REG_DATA 0x03
#define AD_SD_REG_STATUS_RDY 0x80
/**
* ad_sd_set_comm() - Set communications register
*
@ -109,7 +112,7 @@ static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
}, {
.rx_buf = val,
.len = size,
.cs_change = sigma_delta->bus_locked,
.cs_change = sigma_delta->keep_cs_asserted,
},
};
struct spi_message m;
@ -178,13 +181,12 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_read_reg, "IIO_AD_SIGMA_DELTA");
* ad_sd_reset() - Reset the serial interface
*
* @sigma_delta: The sigma delta device
* @reset_length: Number of SCLKs with DIN = 1
*
* Returns 0 on success, an error code otherwise.
**/
int ad_sd_reset(struct ad_sigma_delta *sigma_delta,
unsigned int reset_length)
int ad_sd_reset(struct ad_sigma_delta *sigma_delta)
{
unsigned int reset_length = sigma_delta->info->num_resetclks;
uint8_t *buf;
unsigned int size;
int ret;
@ -202,6 +204,107 @@ int ad_sd_reset(struct ad_sigma_delta *sigma_delta,
}
EXPORT_SYMBOL_NS_GPL(ad_sd_reset, "IIO_AD_SIGMA_DELTA");
static bool ad_sd_disable_irq(struct ad_sigma_delta *sigma_delta)
{
guard(spinlock_irqsave)(&sigma_delta->irq_lock);
/* It's already off, return false to indicate nothing was changed */
if (sigma_delta->irq_dis)
return false;
sigma_delta->irq_dis = true;
disable_irq_nosync(sigma_delta->irq_line);
return true;
}
static void ad_sd_enable_irq(struct ad_sigma_delta *sigma_delta)
{
guard(spinlock_irqsave)(&sigma_delta->irq_lock);
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->irq_line);
}
#define AD_SD_CLEAR_DATA_BUFLEN 9
/* Called with `sigma_delta->bus_locked == true` only. */
static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta)
{
bool pending_event;
unsigned int data_read_len = BITS_TO_BYTES(sigma_delta->info->num_resetclks);
u8 *data;
struct spi_transfer t[] = {
{
.len = 1,
}, {
.len = data_read_len,
}
};
struct spi_message m;
int ret;
/*
* Read R̅D̅Y̅ pin (if possible) or status register to check if there is an
* old event.
*/
if (sigma_delta->rdy_gpiod) {
pending_event = gpiod_get_value(sigma_delta->rdy_gpiod);
} else {
unsigned status_reg;
ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_STATUS, 1, &status_reg);
if (ret)
return ret;
pending_event = !(status_reg & AD_SD_REG_STATUS_RDY);
}
if (!pending_event)
return 0;
/*
* In general the size of the data register is unknown. It varies from
* device to device, might be one byte longer if CONTROL.DATA_STATUS is
* set and even varies on some devices depending on which input is
* selected. So send one byte to start reading the data register and
* then just clock for some bytes with DIN (aka MOSI) high to not
* confuse the register access state machine after the data register was
* completely read. Note however that the sequence length must be
* shorter than the reset procedure.
*/
data = kzalloc(data_read_len + 1, GFP_KERNEL);
if (!data)
return -ENOMEM;
spi_message_init(&m);
if (sigma_delta->info->has_registers) {
unsigned int data_reg = sigma_delta->info->data_reg ?: AD_SD_REG_DATA;
data[0] = data_reg << sigma_delta->info->addr_shift;
data[0] |= sigma_delta->info->read_mask;
data[0] |= sigma_delta->comm;
t[0].tx_buf = data;
spi_message_add_tail(&t[0], &m);
}
/*
* The first transferred byte is part of the real data register,
* so this doesn't need to be 0xff. In the remaining
* `data_read_len - 1` bytes are less than $num_resetclks ones.
*/
t[1].tx_buf = data + 1;
data[1] = 0x00;
memset(data + 2, 0xff, data_read_len - 1);
spi_message_add_tail(&t[1], &m);
ret = spi_sync_locked(sigma_delta->spi, &m);
kfree(data);
return ret;
}
int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
unsigned int mode, unsigned int channel)
{
@ -217,16 +320,18 @@ int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
sigma_delta->keep_cs_asserted = true;
reinit_completion(&sigma_delta->completion);
ret = ad_sigma_delta_clear_pending_event(sigma_delta);
if (ret)
goto out;
ret = ad_sigma_delta_set_mode(sigma_delta, mode);
if (ret < 0)
goto out;
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->irq_line);
ad_sd_enable_irq(sigma_delta);
time_left = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ);
if (time_left == 0) {
sigma_delta->irq_dis = true;
disable_irq_nosync(sigma_delta->irq_line);
ad_sd_disable_irq(sigma_delta);
ret = -EIO;
} else {
ret = 0;
@ -292,10 +397,13 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
sigma_delta->keep_cs_asserted = true;
reinit_completion(&sigma_delta->completion);
ret = ad_sigma_delta_clear_pending_event(sigma_delta);
if (ret)
goto out_unlock;
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->irq_line);
ad_sd_enable_irq(sigma_delta);
ret = wait_for_completion_interruptible_timeout(
&sigma_delta->completion, HZ);
@ -314,14 +422,13 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
&raw_sample);
out:
if (!sigma_delta->irq_dis) {
disable_irq_nosync(sigma_delta->irq_line);
sigma_delta->irq_dis = true;
}
ad_sd_disable_irq(sigma_delta);
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);
out_unlock:
sigma_delta->keep_cs_asserted = false;
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->controller);
iio_device_release_direct_mode(indio_dev);
@ -392,12 +499,15 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
sigma_delta->bus_locked = true;
sigma_delta->keep_cs_asserted = true;
ret = ad_sigma_delta_clear_pending_event(sigma_delta);
if (ret)
goto err_unlock;
ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
if (ret)
goto err_unlock;
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->irq_line);
ad_sd_enable_irq(sigma_delta);
return 0;
@ -414,10 +524,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
reinit_completion(&sigma_delta->completion);
wait_for_completion_timeout(&sigma_delta->completion, HZ);
if (!sigma_delta->irq_dis) {
disable_irq_nosync(sigma_delta->irq_line);
sigma_delta->irq_dis = true;
}
ad_sd_disable_irq(sigma_delta);
sigma_delta->keep_cs_asserted = false;
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
@ -516,8 +623,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
irq_handled:
iio_trigger_notify_done(indio_dev->trig);
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->irq_line);
ad_sd_enable_irq(sigma_delta);
return IRQ_HANDLED;
}
@ -539,12 +645,31 @@ static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private)
{
struct ad_sigma_delta *sigma_delta = private;
complete(&sigma_delta->completion);
disable_irq_nosync(irq);
sigma_delta->irq_dis = true;
iio_trigger_poll(sigma_delta->trig);
/*
* AD7124 and a few others use the same physical line for interrupt
* reporting (R̅D̅Y̅) and MISO.
* As MISO toggles when reading a register, this likely results in a
* pending interrupt. This has two consequences: a) The irq might
* trigger immediately after it's enabled even though the conversion
* isn't done yet; and b) checking the STATUS register's R̅D̅Y̅ flag is
* off-limits as reading that would trigger another irq event.
*
* So read the MOSI line as GPIO (if available) and only trigger the irq
* if the line is active. Without such a GPIO assume this is a valid
* interrupt.
*
* Also as disable_irq_nosync() is used to disable the irq, only act if
* the irq wasn't disabled before.
*/
if ((!sigma_delta->rdy_gpiod || gpiod_get_value(sigma_delta->rdy_gpiod)) &&
ad_sd_disable_irq(sigma_delta)) {
complete(&sigma_delta->completion);
iio_trigger_poll(sigma_delta->trig);
return IRQ_HANDLED;
return IRQ_HANDLED;
}
return IRQ_NONE;
}
/**
@ -674,11 +799,24 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
}
}
spin_lock_init(&sigma_delta->irq_lock);
if (info->irq_line)
sigma_delta->irq_line = info->irq_line;
else
sigma_delta->irq_line = spi->irq;
sigma_delta->rdy_gpiod = devm_gpiod_get_optional(&spi->dev, "rdy", GPIOD_IN);
if (IS_ERR(sigma_delta->rdy_gpiod))
return dev_err_probe(&spi->dev, PTR_ERR(sigma_delta->rdy_gpiod),
"Failed to find rdy gpio\n");
if (sigma_delta->rdy_gpiod && !sigma_delta->irq_line) {
sigma_delta->irq_line = gpiod_to_irq(sigma_delta->rdy_gpiod);
if (sigma_delta->irq_line < 0)
return sigma_delta->irq_line;
}
iio_device_set_drvdata(indio_dev, sigma_delta);
return 0;

View File

@ -12,6 +12,7 @@
#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/limits.h>
#include <linux/regmap.h>
#include <linux/units.h>
@ -67,6 +68,14 @@ enum pac1921_mxsl {
#define PAC1921_DEFAULT_DI_GAIN 0 /* 2^(value): 1x gain (HW default) */
#define PAC1921_DEFAULT_NUM_SAMPLES 0 /* 2^(value): 1 sample (HW default) */
#define PAC1921_ACPI_GET_uOHMS_VALS 0
#define PAC1921_ACPI_GET_LABEL 1
/* f7bb9932-86ee-4516-a236-7a7a742e55cb */
static const guid_t pac1921_guid =
GUID_INIT(0xf7bb9932, 0x86ee, 0x4516, 0xa2,
0x36, 0x7a, 0x7a, 0x74, 0x2e, 0x55, 0xcb);
/*
* Pre-computed scale factors for BUS voltage
* format: IIO_VAL_INT_PLUS_NANO
@ -782,7 +791,7 @@ static ssize_t pac1921_write_shunt_resistor(struct iio_dev *indio_dev,
const char *buf, size_t len)
{
struct pac1921_priv *priv = iio_priv(indio_dev);
u64 rshunt_uohm;
u32 rshunt_uohm;
int val, val_fract;
int ret;
@ -793,10 +802,17 @@ static ssize_t pac1921_write_shunt_resistor(struct iio_dev *indio_dev,
if (ret)
return ret;
rshunt_uohm = val * MICRO + val_fract;
if (rshunt_uohm == 0 || rshunt_uohm > INT_MAX)
/*
* This check validates the shunt is not zero and does not surpass
* INT_MAX. The check is done before calculating in order to avoid
* val * MICRO overflowing.
*/
if ((!val && !val_fract) || val > INT_MAX / MICRO ||
(val == INT_MAX / MICRO && val_fract > INT_MAX % MICRO))
return -EINVAL;
rshunt_uohm = val * MICRO + val_fract;
guard(mutex)(&priv->lock);
priv->rshunt_uohm = rshunt_uohm;
@ -1151,6 +1167,61 @@ static void pac1921_regulator_disable(void *data)
regulator_disable(regulator);
}
/*
* Documentation related to the ACPI device definition
* https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC193X-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf
*/
static int pac1921_match_acpi_device(struct iio_dev *indio_dev)
{
acpi_handle handle;
union acpi_object *status;
char *label;
struct pac1921_priv *priv = iio_priv(indio_dev);
struct device *dev = &priv->client->dev;
handle = ACPI_HANDLE(dev);
status = acpi_evaluate_dsm(handle, &pac1921_guid, 1,
PAC1921_ACPI_GET_uOHMS_VALS, NULL);
if (!status)
return dev_err_probe(dev, -EINVAL,
"Could not read shunt from ACPI table\n");
priv->rshunt_uohm = status->package.elements[0].integer.value;
ACPI_FREE(status);
status = acpi_evaluate_dsm(handle, &pac1921_guid, 1,
PAC1921_ACPI_GET_LABEL, NULL);
if (!status)
return dev_err_probe(dev, -EINVAL,
"Could not read label from ACPI table\n");
label = devm_kstrdup(dev, status->package.elements[0].string.pointer,
GFP_KERNEL);
if (!label)
return -ENOMEM;
indio_dev->label = label;
ACPI_FREE(status);
return 0;
}
static int pac1921_parse_of_fw(struct iio_dev *indio_dev)
{
int ret;
struct pac1921_priv *priv = iio_priv(indio_dev);
struct device *dev = &priv->client->dev;
ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms",
&priv->rshunt_uohm);
if (ret)
return dev_err_probe(dev, ret,
"Cannot read shunt resistor property\n");
return 0;
}
static int pac1921_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@ -1179,11 +1250,14 @@ static int pac1921_probe(struct i2c_client *client)
priv->di_gain = PAC1921_DEFAULT_DI_GAIN;
priv->n_samples = PAC1921_DEFAULT_NUM_SAMPLES;
ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms",
&priv->rshunt_uohm);
if (is_acpi_device_node(dev->fwnode))
ret = pac1921_match_acpi_device(indio_dev);
else
ret = pac1921_parse_of_fw(indio_dev);
if (ret)
return dev_err_probe(dev, ret,
"Cannot read shunt resistor property\n");
"Parameter parsing error\n");
if (priv->rshunt_uohm == 0 || priv->rshunt_uohm > INT_MAX)
return dev_err_probe(dev, -EINVAL,
"Invalid shunt resistor: %u\n",
@ -1246,11 +1320,18 @@ static const struct of_device_id pac1921_of_match[] = {
};
MODULE_DEVICE_TABLE(of, pac1921_of_match);
static const struct acpi_device_id pac1921_acpi_match[] = {
{ "MCHP1921" },
{ }
};
MODULE_DEVICE_TABLE(acpi, pac1921_acpi_match);
static struct i2c_driver pac1921_driver = {
.driver = {
.name = "pac1921",
.pm = pm_sleep_ptr(&pac1921_pm_ops),
.of_match_table = pac1921_of_match,
.acpi_match_table = pac1921_acpi_match,
},
.probe = pac1921_probe,
.id_table = pac1921_id,

View File

@ -8,12 +8,13 @@
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@ -32,20 +33,15 @@
#define RZG2L_ADM1_MS BIT(2)
#define RZG2L_ADM1_BS BIT(4)
#define RZG2L_ADM1_EGA_MASK GENMASK(13, 12)
#define RZG2L_ADM2_CHSEL_MASK GENMASK(7, 0)
#define RZG2L_ADM3_ADIL_MASK GENMASK(31, 24)
#define RZG2L_ADM3_ADCMP_MASK GENMASK(23, 16)
#define RZG2L_ADM3_ADCMP_E FIELD_PREP(RZG2L_ADM3_ADCMP_MASK, 0xe)
#define RZG2L_ADM3_ADSMP_MASK GENMASK(15, 0)
#define RZG2L_ADINT 0x20
#define RZG2L_ADINT_INTEN_MASK GENMASK(7, 0)
#define RZG2L_ADINT_CSEEN BIT(16)
#define RZG2L_ADINT_INTS BIT(31)
#define RZG2L_ADSTS 0x24
#define RZG2L_ADSTS_CSEST BIT(16)
#define RZG2L_ADSTS_INTST_MASK GENMASK(7, 0)
#define RZG2L_ADIVC 0x28
#define RZG2L_ADIVC_DIVADC_MASK GENMASK(8, 0)
@ -56,12 +52,28 @@
#define RZG2L_ADCR(n) (0x30 + ((n) * 0x4))
#define RZG2L_ADCR_AD_MASK GENMASK(11, 0)
#define RZG2L_ADSMP_DEFAULT_SAMPLING 0x578
#define RZG2L_ADC_MAX_CHANNELS 8
#define RZG2L_ADC_CHN_MASK 0x7
#define RZG2L_ADC_MAX_CHANNELS 9
#define RZG2L_ADC_TIMEOUT usecs_to_jiffies(1 * 4)
/**
* struct rzg2l_adc_hw_params - ADC hardware specific parameters
* @default_adsmp: default ADC sampling period (see ADM3 register); index 0 is
* used for voltage channels, index 1 is used for temperature channel
* @adsmp_mask: ADC sampling period mask (see ADM3 register)
* @adint_inten_mask: conversion end interrupt mask (see ADINT register)
* @default_adcmp: default ADC cmp (see ADM3 register)
* @num_channels: number of supported channels
* @adivc: specifies if ADVIC register is available
*/
struct rzg2l_adc_hw_params {
u16 default_adsmp[2];
u16 adsmp_mask;
u16 adint_inten_mask;
u8 default_adcmp;
u8 num_channels;
bool adivc;
};
struct rzg2l_adc_data {
const struct iio_chan_spec *channels;
u8 num_channels;
@ -69,25 +81,36 @@ struct rzg2l_adc_data {
struct rzg2l_adc {
void __iomem *base;
struct clk *pclk;
struct clk *adclk;
struct reset_control *presetn;
struct reset_control *adrstn;
struct completion completion;
const struct rzg2l_adc_data *data;
const struct rzg2l_adc_hw_params *hw_params;
struct completion completion;
struct mutex lock;
u16 last_val[RZG2L_ADC_MAX_CHANNELS];
bool was_rpm_active;
};
static const char * const rzg2l_adc_channel_name[] = {
"adc0",
"adc1",
"adc2",
"adc3",
"adc4",
"adc5",
"adc6",
"adc7",
/**
* struct rzg2l_adc_channel - ADC channel descriptor
* @name: ADC channel name
* @type: ADC channel type
*/
struct rzg2l_adc_channel {
const char * const name;
enum iio_chan_type type;
};
static const struct rzg2l_adc_channel rzg2l_adc_channels[] = {
{ "adc0", IIO_VOLTAGE },
{ "adc1", IIO_VOLTAGE },
{ "adc2", IIO_VOLTAGE },
{ "adc3", IIO_VOLTAGE },
{ "adc4", IIO_VOLTAGE },
{ "adc5", IIO_VOLTAGE },
{ "adc6", IIO_VOLTAGE },
{ "adc7", IIO_VOLTAGE },
{ "adc8", IIO_TEMP },
};
static unsigned int rzg2l_adc_readl(struct rzg2l_adc *adc, u32 reg)
@ -115,7 +138,7 @@ static void rzg2l_adc_pwr(struct rzg2l_adc *adc, bool on)
static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start)
{
int timeout = 5;
int ret;
u32 reg;
reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
@ -128,15 +151,10 @@ static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start)
if (start)
return;
do {
usleep_range(100, 200);
reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
timeout--;
if (!timeout) {
pr_err("%s stopping ADC timed out\n", __func__);
break;
}
} while (((reg & RZG2L_ADM0_ADBSY) || (reg & RZG2L_ADM0_ADCE)));
ret = read_poll_timeout(rzg2l_adc_readl, reg, !(reg & (RZG2L_ADM0_ADBSY | RZG2L_ADM0_ADCE)),
200, 1000, true, adc, RZG2L_ADM(0));
if (ret)
pr_err("%s stopping ADC timed out\n", __func__);
}
static void rzg2l_set_trigger(struct rzg2l_adc *adc)
@ -158,8 +176,18 @@ static void rzg2l_set_trigger(struct rzg2l_adc *adc)
rzg2l_adc_writel(adc, RZG2L_ADM(1), reg);
}
static u8 rzg2l_adc_ch_to_adsmp_index(u8 ch)
{
if (rzg2l_adc_channels[ch].type == IIO_VOLTAGE)
return 0;
return 1;
}
static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch)
{
const struct rzg2l_adc_hw_params *hw_params = adc->hw_params;
u8 index = rzg2l_adc_ch_to_adsmp_index(ch);
u32 reg;
if (rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_ADBSY)
@ -169,10 +197,15 @@ static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch)
/* Select analog input channel subjected to conversion. */
reg = rzg2l_adc_readl(adc, RZG2L_ADM(2));
reg &= ~RZG2L_ADM2_CHSEL_MASK;
reg &= ~GENMASK(hw_params->num_channels - 1, 0);
reg |= BIT(ch);
rzg2l_adc_writel(adc, RZG2L_ADM(2), reg);
reg = rzg2l_adc_readl(adc, RZG2L_ADM(3));
reg &= ~hw_params->adsmp_mask;
reg |= hw_params->default_adsmp[index];
rzg2l_adc_writel(adc, RZG2L_ADM(3), reg);
/*
* Setup ADINT
* INTS[31] - Select pulse signal
@ -181,36 +214,26 @@ static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch)
*/
reg = rzg2l_adc_readl(adc, RZG2L_ADINT);
reg &= ~RZG2L_ADINT_INTS;
reg &= ~RZG2L_ADINT_INTEN_MASK;
reg &= ~hw_params->adint_inten_mask;
reg |= (RZG2L_ADINT_CSEEN | BIT(ch));
rzg2l_adc_writel(adc, RZG2L_ADINT, reg);
return 0;
}
static int rzg2l_adc_set_power(struct iio_dev *indio_dev, bool on)
{
struct device *dev = indio_dev->dev.parent;
if (on)
return pm_runtime_resume_and_get(dev);
return pm_runtime_put_sync(dev);
}
static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc, u8 ch)
{
const struct rzg2l_adc_hw_params *hw_params = adc->hw_params;
struct device *dev = indio_dev->dev.parent;
int ret;
ret = rzg2l_adc_set_power(indio_dev, true);
ret = pm_runtime_resume_and_get(dev);
if (ret)
return ret;
ret = rzg2l_adc_conversion_setup(adc, ch);
if (ret) {
rzg2l_adc_set_power(indio_dev, false);
return ret;
}
if (ret)
goto rpm_put;
reinit_completion(&adc->completion);
@ -218,13 +241,16 @@ static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc
if (!wait_for_completion_timeout(&adc->completion, RZG2L_ADC_TIMEOUT)) {
rzg2l_adc_writel(adc, RZG2L_ADINT,
rzg2l_adc_readl(adc, RZG2L_ADINT) & ~RZG2L_ADINT_INTEN_MASK);
rzg2l_adc_start_stop(adc, false);
rzg2l_adc_set_power(indio_dev, false);
return -ETIMEDOUT;
rzg2l_adc_readl(adc, RZG2L_ADINT) & ~hw_params->adint_inten_mask);
ret = -ETIMEDOUT;
}
return rzg2l_adc_set_power(indio_dev, false);
rzg2l_adc_start_stop(adc, false);
rpm_put:
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
static int rzg2l_adc_read_raw(struct iio_dev *indio_dev,
@ -233,24 +259,22 @@ static int rzg2l_adc_read_raw(struct iio_dev *indio_dev,
{
struct rzg2l_adc *adc = iio_priv(indio_dev);
int ret;
u8 ch;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->type != IIO_VOLTAGE)
case IIO_CHAN_INFO_RAW: {
if (chan->type != IIO_VOLTAGE && chan->type != IIO_TEMP)
return -EINVAL;
mutex_lock(&adc->lock);
ch = chan->channel & RZG2L_ADC_CHN_MASK;
ret = rzg2l_adc_conversion(indio_dev, adc, ch);
if (ret) {
mutex_unlock(&adc->lock);
guard(mutex)(&adc->lock);
ret = rzg2l_adc_conversion(indio_dev, adc, chan->channel);
if (ret)
return ret;
}
*val = adc->last_val[ch];
mutex_unlock(&adc->lock);
*val = adc->last_val[chan->channel];
return IIO_VAL_INT;
}
default:
return -EINVAL;
@ -261,7 +285,7 @@ static int rzg2l_adc_read_label(struct iio_dev *iio_dev,
const struct iio_chan_spec *chan,
char *label)
{
return sysfs_emit(label, "%s\n", rzg2l_adc_channel_name[chan->channel]);
return sysfs_emit(label, "%s\n", rzg2l_adc_channels[chan->channel].name);
}
static const struct iio_info rzg2l_adc_iio_info = {
@ -272,6 +296,7 @@ static const struct iio_info rzg2l_adc_iio_info = {
static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id)
{
struct rzg2l_adc *adc = dev_id;
const struct rzg2l_adc_hw_params *hw_params = adc->hw_params;
unsigned long intst;
u32 reg;
int ch;
@ -284,11 +309,11 @@ static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
intst = reg & RZG2L_ADSTS_INTST_MASK;
intst = reg & GENMASK(hw_params->num_channels - 1, 0);
if (!intst)
return IRQ_NONE;
for_each_set_bit(ch, &intst, RZG2L_ADC_MAX_CHANNELS)
for_each_set_bit(ch, &intst, hw_params->num_channels)
adc->last_val[ch] = rzg2l_adc_readl(adc, RZG2L_ADCR(ch)) & RZG2L_ADCR_AD_MASK;
/* clear the channel interrupt */
@ -301,6 +326,7 @@ static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id)
static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc)
{
const struct rzg2l_adc_hw_params *hw_params = adc->hw_params;
struct iio_chan_spec *chan_array;
struct rzg2l_adc_data *data;
unsigned int channel;
@ -313,15 +339,12 @@ static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l
return -ENOMEM;
num_channels = device_get_child_node_count(&pdev->dev);
if (!num_channels) {
dev_err(&pdev->dev, "no channel children\n");
return -ENODEV;
}
if (!num_channels)
return dev_err_probe(&pdev->dev, -ENODEV, "no channel children\n");
if (num_channels > RZG2L_ADC_MAX_CHANNELS) {
dev_err(&pdev->dev, "num of channel children out of range\n");
return -EINVAL;
}
if (num_channels > hw_params->num_channels)
return dev_err_probe(&pdev->dev, -EINVAL,
"num of channel children out of range\n");
chan_array = devm_kcalloc(&pdev->dev, num_channels, sizeof(*chan_array),
GFP_KERNEL);
@ -334,14 +357,14 @@ static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l
if (ret)
return ret;
if (channel >= RZG2L_ADC_MAX_CHANNELS)
if (channel >= hw_params->num_channels)
return -EINVAL;
chan_array[i].type = IIO_VOLTAGE;
chan_array[i].type = rzg2l_adc_channels[channel].type;
chan_array[i].indexed = 1;
chan_array[i].channel = channel;
chan_array[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
chan_array[i].datasheet_name = rzg2l_adc_channel_name[channel];
chan_array[i].datasheet_name = rzg2l_adc_channels[channel].name;
i++;
}
@ -352,13 +375,13 @@ static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l
return 0;
}
static int rzg2l_adc_hw_init(struct rzg2l_adc *adc)
static int rzg2l_adc_hw_init(struct device *dev, struct rzg2l_adc *adc)
{
int timeout = 5;
const struct rzg2l_adc_hw_params *hw_params = adc->hw_params;
u32 reg;
int ret;
ret = clk_prepare_enable(adc->pclk);
ret = pm_runtime_resume_and_get(dev);
if (ret)
return ret;
@ -367,20 +390,18 @@ static int rzg2l_adc_hw_init(struct rzg2l_adc *adc)
reg |= RZG2L_ADM0_SRESB;
rzg2l_adc_writel(adc, RZG2L_ADM(0), reg);
while (!(rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_SRESB)) {
if (!timeout) {
ret = -EBUSY;
goto exit_hw_init;
}
timeout--;
usleep_range(100, 200);
}
ret = read_poll_timeout(rzg2l_adc_readl, reg, reg & RZG2L_ADM0_SRESB,
200, 1000, false, adc, RZG2L_ADM(0));
if (ret)
goto exit_hw_init;
/* Only division by 4 can be set */
reg = rzg2l_adc_readl(adc, RZG2L_ADIVC);
reg &= ~RZG2L_ADIVC_DIVADC_MASK;
reg |= RZG2L_ADIVC_DIVADC_4;
rzg2l_adc_writel(adc, RZG2L_ADIVC, reg);
if (hw_params->adivc) {
/* Only division by 4 can be set */
reg = rzg2l_adc_readl(adc, RZG2L_ADIVC);
reg &= ~RZG2L_ADIVC_DIVADC_MASK;
reg |= RZG2L_ADIVC_DIVADC_4;
rzg2l_adc_writel(adc, RZG2L_ADIVC, reg);
}
/*
* Setup AMD3
@ -391,35 +412,18 @@ static int rzg2l_adc_hw_init(struct rzg2l_adc *adc)
reg = rzg2l_adc_readl(adc, RZG2L_ADM(3));
reg &= ~RZG2L_ADM3_ADIL_MASK;
reg &= ~RZG2L_ADM3_ADCMP_MASK;
reg &= ~RZG2L_ADM3_ADSMP_MASK;
reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFAULT_SAMPLING);
reg &= ~hw_params->adsmp_mask;
reg |= FIELD_PREP(RZG2L_ADM3_ADCMP_MASK, hw_params->default_adcmp) |
hw_params->default_adsmp[0];
rzg2l_adc_writel(adc, RZG2L_ADM(3), reg);
exit_hw_init:
clk_disable_unprepare(adc->pclk);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
static void rzg2l_adc_pm_runtime_disable(void *data)
{
struct device *dev = data;
pm_runtime_disable(dev->parent);
}
static void rzg2l_adc_pm_runtime_set_suspended(void *data)
{
struct device *dev = data;
pm_runtime_set_suspended(dev->parent);
}
static void rzg2l_adc_reset_assert(void *data)
{
reset_control_assert(data);
}
static int rzg2l_adc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -434,6 +438,10 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
adc = iio_priv(indio_dev);
adc->hw_params = device_get_match_data(dev);
if (!adc->hw_params || adc->hw_params->num_channels > RZG2L_ADC_MAX_CHANNELS)
return -EINVAL;
ret = rzg2l_adc_parse_properties(pdev, adc);
if (ret)
return ret;
@ -444,63 +452,28 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
if (IS_ERR(adc->base))
return PTR_ERR(adc->base);
adc->pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(adc->pclk)) {
dev_err(dev, "Failed to get pclk");
return PTR_ERR(adc->pclk);
}
adc->adrstn = devm_reset_control_get_exclusive_deasserted(dev, "adrst-n");
if (IS_ERR(adc->adrstn))
return dev_err_probe(dev, PTR_ERR(adc->adrstn),
"failed to get/deassert adrst-n\n");
adc->adclk = devm_clk_get(dev, "adclk");
if (IS_ERR(adc->adclk)) {
dev_err(dev, "Failed to get adclk");
return PTR_ERR(adc->adclk);
}
adc->presetn = devm_reset_control_get_exclusive_deasserted(dev, "presetn");
if (IS_ERR(adc->presetn))
return dev_err_probe(dev, PTR_ERR(adc->presetn),
"failed to get/deassert presetn\n");
adc->adrstn = devm_reset_control_get_exclusive(dev, "adrst-n");
if (IS_ERR(adc->adrstn)) {
dev_err(dev, "failed to get adrstn\n");
return PTR_ERR(adc->adrstn);
}
adc->presetn = devm_reset_control_get_exclusive(dev, "presetn");
if (IS_ERR(adc->presetn)) {
dev_err(dev, "failed to get presetn\n");
return PTR_ERR(adc->presetn);
}
ret = reset_control_deassert(adc->adrstn);
if (ret) {
dev_err(&pdev->dev, "failed to deassert adrstn pin, %d\n", ret);
pm_runtime_set_autosuspend_delay(dev, 300);
pm_runtime_use_autosuspend(dev);
ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
}
ret = devm_add_action_or_reset(&pdev->dev,
rzg2l_adc_reset_assert, adc->adrstn);
if (ret) {
dev_err(&pdev->dev, "failed to register adrstn assert devm action, %d\n",
ret);
return ret;
}
platform_set_drvdata(pdev, indio_dev);
ret = reset_control_deassert(adc->presetn);
if (ret) {
dev_err(&pdev->dev, "failed to deassert presetn pin, %d\n", ret);
return ret;
}
ret = devm_add_action_or_reset(&pdev->dev,
rzg2l_adc_reset_assert, adc->presetn);
if (ret) {
dev_err(&pdev->dev, "failed to register presetn assert devm action, %d\n",
ret);
return ret;
}
ret = rzg2l_adc_hw_init(adc);
if (ret) {
dev_err(&pdev->dev, "failed to initialize ADC HW, %d\n", ret);
return ret;
}
ret = rzg2l_adc_hw_init(dev, adc);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"failed to initialize ADC HW\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@ -513,72 +486,130 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
init_completion(&adc->completion);
platform_set_drvdata(pdev, indio_dev);
indio_dev->name = DRIVER_NAME;
indio_dev->info = &rzg2l_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = adc->data->channels;
indio_dev->num_channels = adc->data->num_channels;
pm_runtime_set_suspended(dev);
ret = devm_add_action_or_reset(&pdev->dev,
rzg2l_adc_pm_runtime_set_suspended, &indio_dev->dev);
if (ret)
return ret;
pm_runtime_enable(dev);
ret = devm_add_action_or_reset(&pdev->dev,
rzg2l_adc_pm_runtime_disable, &indio_dev->dev);
if (ret)
return ret;
return devm_iio_device_register(dev, indio_dev);
}
static const struct rzg2l_adc_hw_params rzg2l_hw_params = {
.num_channels = 8,
.default_adcmp = 0xe,
.default_adsmp = { 0x578 },
.adsmp_mask = GENMASK(15, 0),
.adint_inten_mask = GENMASK(7, 0),
.adivc = true
};
static const struct rzg2l_adc_hw_params rzg3s_hw_params = {
.num_channels = 9,
.default_adcmp = 0x1d,
.default_adsmp = { 0x7f, 0xff },
.adsmp_mask = GENMASK(7, 0),
.adint_inten_mask = GENMASK(11, 0),
};
static const struct of_device_id rzg2l_adc_match[] = {
{ .compatible = "renesas,rzg2l-adc",},
{ .compatible = "renesas,r9a08g045-adc", .data = &rzg3s_hw_params },
{ .compatible = "renesas,rzg2l-adc", .data = &rzg2l_hw_params },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rzg2l_adc_match);
static int __maybe_unused rzg2l_adc_pm_runtime_suspend(struct device *dev)
static int rzg2l_adc_pm_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct rzg2l_adc *adc = iio_priv(indio_dev);
rzg2l_adc_pwr(adc, false);
clk_disable_unprepare(adc->adclk);
clk_disable_unprepare(adc->pclk);
return 0;
}
static int __maybe_unused rzg2l_adc_pm_runtime_resume(struct device *dev)
static int rzg2l_adc_pm_runtime_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct rzg2l_adc *adc = iio_priv(indio_dev);
int ret;
ret = clk_prepare_enable(adc->pclk);
if (ret)
return ret;
ret = clk_prepare_enable(adc->adclk);
if (ret) {
clk_disable_unprepare(adc->pclk);
return ret;
}
rzg2l_adc_pwr(adc, true);
return 0;
}
static int rzg2l_adc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct rzg2l_adc *adc = iio_priv(indio_dev);
struct reset_control_bulk_data resets[] = {
{ .rstc = adc->presetn },
{ .rstc = adc->adrstn },
};
int ret;
if (pm_runtime_suspended(dev)) {
adc->was_rpm_active = false;
} else {
ret = pm_runtime_force_suspend(dev);
if (ret)
return ret;
adc->was_rpm_active = true;
}
ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
if (ret)
goto rpm_restore;
return 0;
rpm_restore:
if (adc->was_rpm_active)
pm_runtime_force_resume(dev);
return ret;
}
static int rzg2l_adc_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct rzg2l_adc *adc = iio_priv(indio_dev);
struct reset_control_bulk_data resets[] = {
{ .rstc = adc->adrstn },
{ .rstc = adc->presetn },
};
int ret;
ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
if (ret)
return ret;
if (adc->was_rpm_active) {
ret = pm_runtime_force_resume(dev);
if (ret)
goto resets_restore;
}
ret = rzg2l_adc_hw_init(dev, adc);
if (ret)
goto rpm_restore;
return 0;
rpm_restore:
if (adc->was_rpm_active) {
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
}
resets_restore:
reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
return ret;
}
static const struct dev_pm_ops rzg2l_adc_pm_ops = {
SET_RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend,
rzg2l_adc_pm_runtime_resume,
NULL)
RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend, rzg2l_adc_pm_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(rzg2l_adc_suspend, rzg2l_adc_resume)
};
static struct platform_driver rzg2l_adc_driver = {
@ -586,7 +617,7 @@ static struct platform_driver rzg2l_adc_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = rzg2l_adc_match,
.pm = &rzg2l_adc_pm_ops,
.pm = pm_ptr(&rzg2l_adc_pm_ops),
},
};

View File

@ -177,6 +177,10 @@ struct vf610_adc {
} scan;
};
struct vf610_chip_info {
u8 num_channels;
};
static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 };
@ -808,14 +812,31 @@ static const struct iio_info vf610_adc_iio_info = {
.attrs = &vf610_attribute_group,
};
static const struct vf610_chip_info vf610_chip_info = {
.num_channels = ARRAY_SIZE(vf610_adc_iio_channels),
};
static const struct vf610_chip_info imx6sx_chip_info = {
.num_channels = 4,
};
static const struct of_device_id vf610_adc_match[] = {
{ .compatible = "fsl,vf610-adc", },
{ .compatible = "fsl,imx6sx-adc", .data = &imx6sx_chip_info},
{ .compatible = "fsl,vf610-adc", .data = &vf610_chip_info},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, vf610_adc_match);
static void vf610_adc_action_remove(void *d)
{
struct vf610_adc *info = d;
regulator_disable(info->vref);
}
static int vf610_adc_probe(struct platform_device *pdev)
{
const struct vf610_chip_info *chip_info;
struct device *dev = &pdev->dev;
struct vf610_adc *info;
struct iio_dev *indio_dev;
@ -823,10 +844,8 @@ static int vf610_adc_probe(struct platform_device *pdev)
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc));
if (!indio_dev) {
dev_err(&pdev->dev, "Failed allocating iio device\n");
return -ENOMEM;
}
if (!indio_dev)
return dev_err_probe(&pdev->dev, -ENOMEM, "Failed allocating iio device\n");
info = iio_priv(indio_dev);
info->dev = &pdev->dev;
@ -835,6 +854,8 @@ static int vf610_adc_probe(struct platform_device *pdev)
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
chip_info = device_get_match_data(dev);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@ -842,17 +863,12 @@ static int vf610_adc_probe(struct platform_device *pdev)
ret = devm_request_irq(info->dev, irq,
vf610_adc_isr, 0,
dev_name(&pdev->dev), indio_dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq);
return ret;
}
if (ret < 0)
return dev_err_probe(&pdev->dev, ret, "failed requesting irq, irq = %d\n", irq);
info->clk = devm_clk_get(&pdev->dev, "adc");
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
PTR_ERR(info->clk));
return PTR_ERR(info->clk);
}
info->clk = devm_clk_get_enabled(&pdev->dev, "adc");
if (IS_ERR(info->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(info->clk), "failed getting clock\n");
info->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(info->vref))
@ -862,6 +878,10 @@ static int vf610_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
ret = devm_add_action_or_reset(&pdev->dev, vf610_adc_action_remove, info);
if (ret)
return ret;
info->vref_uv = regulator_get_voltage(info->vref);
device_property_read_u32_array(dev, "fsl,adck-max-frequency", info->max_adck_rate, 3);
@ -877,54 +897,23 @@ static int vf610_adc_probe(struct platform_device *pdev)
indio_dev->info = &vf610_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = vf610_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(vf610_adc_iio_channels);
ret = clk_prepare_enable(info->clk);
if (ret) {
dev_err(&pdev->dev,
"Could not prepare or enable the clock.\n");
goto error_adc_clk_enable;
}
indio_dev->num_channels = chip_info->num_channels;
vf610_adc_cfg_init(info);
vf610_adc_hw_init(info);
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, &iio_triggered_buffer_setup_ops);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't initialise the buffer\n");
goto error_iio_device_register;
}
ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev, &iio_pollfunc_store_time,
NULL, &iio_triggered_buffer_setup_ops);
if (ret < 0)
return dev_err_probe(&pdev->dev, ret, "Couldn't initialise the buffer\n");
mutex_init(&info->lock);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register the device.\n");
goto error_adc_buffer_init;
}
ret = devm_iio_device_register(&pdev->dev, indio_dev);
if (ret)
return dev_err_probe(&pdev->dev, ret, "Couldn't register the device.\n");
return 0;
error_adc_buffer_init:
iio_triggered_buffer_cleanup(indio_dev);
error_iio_device_register:
clk_disable_unprepare(info->clk);
error_adc_clk_enable:
regulator_disable(info->vref);
return ret;
}
static void vf610_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct vf610_adc *info = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(info->vref);
clk_disable_unprepare(info->clk);
}
static int vf610_adc_suspend(struct device *dev)
@ -972,7 +961,6 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend,
static struct platform_driver vf610_adc_driver = {
.probe = vf610_adc_probe,
.remove = vf610_adc_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = vf610_adc_match,

View File

@ -206,7 +206,7 @@ static const struct iio_dev_attr *iio_dmaengine_buffer_attrs[] = {
/**
* iio_dmaengine_buffer_alloc() - Allocate new buffer which uses DMAengine
* @dev: Parent device for the buffer
* @dev: DMA channel consumer device
* @channel: DMA channel name, typically "rx".
*
* This allocates a new IIO buffer which internally uses the DMAengine framework
@ -288,6 +288,21 @@ void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
}
EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, "IIO_DMAENGINE_BUFFER");
/**
* iio_dmaengine_buffer_setup_ext() - Setup a DMA buffer for an IIO device
* @dev: DMA channel consumer device
* @indio_dev: IIO device to which to attach this buffer.
* @channel: DMA channel name, typically "rx".
* @dir: Direction of buffer (in or out)
*
* This allocates a new IIO buffer with devm_iio_dmaengine_buffer_alloc()
* and attaches it to an IIO device with iio_device_attach_buffer().
* It also appends the INDIO_BUFFER_HARDWARE mode to the supported modes of the
* IIO device.
*
* Once done using the buffer iio_dmaengine_buffer_free() should be used to
* release it.
*/
struct iio_buffer *iio_dmaengine_buffer_setup_ext(struct device *dev,
struct iio_dev *indio_dev,
const char *channel,
@ -321,7 +336,7 @@ static void __devm_iio_dmaengine_buffer_free(void *buffer)
/**
* devm_iio_dmaengine_buffer_setup_ext() - Setup a DMA buffer for an IIO device
* @dev: Parent device for the buffer
* @dev: Device for devm ownership and DMA channel consumer device
* @indio_dev: IIO device to which to attach this buffer.
* @channel: DMA channel name, typically "rx".
* @dir: Direction of buffer (in or out)

View File

@ -2,6 +2,7 @@
#ifndef BME680_H_
#define BME680_H_
#include <linux/pm.h>
#include <linux/regmap.h>
#define BME680_REG_CHIP_ID 0xD0
@ -80,6 +81,7 @@
#define BME680_CALIB_RANGE_3_LEN 5
extern const struct regmap_config bme680_regmap_config;
extern const struct dev_pm_ops bme680_dev_pm_ops;
int bme680_core_probe(struct device *dev, struct regmap *regmap,
const char *name);

View File

@ -14,7 +14,10 @@
#include <linux/device.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
@ -111,6 +114,8 @@ enum bme680_scan {
BME680_GAS,
};
static const char *const bme680_supply_names[] = { "vdd", "vddio" };
struct bme680_data {
struct regmap *regmap;
struct bme680_calib bme680;
@ -817,9 +822,9 @@ static int bme680_read_gas(struct bme680_data *data, int *comp_gas_res)
return 0;
}
static int bme680_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
static int __bme680_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct bme680_data *data = iio_priv(indio_dev);
int chan_val, ret;
@ -932,14 +937,33 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
}
}
static int bme680_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct bme680_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
int ret;
ret = pm_runtime_resume_and_get(dev);
if (ret)
return ret;
ret = __bme680_read_raw(indio_dev, chan, val, val2, mask);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
static bool bme680_is_valid_oversampling(int rate)
{
return (rate > 0 && rate <= 16 && is_power_of_2(rate));
}
static int bme680_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
static int __bme680_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct bme680_data *data = iio_priv(indio_dev);
@ -984,6 +1008,25 @@ static int bme680_write_raw(struct iio_dev *indio_dev,
}
}
static int bme680_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct bme680_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
int ret;
ret = pm_runtime_resume_and_get(dev);
if (ret)
return ret;
ret = __bme680_write_raw(indio_dev, chan, val, val2, mask);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
static const char bme680_oversampling_ratio_show[] = "1 2 4 8 16";
static IIO_CONST_ATTR(oversampling_ratio_available,
@ -1084,6 +1127,29 @@ static irqreturn_t bme680_trigger_handler(int irq, void *p)
return IRQ_HANDLED;
}
static int bme680_buffer_preenable(struct iio_dev *indio_dev)
{
struct bme680_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
return pm_runtime_resume_and_get(dev);
}
static int bme680_buffer_postdisable(struct iio_dev *indio_dev)
{
struct bme680_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
}
static const struct iio_buffer_setup_ops bme680_buffer_setup_ops = {
.preenable = bme680_buffer_preenable,
.postdisable = bme680_buffer_postdisable,
};
int bme680_core_probe(struct device *dev, struct regmap *regmap,
const char *name)
{
@ -1114,6 +1180,14 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
data->heater_dur = 150; /* milliseconds */
data->preheat_curr_mA = 0;
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(bme680_supply_names),
bme680_supply_names);
if (ret)
return dev_err_probe(dev, ret,
"failed to get and enable supplies.\n");
fsleep(BME680_STARTUP_TIME_US);
ret = regmap_write(regmap, BME680_REG_SOFT_RESET, BME680_CMD_SOFTRESET);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to reset chip\n");
@ -1149,15 +1223,47 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
bme680_trigger_handler,
NULL);
&bme680_buffer_setup_ops);
if (ret)
return dev_err_probe(dev, ret,
"iio triggered buffer setup failed\n");
/* Enable runtime PM */
pm_runtime_set_autosuspend_delay(dev, BME680_STARTUP_TIME_US);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_active(dev);
ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(bme680_core_probe, "IIO_BME680");
static int bme680_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bme680_data *data = iio_priv(indio_dev);
return bme680_set_mode(data, BME680_MODE_SLEEP);
}
static int bme680_runtime_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bme680_data *data = iio_priv(indio_dev);
int ret;
ret = bme680_chip_config(data);
if (ret)
return ret;
return bme680_gas_config(data);
}
EXPORT_RUNTIME_DEV_PM_OPS(bme680_dev_pm_ops, bme680_runtime_suspend,
bme680_runtime_resume, NULL);
MODULE_AUTHOR("Himanshu Jha <himanshujha199640@gmail.com>");
MODULE_DESCRIPTION("Bosch BME680 Driver");
MODULE_LICENSE("GPL v2");

View File

@ -51,6 +51,7 @@ static struct i2c_driver bme680_i2c_driver = {
.driver = {
.name = "bme680_i2c",
.of_match_table = bme680_of_i2c_match,
.pm = pm_ptr(&bme680_dev_pm_ops),
},
.probe = bme680_i2c_probe,
.id_table = bme680_i2c_id,

View File

@ -154,6 +154,7 @@ static struct spi_driver bme680_spi_driver = {
.driver = {
.name = "bme680_spi",
.of_match_table = bme680_of_spi_match,
.pm = pm_ptr(&bme680_dev_pm_ops),
},
.probe = bme680_spi_probe,
.id_table = bme680_spi_id,

View File

@ -109,8 +109,8 @@ static bool inv_update_chip_period(struct inv_sensors_timestamp *ts,
static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts)
{
const int64_t period_min = ts->min_period * ts->mult;
const int64_t period_max = ts->max_period * ts->mult;
const int64_t period_min = (int64_t)ts->min_period * ts->mult;
const int64_t period_max = (int64_t)ts->max_period * ts->mult;
int64_t add_max, sub_max;
int64_t delta, jitter;
int64_t adjust;

View File

@ -80,7 +80,7 @@ config AD5421
depends on SPI
help
Say yes here to build support for Analog Devices AD5421 loop-powered
digital-to-analog convertors (DAC).
digital-to-analog converters (DAC).
To compile this driver as module choose M here: the module will be called
ad5421.

View File

@ -41,7 +41,7 @@ struct ad5624r_chip_info {
};
/**
* struct ad5446_state - driver instance specific data
* struct ad5624r_state - driver instance specific data
* @indio_dev: the industrial I/O device
* @us: spi_device
* @chip_info: chip model specific constants, available modes etc

View File

@ -95,11 +95,6 @@ static int ad5686_spi_probe(struct spi_device *spi)
ad5686_spi_write, ad5686_spi_read);
}
static void ad5686_spi_remove(struct spi_device *spi)
{
ad5686_remove(&spi->dev);
}
static const struct spi_device_id ad5686_spi_id[] = {
{"ad5310r", ID_AD5310R},
{"ad5672r", ID_AD5672R},
@ -126,7 +121,6 @@ static struct spi_driver ad5686_spi_driver = {
.name = "ad5686",
},
.probe = ad5686_spi_probe,
.remove = ad5686_spi_remove,
.id_table = ad5686_spi_id,
};

View File

@ -455,39 +455,28 @@ int ad5686_probe(struct device *dev,
struct ad5686_state *st;
struct iio_dev *indio_dev;
unsigned int val, ref_bit_msk;
bool has_external_vref;
u8 cmd;
int ret, i, voltage_uv = 0;
int ret, i;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
st->dev = dev;
st->write = write;
st->read = read;
st->reg = devm_regulator_get_optional(dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
goto error_disable_reg;
voltage_uv = ret;
}
st->chip_info = &ad5686_chip_info_tbl[chip_type];
if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else
st->vref_mv = st->chip_info->int_vref_mv;
ret = devm_regulator_get_enable_read_voltage(dev, "vcc");
if (ret < 0 && ret != -ENODEV)
return ret;
has_external_vref = ret != -ENODEV;
st->vref_mv = has_external_vref ? ret / 1000 : st->chip_info->int_vref_mv;
/* Set all the power down mode for all channels to 1K pulldown */
for (i = 0; i < st->chip_info->num_channels; i++)
@ -505,12 +494,12 @@ int ad5686_probe(struct device *dev,
case AD5310_REGMAP:
cmd = AD5686_CMD_CONTROL_REG;
ref_bit_msk = AD5310_REF_BIT_MSK;
st->use_internal_vref = !voltage_uv;
st->use_internal_vref = !has_external_vref;
break;
case AD5683_REGMAP:
cmd = AD5686_CMD_CONTROL_REG;
ref_bit_msk = AD5683_REF_BIT_MSK;
st->use_internal_vref = !voltage_uv;
st->use_internal_vref = !has_external_vref;
break;
case AD5686_REGMAP:
cmd = AD5686_CMD_INTERNAL_REFER_SETUP;
@ -519,43 +508,22 @@ int ad5686_probe(struct device *dev,
case AD5693_REGMAP:
cmd = AD5686_CMD_CONTROL_REG;
ref_bit_msk = AD5693_REF_BIT_MSK;
st->use_internal_vref = !voltage_uv;
st->use_internal_vref = !has_external_vref;
break;
default:
ret = -EINVAL;
goto error_disable_reg;
return -EINVAL;
}
val = (voltage_uv | ref_bit_msk);
val = (has_external_vref | ref_bit_msk);
ret = st->write(st, cmd, 0, !!val);
if (ret)
goto error_disable_reg;
return ret;
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(ad5686_probe, "IIO_AD5686");
void ad5686_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5686_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
}
EXPORT_SYMBOL_NS_GPL(ad5686_remove, "IIO_AD5686");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
MODULE_LICENSE("GPL v2");

View File

@ -115,10 +115,9 @@ struct ad5686_chip_info {
};
/**
* struct ad5446_state - driver instance specific data
* struct ad5686_state - driver instance specific data
* @spi: spi_device
* @chip_info: chip model specific constants, available modes etc
* @reg: supply regulator
* @vref_mv: actual reference voltage used
* @pwr_down_mask: power down mask
* @pwr_down_mode: current power down mode
@ -130,7 +129,6 @@ struct ad5686_chip_info {
struct ad5686_state {
struct device *dev;
const struct ad5686_chip_info *chip_info;
struct regulator *reg;
unsigned short vref_mv;
unsigned int pwr_down_mask;
unsigned int pwr_down_mode;
@ -157,7 +155,5 @@ int ad5686_probe(struct device *dev,
const char *name, ad5686_write_func write,
ad5686_read_func read);
void ad5686_remove(struct device *dev);
#endif /* __DRIVERS_IIO_DAC_AD5686_H__ */

View File

@ -65,11 +65,6 @@ static int ad5686_i2c_probe(struct i2c_client *i2c)
ad5686_i2c_write, ad5686_i2c_read);
}
static void ad5686_i2c_remove(struct i2c_client *i2c)
{
ad5686_remove(&i2c->dev);
}
static const struct i2c_device_id ad5686_i2c_id[] = {
{"ad5311r", ID_AD5311R},
{"ad5337r", ID_AD5337R},
@ -116,7 +111,6 @@ static struct i2c_driver ad5686_i2c_driver = {
.of_match_table = ad5686_of_match,
},
.probe = ad5686_i2c_probe,
.remove = ad5686_i2c_remove,
.id_table = ad5686_i2c_id,
};

View File

@ -23,8 +23,6 @@ struct ad8801_state {
unsigned char dac_cache[8]; /* Value write on each channel */
unsigned int vrefh_mv;
unsigned int vrefl_mv;
struct regulator *vrefh_reg;
struct regulator *vrefl_reg;
__be16 data __aligned(IIO_DMA_MINALIGN);
};
@ -122,86 +120,34 @@ static int ad8801_probe(struct spi_device *spi)
state->spi = spi;
id = spi_get_device_id(spi);
state->vrefh_reg = devm_regulator_get(&spi->dev, "vrefh");
if (IS_ERR(state->vrefh_reg))
return dev_err_probe(&spi->dev, PTR_ERR(state->vrefh_reg),
"Vrefh regulator not specified\n");
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vrefh");
if (ret < 0)
return dev_err_probe(&spi->dev, ret,
"failed to get Vrefh voltage\n");
ret = regulator_enable(state->vrefh_reg);
if (ret) {
dev_err(&spi->dev, "Failed to enable vrefh regulator: %d\n",
ret);
return ret;
}
ret = regulator_get_voltage(state->vrefh_reg);
if (ret < 0) {
dev_err(&spi->dev, "Failed to read vrefh regulator: %d\n",
ret);
goto error_disable_vrefh_reg;
}
state->vrefh_mv = ret / 1000;
if (id->driver_data == ID_AD8803) {
state->vrefl_reg = devm_regulator_get(&spi->dev, "vrefl");
if (IS_ERR(state->vrefl_reg)) {
ret = dev_err_probe(&spi->dev, PTR_ERR(state->vrefl_reg),
"Vrefl regulator not specified\n");
goto error_disable_vrefh_reg;
}
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vrefl");
if (ret < 0)
return dev_err_probe(&spi->dev, ret,
"failed to get Vrefl voltage\n");
ret = regulator_enable(state->vrefl_reg);
if (ret) {
dev_err(&spi->dev, "Failed to enable vrefl regulator: %d\n",
ret);
goto error_disable_vrefh_reg;
}
ret = regulator_get_voltage(state->vrefl_reg);
if (ret < 0) {
dev_err(&spi->dev, "Failed to read vrefl regulator: %d\n",
ret);
goto error_disable_vrefl_reg;
}
state->vrefl_mv = ret / 1000;
} else {
state->vrefl_mv = 0;
state->vrefl_reg = NULL;
}
spi_set_drvdata(spi, indio_dev);
indio_dev->info = &ad8801_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ad8801_channels;
indio_dev->num_channels = ARRAY_SIZE(ad8801_channels);
indio_dev->name = id->name;
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to register iio device: %d\n",
ret);
goto error_disable_vrefl_reg;
}
ret = devm_iio_device_register(&spi->dev, indio_dev);
if (ret)
return dev_err_probe(&spi->dev, ret,
"Failed to register iio device\n");
return 0;
error_disable_vrefl_reg:
if (state->vrefl_reg)
regulator_disable(state->vrefl_reg);
error_disable_vrefh_reg:
regulator_disable(state->vrefh_reg);
return ret;
}
static void ad8801_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad8801_state *state = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (state->vrefl_reg)
regulator_disable(state->vrefl_reg);
regulator_disable(state->vrefh_reg);
}
static const struct spi_device_id ad8801_ids[] = {
@ -216,7 +162,6 @@ static struct spi_driver ad8801_driver = {
.name = "ad8801",
},
.probe = ad8801_probe,
.remove = ad8801_remove,
.id_table = ad8801_ids,
};
module_spi_driver(ad8801_driver);

View File

@ -41,13 +41,11 @@ struct ltc2632_chip_info {
* @spi_dev: pointer to the spi_device struct
* @powerdown_cache_mask: used to show current channel powerdown state
* @vref_mv: used reference voltage (internal or external)
* @vref_reg: regulator for the reference voltage
*/
struct ltc2632_state {
struct spi_device *spi_dev;
unsigned int powerdown_cache_mask;
int vref_mv;
struct regulator *vref_reg;
};
enum ltc2632_supported_device_ids {
@ -310,6 +308,7 @@ static int ltc2632_probe(struct spi_device *spi)
struct ltc2632_state *st;
struct iio_dev *indio_dev;
struct ltc2632_chip_info *chip_info;
bool has_external_vref;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@ -318,49 +317,31 @@ static int ltc2632_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->spi_dev = spi;
chip_info = (struct ltc2632_chip_info *)
spi_get_device_id(spi)->driver_data;
st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref");
if (PTR_ERR(st->vref_reg) == -ENODEV) {
/* use internal reference voltage */
st->vref_reg = NULL;
st->vref_mv = chip_info->vref_mv;
ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(&spi->dev, ret,
"Failed to get vref regulator voltage\n");
ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER,
0, 0, 0);
if (ret) {
dev_err(&spi->dev,
"Set internal reference command failed, %d\n",
ret);
return ret;
}
} else if (IS_ERR(st->vref_reg)) {
dev_err(&spi->dev,
"Error getting voltage reference regulator\n");
return PTR_ERR(st->vref_reg);
} else {
/* use external reference voltage */
ret = regulator_enable(st->vref_reg);
if (ret) {
dev_err(&spi->dev,
"enable reference regulator failed, %d\n",
ret);
return ret;
}
st->vref_mv = regulator_get_voltage(st->vref_reg) / 1000;
has_external_vref = ret != -ENODEV;
st->vref_mv = has_external_vref ? ret / 1000 : chip_info->vref_mv;
if (has_external_vref) {
ret = ltc2632_spi_write(spi, LTC2632_CMD_EXTERNAL_REFER,
0, 0, 0);
if (ret) {
dev_err(&spi->dev,
"Set external reference command failed, %d\n",
ret);
return ret;
}
0, 0, 0);
if (ret)
return dev_err_probe(&spi->dev, ret,
"Set external reference command failed\n");
} else {
ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER,
0, 0, 0);
if (ret)
return dev_err_probe(&spi->dev, ret,
"Set internal reference command failed\n");
}
indio_dev->name = fwnode_get_name(dev_fwnode(&spi->dev)) ?: spi_get_device_id(spi)->name;
@ -369,18 +350,7 @@ static int ltc2632_probe(struct spi_device *spi)
indio_dev->channels = chip_info->channels;
indio_dev->num_channels = chip_info->num_channels;
return iio_device_register(indio_dev);
}
static void ltc2632_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ltc2632_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (st->vref_reg)
regulator_disable(st->vref_reg);
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ltc2632_id[] = {
@ -472,7 +442,6 @@ static struct spi_driver ltc2632_driver = {
.of_match_table = ltc2632_of_match,
},
.probe = ltc2632_probe,
.remove = ltc2632_remove,
.id_table = ltc2632_id,
};
module_spi_driver(ltc2632_driver);

View File

@ -842,7 +842,7 @@ static int ltc2688_channel_config(struct ltc2688_state *st)
return 0;
}
static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref)
static int ltc2688_setup(struct ltc2688_state *st, bool has_external_vref)
{
struct device *dev = &st->spi->dev;
struct gpio_desc *gpio;
@ -881,18 +881,13 @@ static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref)
if (ret)
return ret;
if (!vref)
if (!has_external_vref)
return 0;
return regmap_set_bits(st->regmap, LTC2688_CMD_CONFIG,
LTC2688_CONFIG_EXT_REF);
}
static void ltc2688_disable_regulator(void *regulator)
{
regulator_disable(regulator);
}
static bool ltc2688_reg_readable(struct device *dev, unsigned int reg)
{
switch (reg) {
@ -947,8 +942,8 @@ static int ltc2688_probe(struct spi_device *spi)
static const char * const regulators[] = { "vcc", "iovcc" };
struct ltc2688_state *st;
struct iio_dev *indio_dev;
struct regulator *vref_reg;
struct device *dev = &spi->dev;
bool has_external_vref;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
@ -973,34 +968,15 @@ static int ltc2688_probe(struct spi_device *spi)
if (ret)
return dev_err_probe(dev, ret, "Failed to enable regulators\n");
vref_reg = devm_regulator_get_optional(dev, "vref");
if (IS_ERR(vref_reg)) {
if (PTR_ERR(vref_reg) != -ENODEV)
return dev_err_probe(dev, PTR_ERR(vref_reg),
"Failed to get vref regulator");
ret = devm_regulator_get_enable_read_voltage(dev, "vref");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(dev, ret,
"Failed to get vref regulator voltage\n");
vref_reg = NULL;
/* internal reference */
st->vref = 4096;
} else {
ret = regulator_enable(vref_reg);
if (ret)
return dev_err_probe(dev, ret,
"Failed to enable vref regulators\n");
has_external_vref = ret != -ENODEV;
st->vref = has_external_vref ? ret / 1000 : 0;
ret = devm_add_action_or_reset(dev, ltc2688_disable_regulator,
vref_reg);
if (ret)
return ret;
ret = regulator_get_voltage(vref_reg);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to get vref\n");
st->vref = ret / 1000;
}
ret = ltc2688_setup(st, vref_reg);
ret = ltc2688_setup(st, has_external_vref);
if (ret)
return ret;

View File

@ -32,7 +32,6 @@ enum max5821_device_ids {
struct max5821_data {
struct i2c_client *client;
struct regulator *vref_reg;
unsigned short vref_mv;
bool powerdown[MAX5821_MAX_DAC_CHANNELS];
u8 powerdown_mode[MAX5821_MAX_DAC_CHANNELS];
@ -295,11 +294,6 @@ static const struct iio_info max5821_info = {
.write_raw = max5821_write_raw,
};
static void max5821_regulator_disable(void *reg)
{
regulator_disable(reg);
}
static int max5821_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
@ -321,32 +315,10 @@ static int max5821_probe(struct i2c_client *client)
data->powerdown_mode[tmp] = MAX5821_100KOHM_TO_GND;
}
data->vref_reg = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(data->vref_reg))
return dev_err_probe(&client->dev, PTR_ERR(data->vref_reg),
"Failed to get vref regulator\n");
ret = regulator_enable(data->vref_reg);
if (ret) {
dev_err(&client->dev,
"Failed to enable vref regulator: %d\n", ret);
return ret;
}
ret = devm_add_action_or_reset(&client->dev, max5821_regulator_disable,
data->vref_reg);
if (ret) {
dev_err(&client->dev,
"Failed to add action to managed regulator: %d\n", ret);
return ret;
}
ret = regulator_get_voltage(data->vref_reg);
if (ret < 0) {
dev_err(&client->dev,
"Failed to get voltage on regulator: %d\n", ret);
return ret;
}
ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref");
if (ret)
return dev_err_probe(&client->dev, ret,
"Failed to get vref regulator voltage\n");
data->vref_mv = ret / 1000;

View File

@ -379,7 +379,7 @@ static int mcp4725_probe_dt(struct device *dev,
struct mcp4725_platform_data *pdata)
{
/* check if is the vref-supply defined */
pdata->use_vref = device_property_read_bool(dev, "vref-supply");
pdata->use_vref = device_property_present(dev, "vref-supply");
pdata->vref_buffered =
device_property_read_bool(dev, "microchip,vref-buffered");

View File

@ -878,11 +878,32 @@ static const struct iio_chan_spec adis16545_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(17),
};
static const struct iio_chan_spec adis16489_channels[] = {
ADIS16480_GYRO_CHANNEL(X),
ADIS16480_GYRO_CHANNEL(Y),
ADIS16480_GYRO_CHANNEL(Z),
ADIS16480_ACCEL_CHANNEL(X),
ADIS16480_ACCEL_CHANNEL(Y),
ADIS16480_ACCEL_CHANNEL(Z),
ADIS16480_PRESSURE_CHANNEL(),
ADIS16480_TEMP_CHANNEL(),
IIO_CHAN_SOFT_TIMESTAMP(8),
ADIS16480_DELTANG_CHANNEL_NO_SCAN(X),
ADIS16480_DELTANG_CHANNEL_NO_SCAN(Y),
ADIS16480_DELTANG_CHANNEL_NO_SCAN(Z),
ADIS16480_DELTVEL_CHANNEL_NO_SCAN(X),
ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Y),
ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z),
};
enum adis16480_variant {
ADIS16375,
ADIS16480,
ADIS16485,
ADIS16486,
ADIS16487,
ADIS16488,
ADIS16489,
ADIS16490,
ADIS16495_1,
ADIS16495_2,
@ -1038,6 +1059,38 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.filter_freqs = adis16480_def_filter_freqs,
.adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0, 0),
},
[ADIS16486] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
.gyro_max_val = 22500 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
.accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
.accel_max_scale = 18,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(720),
.deltvel_max_val = 200,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
.adis_data = ADIS16480_DATA(16486, &adis16480_timeouts, 0, 0),
},
[ADIS16487] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
.gyro_max_val = 22500 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
.accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
.accel_max_scale = 5,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(720),
.deltvel_max_val = 50,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
.adis_data = ADIS16480_DATA(16487, &adis16485_timeouts, 0, 0),
},
[ADIS16488] = {
.channels = adis16480_channels,
.num_channels = ARRAY_SIZE(adis16480_channels),
@ -1054,6 +1107,22 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.filter_freqs = adis16480_def_filter_freqs,
.adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0, 0),
},
[ADIS16489] = {
.channels = adis16489_channels,
.num_channels = ARRAY_SIZE(adis16489_channels),
.gyro_max_val = 22500 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
.accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
.accel_max_scale = 18,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
.deltang_max_val = IIO_DEGREE_TO_RAD(720),
.deltvel_max_val = 200,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
.adis_data = ADIS16480_DATA(16489, &adis16480_timeouts, 0, 0),
},
[ADIS16490] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
@ -1741,7 +1810,10 @@ static const struct spi_device_id adis16480_ids[] = {
{ "adis16375", ADIS16375 },
{ "adis16480", ADIS16480 },
{ "adis16485", ADIS16485 },
{ "adis16486", ADIS16486 },
{ "adis16487", ADIS16487 },
{ "adis16488", ADIS16488 },
{ "adis16489", ADIS16489 },
{ "adis16490", ADIS16490 },
{ "adis16495-1", ADIS16495_1 },
{ "adis16495-2", ADIS16495_2 },
@ -1763,7 +1835,10 @@ static const struct of_device_id adis16480_of_match[] = {
{ .compatible = "adi,adis16375" },
{ .compatible = "adi,adis16480" },
{ .compatible = "adi,adis16485" },
{ .compatible = "adi,adis16486" },
{ .compatible = "adi,adis16487" },
{ .compatible = "adi,adis16488" },
{ .compatible = "adi,adis16489" },
{ .compatible = "adi,adis16490" },
{ .compatible = "adi,adis16495-1" },
{ .compatible = "adi,adis16495-2" },

View File

@ -277,6 +277,14 @@ static const struct inv_mpu6050_hw hw_info[] = {
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
.startup_time = {INV_ICM20690_GYRO_STARTUP_TIME, INV_ICM20690_ACCEL_STARTUP_TIME},
},
{ .whoami = INV_IAM20380_WHOAMI_VALUE,
.name = "IAM20380",
.reg = &reg_set_6500,
.config = &chip_config_6500,
.fifo_size = 512,
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
.startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_IAM20680_WHOAMI_VALUE,
.name = "IAM20680",
@ -1519,6 +1527,14 @@ static const struct iio_chan_spec inv_mpu6050_channels[] = {
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z),
};
static const struct iio_chan_spec inv_iam20380_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z),
};
static const struct iio_chan_spec inv_mpu6500_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP),
@ -1623,6 +1639,10 @@ static const struct iio_chan_spec inv_mpu9250_channels[] = {
| BIT(INV_MPU9X50_SCAN_MAGN_Y) \
| BIT(INV_MPU9X50_SCAN_MAGN_Z))
static const unsigned long inv_iam20380_scan_masks[] = {
INV_MPU6050_SCAN_MASK_3AXIS_GYRO,
};
static const unsigned long inv_mpu9x50_scan_masks[] = {
/* 3-axis accel */
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL,
@ -2026,6 +2046,11 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
break;
case INV_IAM20380:
indio_dev->channels = inv_iam20380_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_iam20380_channels);
indio_dev->available_scan_masks = inv_iam20380_scan_masks;
break;
case INV_ICM20600:
case INV_ICM20602:
indio_dev->channels = inv_mpu6500_channels;

View File

@ -34,6 +34,7 @@ static bool inv_mpu_i2c_aux_bus(struct device *dev)
case INV_ICM20689:
case INV_ICM20600:
case INV_ICM20602:
case INV_IAM20380:
case INV_IAM20680:
/* no i2c auxiliary bus on the chip */
return false;
@ -187,6 +188,7 @@ static const struct i2c_device_id inv_mpu_id[] = {
{"icm20600", INV_ICM20600},
{"icm20602", INV_ICM20602},
{"icm20690", INV_ICM20690},
{"iam20380", INV_IAM20380},
{"iam20680", INV_IAM20680},
{"iam20680hp", INV_IAM20680HP},
{"iam20680ht", INV_IAM20680HT},
@ -252,6 +254,10 @@ static const struct of_device_id inv_of_match[] = {
.compatible = "invensense,icm20690",
.data = (void *)INV_ICM20690
},
{
.compatible = "invensense,iam20380",
.data = (void *)INV_IAM20380
},
{
.compatible = "invensense,iam20680",
.data = (void *)INV_IAM20680

View File

@ -84,6 +84,7 @@ enum inv_devices {
INV_ICM20600,
INV_ICM20602,
INV_ICM20690,
INV_IAM20380,
INV_IAM20680,
INV_IAM20680HP,
INV_IAM20680HT,
@ -425,6 +426,7 @@ struct inv_mpu6050_state {
#define INV_ICM20600_WHOAMI_VALUE 0x11
#define INV_ICM20602_WHOAMI_VALUE 0x12
#define INV_ICM20690_WHOAMI_VALUE 0x20
#define INV_IAM20380_WHOAMI_VALUE 0xB5
#define INV_IAM20680_WHOAMI_VALUE 0xA9
#define INV_IAM20680HP_WHOAMI_VALUE 0xF8
#define INV_IAM20680HT_WHOAMI_VALUE 0xFA

View File

@ -79,6 +79,7 @@ static const struct spi_device_id inv_mpu_id[] = {
{"icm20600", INV_ICM20600},
{"icm20602", INV_ICM20602},
{"icm20690", INV_ICM20690},
{"iam20380", INV_IAM20380},
{"iam20680", INV_IAM20680},
{"iam20680hp", INV_IAM20680HP},
{"iam20680ht", INV_IAM20680HT},
@ -140,6 +141,10 @@ static const struct of_device_id inv_of_match[] = {
.compatible = "invensense,icm20690",
.data = (void *)INV_ICM20690
},
{
.compatible = "invensense,iam20380",
.data = (void *)INV_IAM20380
},
{
.compatible = "invensense,iam20680",
.data = (void *)INV_IAM20680

View File

@ -6,9 +6,6 @@ config IIO_ST_LSM6DSX
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select IIO_KFIFO_BUF
select IIO_ST_LSM6DSX_I2C if (I2C)
select IIO_ST_LSM6DSX_SPI if (SPI_MASTER)
select IIO_ST_LSM6DSX_I3C if (I3C)
help
Say yes here to build support for STMicroelectronics LSM6DSx imu
sensor.
@ -42,16 +39,19 @@ config IIO_ST_LSM6DSX
will be called st_lsm6dsx.
config IIO_ST_LSM6DSX_I2C
tristate
depends on IIO_ST_LSM6DSX
tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors I2C Interface"
depends on I2C && IIO_ST_LSM6DSX
default I2C && IIO_ST_LSM6DSX
select REGMAP_I2C
config IIO_ST_LSM6DSX_SPI
tristate
depends on IIO_ST_LSM6DSX
tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors SPI Interface"
depends on SPI_MASTER && IIO_ST_LSM6DSX
default SPI_MASTER && IIO_ST_LSM6DSX
select REGMAP_SPI
config IIO_ST_LSM6DSX_I3C
tristate
depends on IIO_ST_LSM6DSX
tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors I3C Interface"
depends on I3C && IIO_ST_LSM6DSX
default I3C && IIO_ST_LSM6DSX
select REGMAP_I3C

View File

@ -9,7 +9,6 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/i3c/device.h>
#include <linux/i3c/master.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@ -30,15 +29,16 @@ static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev)
};
const struct i3c_device_id *id = i3c_device_match_id(i3cdev,
st_lsm6dsx_i3c_ids);
struct device *dev = i3cdev_to_dev(i3cdev);
struct regmap *regmap;
regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&i3cdev->dev, "Failed to register i3c regmap %ld\n", PTR_ERR(regmap));
dev_err(dev, "Failed to register i3c regmap %ld\n", PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return st_lsm6dsx_probe(&i3cdev->dev, 0, (uintptr_t)id->data, regmap);
return st_lsm6dsx_probe(dev, 0, (uintptr_t)id->data, regmap);
}
static struct i3c_driver st_lsm6dsx_driver = {

View File

@ -7,6 +7,7 @@
#include <linux/err.h>
#include <linux/export.h>
#include <linux/minmax.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/slab.h>
@ -989,6 +990,11 @@ ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
{
const struct iio_chan_spec_ext_info *ext_info;
if (!buf || offset_in_page(buf)) {
pr_err("iio: invalid ext_info read buffer\n");
return -EINVAL;
}
ext_info = iio_lookup_ext_info(chan, attr);
if (!ext_info)
return -EINVAL;
@ -1014,6 +1020,11 @@ EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf)
{
if (!buf || offset_in_page(buf)) {
pr_err("iio: invalid label read buffer\n");
return -EINVAL;
}
return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf);
}
EXPORT_SYMBOL_GPL(iio_read_channel_label);

View File

@ -329,22 +329,6 @@ config JSA1212
To compile this driver as a module, choose M here:
the module will be called jsa1212.
config ROHM_BU27008
tristate "ROHM BU27008 color (RGB+C/IR) sensor"
depends on I2C
select REGMAP_I2C
select IIO_GTS_HELPER
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Enable support for the ROHM BU27008 color sensor.
The ROHM BU27008 is a sensor with 5 photodiodes (red, green,
blue, clear and IR) with four configurable channels. Red and
green being always available and two out of the rest three
(blue, clear, IR) can be selected to be simultaneously measured.
Typical application is adjusting LCD backlight of TVs,
mobile phones and tablet PCs.
config ROHM_BU27034
tristate "ROHM BU27034 ambient light sensor"
depends on I2C
@ -683,6 +667,8 @@ config VEML3235
config VEML6030
tristate "VEML6030 and VEML6035 ambient light sensors"
select REGMAP_I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
depends on I2C
help
Say Y here if you want to build a driver for the Vishay VEML6030

View File

@ -43,7 +43,6 @@ obj-$(CONFIG_NOA1305) += noa1305.o
obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_OPT4001) += opt4001.o
obj-$(CONFIG_PA12203001) += pa12203001.o
obj-$(CONFIG_ROHM_BU27008) += rohm-bu27008.o
obj-$(CONFIG_ROHM_BU27034) += rohm-bu27034.o
obj-$(CONFIG_RPR0521) += rpr0521.o
obj-$(CONFIG_SI1133) += si1133.o

View File

@ -89,6 +89,15 @@ static int cm3232_reg_init(struct cm3232_chip *chip)
chip->als_info = &cm3232_als_info_default;
/* Disable and reset device */
chip->regs_cmd = CM3232_CMD_ALS_DISABLE | CM3232_CMD_ALS_RESET;
ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
chip->regs_cmd);
if (ret < 0) {
dev_err(&chip->client->dev, "Error writing reg_cmd\n");
return ret;
}
/* Identify device */
ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ID);
if (ret < 0) {
@ -99,15 +108,6 @@ static int cm3232_reg_init(struct cm3232_chip *chip)
if ((ret & 0xFF) != chip->als_info->hw_id)
return -ENODEV;
/* Disable and reset device */
chip->regs_cmd = CM3232_CMD_ALS_DISABLE | CM3232_CMD_ALS_RESET;
ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
chip->regs_cmd);
if (ret < 0) {
dev_err(&chip->client->dev, "Error writing reg_cmd\n");
return ret;
}
/* Register default value */
chip->regs_cmd = chip->als_info->regs_cmd_default;

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/module.h>
@ -395,30 +396,26 @@ static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us)
int numg = ARRAY_SIZE(gains);
int ret, int_time_old, i;
mutex_lock(&data->mutex);
guard(mutex)(&data->mutex);
ret = bu27034_get_int_time(data);
if (ret < 0)
goto unlock_out;
return ret;
int_time_old = ret;
if (!iio_gts_valid_time(&data->gts, time_us)) {
dev_err(data->dev, "Unsupported integration time %u\n",
time_us);
ret = -EINVAL;
goto unlock_out;
return -EINVAL;
}
if (time_us == int_time_old) {
ret = 0;
goto unlock_out;
}
if (time_us == int_time_old)
return 0;
for (i = 0; i < numg; i++) {
ret = bu27034_get_gain(data, gains[i].chan, &gains[i].old_gain);
if (ret)
goto unlock_out;
return 0;
ret = iio_gts_find_new_gain_by_old_gain_time(&data->gts,
gains[i].old_gain,
@ -434,7 +431,7 @@ static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us)
gains[i].chan, time_us, scale1, scale2);
if (gains[i].new_gain < 0)
goto unlock_out;
return ret;
/*
* If caller requests for integration time change and we
@ -455,7 +452,7 @@ static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us)
"Total gain increase. Risk of saturation");
ret = iio_gts_get_min_gain(&data->gts);
if (ret < 0)
goto unlock_out;
return ret;
}
dev_dbg(data->dev, "chan %u scale changed\n",
gains[i].chan);
@ -468,15 +465,10 @@ static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us)
for (i = 0; i < numg; i++) {
ret = bu27034_set_gain(data, gains[i].chan, gains[i].new_gain);
if (ret)
goto unlock_out;
return ret;
}
ret = bu27034_set_int_time(data, time_us);
unlock_out:
mutex_unlock(&data->mutex);
return ret;
return bu27034_set_int_time(data, time_us);
}
static int bu27034_set_scale(struct bu27034_data *data, int chan,
@ -492,10 +484,10 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan,
return -EINVAL;
}
mutex_lock(&data->mutex);
guard(mutex)(&data->mutex);
ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL1, &time_sel);
if (ret)
goto unlock_out;
return ret;
ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel,
val, val2, &gain_sel);
@ -518,7 +510,7 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan,
ret = bu27034_get_gain(data, gain.chan, &gain.old_gain);
if (ret)
goto unlock_out;
return ret;
/*
* Iterate through all the times to see if we find one which
@ -551,26 +543,20 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan,
if (!found) {
dev_dbg(data->dev,
"Can't set scale maintaining other channel\n");
ret = -EINVAL;
goto unlock_out;
return -EINVAL;
}
ret = bu27034_set_gain(data, gain.chan, gain.new_gain);
if (ret)
goto unlock_out;
return ret;
ret = regmap_update_bits(data->regmap, BU27034_REG_MODE_CONTROL1,
BU27034_MASK_MEAS_MODE, new_time_sel);
if (ret)
goto unlock_out;
return ret;
}
ret = bu27034_write_gain_sel(data, chan, gain_sel);
unlock_out:
mutex_unlock(&data->mutex);
return ret;
return bu27034_write_gain_sel(data, chan, gain_sel);
}
/*
@ -1221,42 +1207,33 @@ static int bu27034_buffer_enable(struct iio_dev *idev)
struct task_struct *task;
int ret;
mutex_lock(&data->mutex);
guard(mutex)(&data->mutex);
ret = bu27034_meas_set(data, true);
if (ret)
goto unlock_out;
return ret;
task = kthread_run(bu27034_buffer_thread, idev,
"bu27034-buffering-%u",
iio_device_id(idev));
if (IS_ERR(task)) {
ret = PTR_ERR(task);
goto unlock_out;
}
if (IS_ERR(task))
return PTR_ERR(task);
data->task = task;
unlock_out:
mutex_unlock(&data->mutex);
return ret;
return 0;
}
static int bu27034_buffer_disable(struct iio_dev *idev)
{
struct bu27034_data *data = iio_priv(idev);
int ret;
mutex_lock(&data->mutex);
guard(mutex)(&data->mutex);
if (data->task) {
kthread_stop(data->task);
data->task = NULL;
}
ret = bu27034_meas_set(data, false);
mutex_unlock(&data->mutex);
return ret;
return bu27034_meas_set(data, false);
}
static const struct iio_buffer_setup_ops bu27034_buffer_ops = {

View File

@ -28,6 +28,8 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
/* Device registers */
#define VEML6030_REG_ALS_CONF 0x00
@ -37,6 +39,7 @@
#define VEML6030_REG_ALS_DATA 0x04
#define VEML6030_REG_WH_DATA 0x05
#define VEML6030_REG_ALS_INT 0x06
#define VEML6030_REG_DATA(ch) (VEML6030_REG_ALS_DATA + (ch))
/* Bit masks for specific functionality */
#define VEML6030_ALS_IT GENMASK(9, 6)
@ -56,6 +59,12 @@
#define VEML6035_INT_CHAN BIT(3)
#define VEML6035_CHAN_EN BIT(2)
enum veml6030_scan {
VEML6030_SCAN_ALS,
VEML6030_SCAN_WH,
VEML6030_SCAN_TIMESTAMP,
};
struct veml603x_chip {
const char *name;
const int(*scale_vals)[][2];
@ -242,6 +251,13 @@ static const struct iio_chan_spec veml6030_channels[] = {
BIT(IIO_CHAN_INFO_SCALE),
.event_spec = veml6030_event_spec,
.num_event_specs = ARRAY_SIZE(veml6030_event_spec),
.scan_index = VEML6030_SCAN_ALS,
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
},
{
.type = IIO_INTENSITY,
@ -253,7 +269,15 @@ static const struct iio_chan_spec veml6030_channels[] = {
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) |
BIT(IIO_CHAN_INFO_SCALE),
.scan_index = VEML6030_SCAN_WH,
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
},
IIO_CHAN_SOFT_TIMESTAMP(VEML6030_SCAN_TIMESTAMP),
};
static const struct iio_chan_spec veml7700_channels[] = {
@ -266,6 +290,13 @@ static const struct iio_chan_spec veml7700_channels[] = {
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) |
BIT(IIO_CHAN_INFO_SCALE),
.scan_index = VEML6030_SCAN_ALS,
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
},
{
.type = IIO_INTENSITY,
@ -277,7 +308,15 @@ static const struct iio_chan_spec veml7700_channels[] = {
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) |
BIT(IIO_CHAN_INFO_SCALE),
.scan_index = VEML6030_SCAN_WH,
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
},
IIO_CHAN_SOFT_TIMESTAMP(VEML6030_SCAN_TIMESTAMP),
};
static const struct regmap_config veml6030_regmap_config = {
@ -889,6 +928,37 @@ static irqreturn_t veml6030_event_handler(int irq, void *private)
return IRQ_HANDLED;
}
static irqreturn_t veml6030_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *iio = pf->indio_dev;
struct veml6030_data *data = iio_priv(iio);
unsigned int reg;
int ch, ret, i = 0;
struct {
u16 chans[2];
aligned_s64 timestamp;
} scan;
memset(&scan, 0, sizeof(scan));
iio_for_each_active_channel(iio, ch) {
ret = regmap_read(data->regmap, VEML6030_REG_DATA(ch),
&reg);
if (ret)
goto done;
scan.chans[i++] = reg;
}
iio_push_to_buffers_with_timestamp(iio, &scan, pf->timestamp);
done:
iio_trigger_notify_done(iio->trig);
return IRQ_HANDLED;
}
static int veml6030_set_info(struct iio_dev *indio_dev)
{
struct veml6030_data *data = iio_priv(indio_dev);
@ -1077,6 +1147,12 @@ static int veml6030_probe(struct i2c_client *client)
if (ret < 0)
return ret;
ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
veml6030_trigger_handler, NULL);
if (ret)
return dev_err_probe(&client->dev, ret,
"Failed to register triggered buffer");
return devm_iio_device_register(&client->dev, indio_dev);
}

View File

@ -1002,7 +1002,7 @@ static int bmp280_preinit(struct bmp280_data *data)
* after resetting, the device uses the complete power-on sequence so
* it needs to wait for the defined start-up time.
*/
fsleep(data->start_up_time);
fsleep(data->start_up_time_us);
ret = regmap_read(data->regmap, BMP280_REG_STATUS, &reg);
if (ret)
@ -1161,7 +1161,7 @@ const struct bmp280_chip_info bmp280_chip_info = {
.chip_id = bmp280_chip_ids,
.num_chip_id = ARRAY_SIZE(bmp280_chip_ids),
.regmap_config = &bmp280_regmap_config,
.start_up_time = 2000,
.start_up_time_us = 2000,
.channels = bmp280_channels,
.num_channels = ARRAY_SIZE(bmp280_channels),
.avail_scan_masks = bmp280_avail_scan_masks,
@ -1347,7 +1347,7 @@ const struct bmp280_chip_info bme280_chip_info = {
.chip_id = bme280_chip_ids,
.num_chip_id = ARRAY_SIZE(bme280_chip_ids),
.regmap_config = &bme280_regmap_config,
.start_up_time = 2000,
.start_up_time_us = 2000,
.channels = bme280_channels,
.num_channels = ARRAY_SIZE(bme280_channels),
.avail_scan_masks = bme280_avail_scan_masks,
@ -1414,7 +1414,7 @@ static int bmp380_cmd(struct bmp280_data *data, u8 cmd)
return ret;
}
/* Wait for 2ms for command to be processed */
usleep_range(data->start_up_time, data->start_up_time + 100);
fsleep(data->start_up_time_us);
/* Check for command processing error */
ret = regmap_read(data->regmap, BMP380_REG_ERROR, &reg);
if (ret) {
@ -1806,7 +1806,7 @@ static int bmp380_chip_config(struct bmp280_data *data)
* formula in datasheet section 3.9.2 with an offset of ~+15%
* as it seen as well in table 3.9.1.
*/
msleep(150);
fsleep(150 * USEC_PER_MSEC);
/* Check config error flag */
ret = regmap_read(data->regmap, BMP380_REG_ERROR, &tmp);
@ -1957,7 +1957,7 @@ const struct bmp280_chip_info bmp380_chip_info = {
.num_chip_id = ARRAY_SIZE(bmp380_chip_ids),
.regmap_config = &bmp380_regmap_config,
.spi_read_extra_byte = true,
.start_up_time = 2000,
.start_up_time_us = 2000,
.channels = bmp380_channels,
.num_channels = ARRAY_SIZE(bmp380_channels),
.avail_scan_masks = bmp280_avail_scan_masks,
@ -2006,7 +2006,8 @@ static int bmp580_soft_reset(struct bmp280_data *data)
dev_err(data->dev, "failed to send reset command to device\n");
return ret;
}
usleep_range(2000, 2500);
/* From datasheet's table 4: electrical characteristics */
fsleep(2000);
/* Dummy read of chip_id */
ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, &reg);
@ -2208,7 +2209,7 @@ static int bmp580_nvmem_read_impl(void *priv, unsigned int offset, void *val,
goto exit;
}
/* Wait standby transition time */
usleep_range(2500, 3000);
fsleep(2500);
while (bytes >= sizeof(*dst)) {
addr = bmp580_nvmem_addrs[offset / sizeof(*dst)];
@ -2274,7 +2275,7 @@ static int bmp580_nvmem_write_impl(void *priv, unsigned int offset, void *val,
goto exit;
}
/* Wait standby transition time */
usleep_range(2500, 3000);
fsleep(2500);
while (bytes >= sizeof(*buf)) {
addr = bmp580_nvmem_addrs[offset / sizeof(*buf)];
@ -2458,7 +2459,7 @@ static int bmp580_chip_config(struct bmp280_data *data)
return ret;
}
/* From datasheet's table 4: electrical characteristics */
usleep_range(2500, 3000);
fsleep(2500);
/* Set default DSP mode settings */
reg_val = FIELD_PREP(BMP580_DSP_COMP_MASK, BMP580_DSP_PRESS_TEMP_COMP_EN) |
@ -2649,7 +2650,7 @@ const struct bmp280_chip_info bmp580_chip_info = {
.chip_id = bmp580_chip_ids,
.num_chip_id = ARRAY_SIZE(bmp580_chip_ids),
.regmap_config = &bmp580_regmap_config,
.start_up_time = 2000,
.start_up_time_us = 2000,
.channels = bmp580_channels,
.num_channels = ARRAY_SIZE(bmp580_channels),
.avail_scan_masks = bmp280_avail_scan_masks,
@ -2720,7 +2721,7 @@ static int bmp180_wait_for_eoc(struct bmp280_data *data, u8 ctrl_meas)
delay_us =
conversion_time_max[data->oversampling_press];
usleep_range(delay_us, delay_us + 1000);
fsleep(delay_us);
}
ret = regmap_read(data->regmap, BMP280_REG_CTRL_MEAS, &ctrl);
@ -2988,7 +2989,7 @@ const struct bmp280_chip_info bmp180_chip_info = {
.chip_id = bmp180_chip_ids,
.num_chip_id = ARRAY_SIZE(bmp180_chip_ids),
.regmap_config = &bmp180_regmap_config,
.start_up_time = 2000,
.start_up_time_us = 2000,
.channels = bmp280_channels,
.num_channels = ARRAY_SIZE(bmp280_channels),
.avail_scan_masks = bmp280_avail_scan_masks,
@ -3066,7 +3067,7 @@ const struct bmp280_chip_info bmp085_chip_info = {
.chip_id = bmp180_chip_ids,
.num_chip_id = ARRAY_SIZE(bmp180_chip_ids),
.regmap_config = &bmp180_regmap_config,
.start_up_time = 2000,
.start_up_time_us = 2000,
.channels = bmp280_channels,
.num_channels = ARRAY_SIZE(bmp280_channels),
.avail_scan_masks = bmp280_avail_scan_masks,
@ -3175,7 +3176,7 @@ int bmp280_common_probe(struct device *dev,
data->oversampling_temp = chip_info->oversampling_temp_default;
data->iir_filter_coeff = chip_info->iir_filter_coeff_default;
data->sampling_freq = chip_info->sampling_freq_default;
data->start_up_time = chip_info->start_up_time;
data->start_up_time_us = chip_info->start_up_time_us;
/* Bring up regulators */
regulator_bulk_set_supply_names(data->supplies,
@ -3201,7 +3202,7 @@ int bmp280_common_probe(struct device *dev,
return ret;
/* Wait to make sure we started up properly */
usleep_range(data->start_up_time, data->start_up_time + 100);
fsleep(data->start_up_time_us);
/* Bring chip out of reset if there is an assigned GPIO line */
gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
@ -3287,7 +3288,7 @@ int bmp280_common_probe(struct device *dev,
* Set autosuspend to two orders of magnitude larger than the
* start-up time.
*/
pm_runtime_set_autosuspend_delay(dev, data->start_up_time / 10);
pm_runtime_set_autosuspend_delay(dev, data->start_up_time_us / 10);
pm_runtime_use_autosuspend(dev);
pm_runtime_put(dev);
@ -3306,7 +3307,7 @@ static int bmp280_runtime_suspend(struct device *dev)
data->chip_info->set_mode(data, BMP280_SLEEP);
fsleep(data->start_up_time);
fsleep(data->start_up_time_us);
return regulator_bulk_disable(BMP280_NUM_SUPPLIES, data->supplies);
}
@ -3320,7 +3321,7 @@ static int bmp280_runtime_resume(struct device *dev)
if (ret)
return ret;
usleep_range(data->start_up_time, data->start_up_time + 100);
fsleep(data->start_up_time_us);
ret = data->chip_info->chip_config(data);
if (ret)

View File

@ -434,7 +434,7 @@ struct bmp280_data {
struct bmp380_calib bmp380;
} calib;
struct regulator_bulk_data supplies[BMP280_NUM_SUPPLIES];
unsigned int start_up_time; /* in microseconds */
unsigned int start_up_time_us;
/* log of base 2 of oversampling rate */
u8 oversampling_press;
@ -470,8 +470,8 @@ struct bmp280_data {
/* Sensor data buffer */
u8 buf[BME280_BURST_READ_BYTES];
/* Calibration data buffers */
__le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS / 2];
__be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT / 2];
__le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS / sizeof(__le16)];
__be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT / sizeof(__be16)];
u8 bme280_humid_cal_buf[BME280_CONTIGUOUS_CALIB_REGS];
u8 bmp380_cal_buf[BMP380_CALIB_REG_COUNT];
/* Miscellaneous, endianness-aware data buffers */
@ -490,7 +490,7 @@ struct bmp280_chip_info {
const struct iio_chan_spec *channels;
int num_channels;
unsigned int start_up_time;
unsigned int start_up_time_us;
const unsigned long *avail_scan_masks;
const int *oversampling_temp_avail;

View File

@ -8,6 +8,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/module.h>
@ -263,14 +264,14 @@ static int bm1390_read_data(struct bm1390_data *data,
{
int ret, warn;
mutex_lock(&data->mutex);
guard(mutex)(&data->mutex);
/*
* We use 'continuous mode' even for raw read because according to the
* data-sheet an one-shot mode can't be used with IIR filter.
*/
ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS);
if (ret)
goto unlock_out;
return ret;
switch (chan->type) {
case IIO_PRESSURE:
@ -287,10 +288,8 @@ static int bm1390_read_data(struct bm1390_data *data,
warn = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP);
if (warn)
dev_warn(data->dev, "Failed to stop measurement (%d)\n", warn);
unlock_out:
mutex_unlock(&data->mutex);
return ret;
return 0;
}
static int bm1390_read_raw(struct iio_dev *idev,
@ -543,38 +542,33 @@ static int bm1390_fifo_enable(struct iio_dev *idev)
if (data->irq <= 0)
return -EINVAL;
mutex_lock(&data->mutex);
if (data->trigger_enabled) {
ret = -EBUSY;
goto unlock_out;
}
guard(mutex)(&data->mutex);
if (data->trigger_enabled)
return -EBUSY;
/* Update watermark to HW */
ret = bm1390_fifo_set_wmi(data);
if (ret)
goto unlock_out;
return ret;
/* Enable WMI_IRQ */
ret = regmap_set_bits(data->regmap, BM1390_REG_MODE_CTRL,
BM1390_MASK_WMI_EN);
if (ret)
goto unlock_out;
return ret;
/* Enable FIFO */
ret = regmap_set_bits(data->regmap, BM1390_REG_FIFO_CTRL,
BM1390_MASK_FIFO_EN);
if (ret)
goto unlock_out;
return ret;
data->state = BM1390_STATE_FIFO;
data->old_timestamp = iio_get_time_ns(idev);
ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS);
unlock_out:
mutex_unlock(&data->mutex);
return ret;
return bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS);
}
static int bm1390_fifo_disable(struct iio_dev *idev)
@ -584,27 +578,22 @@ static int bm1390_fifo_disable(struct iio_dev *idev)
msleep(1);
mutex_lock(&data->mutex);
guard(mutex)(&data->mutex);
ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP);
if (ret)
goto unlock_out;
return ret;
/* Disable FIFO */
ret = regmap_clear_bits(data->regmap, BM1390_REG_FIFO_CTRL,
BM1390_MASK_FIFO_EN);
if (ret)
goto unlock_out;
return ret;
data->state = BM1390_STATE_SAMPLE;
/* Disable WMI_IRQ */
ret = regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL,
return regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL,
BM1390_MASK_WMI_EN);
unlock_out:
mutex_unlock(&data->mutex);
return ret;
}
static int bm1390_buffer_postenable(struct iio_dev *idev)
@ -688,25 +677,24 @@ static irqreturn_t bm1390_irq_thread_handler(int irq, void *private)
{
struct iio_dev *idev = private;
struct bm1390_data *data = iio_priv(idev);
int ret = IRQ_NONE;
mutex_lock(&data->mutex);
guard(mutex)(&data->mutex);
if (data->trigger_enabled) {
iio_trigger_poll_nested(data->trig);
ret = IRQ_HANDLED;
} else if (data->state == BM1390_STATE_FIFO) {
return IRQ_HANDLED;
}
if (data->state == BM1390_STATE_FIFO) {
int ok;
ok = __bm1390_fifo_flush(idev, BM1390_FIFO_LENGTH,
data->timestamp);
if (ok > 0)
ret = IRQ_HANDLED;
return IRQ_HANDLED;
}
mutex_unlock(&data->mutex);
return ret;
return IRQ_NONE;
}
static int bm1390_set_drdy_irq(struct bm1390_data *data, bool en)
@ -722,17 +710,16 @@ static int bm1390_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct bm1390_data *data = iio_trigger_get_drvdata(trig);
int ret = 0;
int ret;
mutex_lock(&data->mutex);
guard(mutex)(&data->mutex);
if (data->trigger_enabled == state)
goto unlock_out;
return 0;
if (data->state == BM1390_STATE_FIFO) {
dev_warn(data->dev, "Can't set trigger when FIFO enabled\n");
ret = -EBUSY;
goto unlock_out;
return -EBUSY;
}
data->trigger_enabled = state;
@ -740,13 +727,13 @@ static int bm1390_trigger_set_state(struct iio_trigger *trig,
if (state) {
ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS);
if (ret)
goto unlock_out;
return ret;
} else {
int dummy;
ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP);
if (ret)
goto unlock_out;
return ret;
/*
* We need to read the status register in order to ACK the
@ -758,12 +745,7 @@ static int bm1390_trigger_set_state(struct iio_trigger *trig,
dev_warn(data->dev, "status read failed\n");
}
ret = bm1390_set_drdy_irq(data, state);
unlock_out:
mutex_unlock(&data->mutex);
return ret;
return bm1390_set_drdy_irq(data, state);
}
static const struct iio_trigger_ops bm1390_trigger_ops = {

View File

@ -433,7 +433,7 @@ static int aw96103_write_event_config(struct iio_dev *indio_dev,
state ? BIT(chan->channel) : 0);
}
static struct iio_info iio_info = {
static const struct iio_info iio_info = {
.read_raw = aw96103_read_raw,
.read_event_value = aw96103_read_event_val,
.write_event_value = aw96103_write_event_val,

View File

@ -119,7 +119,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
unsigned int frequency)
{
unsigned long long prd, div;
int prescaler = 0;
int prescaler = 0, ret;
u32 ccer;
/* Period and prescaler values depends of clock rate */
@ -150,10 +150,12 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
if (ccer & TIM_CCER_CCXE)
return -EBUSY;
mutex_lock(&priv->lock);
guard(mutex)(&priv->lock);
if (!priv->enabled) {
priv->enabled = true;
clk_enable(priv->clk);
ret = clk_enable(priv->clk);
if (ret)
return ret;
}
regmap_write(priv->regmap, TIM_PSC, prescaler);
@ -173,7 +175,6 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
/* Enable controller */
regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN);
mutex_unlock(&priv->lock);
return 0;
}
@ -307,7 +308,7 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
struct iio_trigger *trig = to_iio_trigger(dev);
u32 mask, shift, master_mode_max;
int i;
int i, ret;
if (stm32_timer_is_trgo2_name(trig->name)) {
mask = TIM_CR2_MMS2;
@ -322,15 +323,16 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
for (i = 0; i <= master_mode_max; i++) {
if (!strncmp(master_mode_table[i], buf,
strlen(master_mode_table[i]))) {
mutex_lock(&priv->lock);
guard(mutex)(&priv->lock);
if (!priv->enabled) {
/* Clock should be enabled first */
priv->enabled = true;
clk_enable(priv->clk);
ret = clk_enable(priv->clk);
if (ret)
return ret;
}
regmap_update_bits(priv->regmap, TIM_CR2, mask,
i << shift);
mutex_unlock(&priv->lock);
return len;
}
}
@ -482,6 +484,7 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
int val, int val2, long mask)
{
struct stm32_timer_trigger *priv = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
@ -491,12 +494,14 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
/* fixed scale */
return -EINVAL;
case IIO_CHAN_INFO_ENABLE:
mutex_lock(&priv->lock);
case IIO_CHAN_INFO_ENABLE: {
guard(mutex)(&priv->lock);
if (val) {
if (!priv->enabled) {
priv->enabled = true;
clk_enable(priv->clk);
ret = clk_enable(priv->clk);
if (ret)
return ret;
}
regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN);
} else {
@ -506,11 +511,12 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
clk_disable(priv->clk);
}
}
mutex_unlock(&priv->lock);
return 0;
}
return -EINVAL;
default:
return -EINVAL;
}
}
static int stm32_counter_validate_trigger(struct iio_dev *indio_dev,
@ -602,6 +608,7 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
{
struct stm32_timer_trigger *priv = iio_priv(indio_dev);
int sms = stm32_enable_mode2sms(mode);
int ret;
if (sms < 0)
return sms;
@ -609,12 +616,15 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
* Triggered mode sets CEN bit automatically by hardware. So, first
* enable counter clock, so it can use it. Keeps it in sync with CEN.
*/
mutex_lock(&priv->lock);
if (sms == 6 && !priv->enabled) {
clk_enable(priv->clk);
priv->enabled = true;
scoped_guard(mutex, &priv->lock) {
if (sms == 6 && !priv->enabled) {
ret = clk_enable(priv->clk);
if (ret)
return ret;
priv->enabled = true;
}
}
mutex_unlock(&priv->lock);
regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms);

View File

@ -29,6 +29,7 @@ struct ad_sd_calib_data {
struct ad_sigma_delta;
struct device;
struct gpio_desc;
struct iio_dev;
/**
@ -53,6 +54,7 @@ struct iio_dev;
* @irq_flags: flags for the interrupt used by the triggered buffer
* @num_slots: Number of sequencer slots
* @irq_line: IRQ for reading conversions. If 0, spi->irq will be used
* @num_resetclks: Number of SPI clk cycles with MOSI=1 to reset the chip.
*/
struct ad_sigma_delta_info {
int (*set_channel)(struct ad_sigma_delta *, unsigned int channel);
@ -69,6 +71,7 @@ struct ad_sigma_delta_info {
unsigned long irq_flags;
unsigned int num_slots;
int irq_line;
unsigned int num_resetclks;
};
/**
@ -85,6 +88,7 @@ struct ad_sigma_delta {
/* private: */
struct completion completion;
spinlock_t irq_lock; /* protects .irq_dis and irq en/disable state */
bool irq_dis;
bool bus_locked;
@ -96,7 +100,8 @@ struct ad_sigma_delta {
unsigned int active_slots;
unsigned int current_slot;
unsigned int num_slots;
int irq_line;
struct gpio_desc *rdy_gpiod;
int irq_line;
bool status_appended;
/* map slots to channels in order to know what to expect from devices */
unsigned int *slots;
@ -178,8 +183,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
unsigned int size, unsigned int *val);
int ad_sd_reset(struct ad_sigma_delta *sigma_delta,
unsigned int reset_length);
int ad_sd_reset(struct ad_sigma_delta *sigma_delta);
int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val);

View File

@ -418,7 +418,7 @@ unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan);
* @chan: The channel being queried.
* @attr: The ext_info attribute to read.
* @buf: Where to store the attribute value. Assumed to hold
* at least PAGE_SIZE bytes.
* at least PAGE_SIZE bytes and to be aligned at PAGE_SIZE.
*
* Returns the number of bytes written to buf (perhaps w/o zero termination;
* it need not even be a string), or an error code.
@ -445,7 +445,7 @@ ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
* iio_read_channel_label() - read label for a given channel
* @chan: The channel being queried.
* @buf: Where to store the attribute value. Assumed to hold
* at least PAGE_SIZE bytes.
* at least PAGE_SIZE bytes and to be aligned at PAGE_SIZE.
*
* Returns the number of bytes written to buf, or an error code.
*/

View File

@ -28,7 +28,7 @@
* @groupcounter: index of next attribute group
* @legacy_scan_el_group: attribute group for legacy scan elements attribute group
* @legacy_buffer_group: attribute group for legacy buffer attributes group
* @bounce_buffer: for devices that call iio_push_to_buffers_with_timestamp_unaligned()
* @bounce_buffer: for devices that call iio_push_to_buffers_with_ts_unaligned()
* @bounce_buffer_size: size of currently allocate bounce buffer
* @scan_index_timestamp: cache of the index to the timestamp
* @clock_id: timestamping clock posix identifier

View File

@ -99,7 +99,6 @@ struct adis_data {
* @spi: Reference to SPI device which owns this ADIS IIO device
* @trig: IIO trigger object data
* @data: ADIS chip variant specific data
* @burst: ADIS burst transfer information
* @burst_extra_len: Burst extra length. Should only be used by devices that can
* dynamically change their burst mode length.
* @state_lock: Lock used by the device to protect state