提交 196db6bb 编写于 作者: G Greg Kroah-Hartman

Merge tag 'iio-for-6.3a' of...

Merge tag 'iio-for-6.3a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next

Jonathan writes:

1st set of IIO new device support, features and cleanups for the 6.3 cycle

The usual mixed bag. So far this has been a quiet cycle for IIO.

New device support
* adi,ad8686
  - Add support for the AD5337 DAC - ID and 8 bit channel support.
* maxim,max5522
  - New driver for this 2 channel DAC.
* nxp,imx93-adc
  - New driver for this SoC ADC which is a fresh IP that will probably
    turn up in additional SoCs going forwards.
* st,magn
  - Add support for magnetometer part of LSM303C which is very similar
    to standalone LIS3MDL already supported.
* ti,ads7924
  - New driver for this 4 channel, 12-bit I2C ADC.
* ti,lmp92064
  - New driver for this 12 bit SPI ADC.
* ti,tmag5273
  - New driver for this 3D Hall-Effect Sensor.

Features
* core
  - Add a standard structure for the value pairs in IIO_VAL_INT_PLUS_MICRO
    available attributes and similar.
* cirrus,ep93xx
  - Add DT binding docs and convert driver to DT based probing.
  - Enable testing building with CONFIG_COMPILE_TEST.
* st,stm32-dfsdm
  - Enable ID register support for discovery of hardware capabilities on
    some devices.

Cleanups and minor fixes
* core
  - Drop the custom iio_sysfs_match_string_with_gaps().
    The special ability of this function to skip gaps in an array
    was never used by any upstream driver.
  - Sort headers whilst touching this file.
* tools
  - Fix memory leak in iio_utils.c
* various
  - leftover i2c probe_new() conversions.
  - scnprintf() -> sysfs_emit() cleanups.
  - hand rolled devm enables -> devm_regulator[_bulk]_get_enable()
  - typo fixes
  - dt-binding cleanup (whitespace, excess quotes and similar)
* adi,ad7746
  - Set variable without pointless conditional.
* fsl,mma9551
  - Squash false positives about use of uninitialized variable where
    garbage undergoes an endian conversion before being ignored.
* measspec,ms5611
  - Switch to fully devm_ managed probe() and so drop explicit remove()
* qcom,spmi-adc
  - Use dev_err_probe() to suppress deferred print.
* qcom,spmi-adc5
  - Define a missing channel used for battery identification.
* qcom,spmi-iadc
  - Document a compatible seen in wild.
* semtech,sx9360
  - Fix units on semtech,resolution dt-binding.
* sensiron,scd30
  - dev_err_probe() usage to simplify error paths a little.
* st,lsm6dsx
  - Add missing mount matrix for the gyro IIO device.
* taos,tsl2563
  - Respect firmware configured interrupt polarity if present.
  - Use i2c_smbus_write_word_data() in a few cases not previously covered.
  - Factor out duplicated interrupt configuration.
  - Switch to GENMASK() / BIT() from hand coded equivalents.
  - Tidy up unused definitions.
  - Use dev_err_probe() as appropriate.
  - Drop platform_data as no in kernel users and there are better ways to
    do equivalent if any are added.
  - Add local struct device variable to tidy up code.
  - Avoid dance via i2c_client to get the drvdata.
  - Tidy up headers ordering and Makefile ordering.
* ti,adc128s052
  - Use new spi_get_device_match_data().
  - Drop ACPI_PTR() protection.
  - Sort headers whilst here.
  - Use asm instead of incorrect include of asm-generic/unaligned.h
* vishay,vcn4000
  - Interrupt support for vcnl4040 (lots of refactoring needed)
* xilinx,ams
  - Use fwnode_device_is_compatible() instead of open coding it.

* tag 'iio-for-6.3a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (71 commits)
  iio: adc: ad7291: Fix indentation error by adding extra spaces
  iio: accel: mma9551_core: Prevent uninitialized variable in mma9551_read_config_word()
  iio: accel: mma9551_core: Prevent uninitialized variable in mma9551_read_status_word()
  dt-bindings: iio/proximity: semtech,sx9360: Fix 'semtech,resolution' type
  iio: imu: fix spdx format
  iio: adc: imx93: Fix spelling mistake "geting" -> "getting"
  dt-bindings: iio: cleanup examples - indentation
  dt-bindings: iio: use lowercase hex in examples
  dt-bindings: iio: correct node names in examples
  dt-bindings: iio: minor whitespace cleanups
  dt-bindings: iio: drop unneeded quotes
  dt-bindings: iio: adc: Add NXP IMX93 ADC
  iio: adc: add imx93 adc support
  dt-bindings: iio: adc: add Texas Instruments ADS7924
  iio: adc: ti-ads7924: add Texas Instruments ADS7924 driver
  iio: imu: st_lsm6dsx: add 'mount_matrix' sysfs entry to gyro channel.
  iio: imu: st_lsm6dsx: fix naming of 'struct iio_info' in st_lsm6dsx_shub.c.
  iio: light: vcnl4000: Add interrupt support for vcnl4040
  iio: light: vcnl4000: Make irq handling more generic
  iio: light: vcnl4000: Prepare for more generic setup
  ...
......@@ -41,7 +41,7 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -39,7 +39,7 @@ examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -59,7 +59,7 @@ examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -49,7 +49,7 @@ examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
......@@ -64,7 +64,7 @@ examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -58,34 +58,34 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
/* Example for a I2C device node */
accelerometer@1d {
compatible = "adi,adxl355";
reg = <0x1d>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "DRDY";
};
/* Example for a I2C device node */
accelerometer@1d {
compatible = "adi,adxl355";
reg = <0x1d>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "DRDY";
};
};
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
accelerometer@0 {
compatible = "adi,adxl355";
reg = <0>;
spi-max-frequency = <1000000>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "DRDY";
};
accelerometer@0 {
compatible = "adi,adxl355";
reg = <0>;
spi-max-frequency = <1000000>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "DRDY";
};
};
......@@ -37,32 +37,32 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
/* Example for a I2C device node */
accelerometer@53 {
compatible = "adi,adxl372";
reg = <0x53>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
};
/* Example for a I2C device node */
accelerometer@53 {
compatible = "adi,adxl372";
reg = <0x53>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
};
};
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
#address-cells = <1>;
#size-cells = <0>;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
accelerometer@0 {
compatible = "adi,adxl372";
reg = <0>;
spi-max-frequency = <1000000>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
};
accelerometer@0 {
compatible = "adi,adxl372";
reg = <0>;
spi-max-frequency = <1000000>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
};
};
......@@ -36,7 +36,7 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -44,7 +44,7 @@ examples:
accel@f {
compatible = "kionix,kxtf9";
reg = <0x0F>;
reg = <0xf>;
mount-matrix = "0", "1", "0",
"1", "0", "0",
"0", "0", "1";
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: "http://devicetree.org/schemas/iio/accel/memsensing,msa311.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/iio/accel/memsensing,msa311.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MEMSensing digital 3-Axis accelerometer
......
......@@ -50,7 +50,7 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
......@@ -65,7 +65,7 @@ examples:
};
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -44,11 +44,11 @@ examples:
#size-cells = <0>;
adc@2f {
compatible = "adi,ad7091r5";
reg = <0x2f>;
compatible = "adi,ad7091r5";
reg = <0x2f>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
};
};
...
......@@ -61,7 +61,7 @@ required:
patternProperties:
"^channel@([0-9]|1[0-5])$":
$ref: "adc.yaml"
$ref: adc.yaml
type: object
description: |
Represents the external channels which are connected to the ADC.
......
......@@ -99,26 +99,26 @@ unevaluatedProperties: false
examples:
- |
spi0 {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,ad7192";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
spi-cpha;
clocks = <&ad7192_mclk>;
clock-names = "mclk";
interrupts = <25 0x2>;
interrupt-parent = <&gpio>;
dvdd-supply = <&dvdd>;
avdd-supply = <&avdd>;
adi,refin2-pins-enable;
adi,rejection-60-Hz-enable;
adi,buffer-enable;
adi,burnout-currents-enable;
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,ad7192";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
spi-cpha;
clocks = <&ad7192_mclk>;
clock-names = "mclk";
interrupts = <25 0x2>;
interrupt-parent = <&gpio>;
dvdd-supply = <&dvdd>;
avdd-supply = <&avdd>;
adi,refin2-pins-enable;
adi,rejection-60-Hz-enable;
adi,buffer-enable;
adi,burnout-currents-enable;
};
};
......@@ -43,7 +43,7 @@ required:
patternProperties:
"^channel@[0-7]$":
$ref: "adc.yaml"
$ref: adc.yaml
type: object
description: |
Represents the external channels which are connected to the ADC.
......
......@@ -112,30 +112,30 @@ examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,ad7606-8";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
spi-cpha;
avcc-supply = <&adc_vref>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>,
<&gpio 23 GPIO_ACTIVE_HIGH>,
<&gpio 26 GPIO_ACTIVE_HIGH>;
standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
adi,sw-mode;
compatible = "adi,ad7606-8";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
spi-cpha;
avcc-supply = <&adc_vref>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>,
<&gpio 23 GPIO_ACTIVE_HIGH>,
<&gpio 26 GPIO_ACTIVE_HIGH>;
standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
adi,sw-mode;
};
};
...
......@@ -72,7 +72,7 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -57,17 +57,17 @@ additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
adc1: adc@28 {
reg = <0x28>;
compatible = "adi,ad7991";
interrupts = <13 2>;
interrupt-parent = <&gpio6>;
adc1: adc@28 {
reg = <0x28>;
compatible = "adi,ad7991";
interrupts = <13 2>;
interrupt-parent = <&gpio6>;
vcc-supply = <&vcc_3v3>;
vref-supply = <&adc_vref>;
vcc-supply = <&vcc_3v3>;
vref-supply = <&adc_vref>;
};
};
...
......@@ -64,10 +64,10 @@ examples:
#size-cells = <0>;
adc@0 {
compatible = "adi,ad9467";
reg = <0>;
clocks = <&adc_clk>;
clock-names = "adc-clk";
compatible = "adi,ad9467";
reg = <0>;
clocks = <&adc_clk>;
clock-names = "adc-clk";
};
};
...
......@@ -51,11 +51,11 @@ additionalProperties: false
examples:
- |
axi-adc@44a00000 {
compatible = "adi,axi-adc-10.0.a";
reg = <0x44a00000 0x10000>;
dmas = <&rx_dma 0>;
dma-names = "rx";
compatible = "adi,axi-adc-10.0.a";
reg = <0x44a00000 0x10000>;
dmas = <&rx_dma 0>;
dma-names = "rx";
adi,adc-dev = <&spi_adc>;
adi,adc-dev = <&spi_adc>;
};
...
......@@ -41,7 +41,7 @@ properties:
description: Startup time expressed in ms, it depends on SoC.
atmel,trigger-edge-type:
$ref: '/schemas/types.yaml#/definitions/uint32'
$ref: /schemas/types.yaml#/definitions/uint32
description:
One of possible edge types for the ADTRG hardware trigger pin.
When the specific edge type is detected, the conversion will
......
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: "http://devicetree.org/schemas/iio/adc/avia-hx711.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/iio/adc/avia-hx711.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: AVIA HX711 ADC chip for weight cells
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/cirrus,ep9301-adc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cirrus Logic EP930x internal ADC
description: |
Cirrus Logic EP9301/EP9302 SoCs' internal ADC block.
User's manual:
https://cdn.embeddedts.com/resource-attachments/ts-7000_ep9301-ug.pdf
maintainers:
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
properties:
compatible:
const: cirrus,ep9301-adc
reg:
maxItems: 1
clocks:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
- clocks
additionalProperties: false
examples:
- |
adc: adc@80900000 {
compatible = "cirrus,ep9301-adc";
reg = <0x80900000 0x28>;
clocks = <&syscon 24>;
interrupt-parent = <&vic1>;
interrupts = <30>;
};
...
......@@ -2,8 +2,8 @@
# Copyright 2019-2020 Artur Rojek
%YAML 1.2
---
$id: "http://devicetree.org/schemas/iio/adc/ingenic,adc.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/iio/adc/ingenic,adc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ingenic JZ47xx ADC controller IIO
......@@ -78,14 +78,14 @@ examples:
#include <dt-bindings/iio/adc/ingenic,adc.h>
adc@10070000 {
compatible = "ingenic,jz4740-adc";
#io-channel-cells = <1>;
compatible = "ingenic,jz4740-adc";
#io-channel-cells = <1>;
reg = <0x10070000 0x30>;
reg = <0x10070000 0x30>;
clocks = <&cgu JZ4740_CLK_ADC>;
clock-names = "adc";
clocks = <&cgu JZ4740_CLK_ADC>;
clock-names = "adc";
interrupt-parent = <&intc>;
interrupts = <18>;
interrupt-parent = <&intc>;
interrupts = <18>;
};
......@@ -54,8 +54,8 @@ examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
maxadc: adc@0 {
compatible = "maxim,max1027";
reg = <0>;
......
......@@ -10,7 +10,7 @@ maintainers:
- Jonathan Cameron <jic23@kernel.org>
description: |
Family of simple ADCs with i2c inteface and internal references.
Family of simple ADCs with i2c interface and internal references.
properties:
compatible:
......
......@@ -54,8 +54,8 @@ examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "maxim,max1241";
......
......@@ -10,7 +10,7 @@ maintainers:
- Jonathan Cameron <jic23@kernel.org>
description: |
Family of ADCs with i2c inteface, internal references and threshold
Family of ADCs with i2c interface, internal references and threshold
monitoring.
properties:
......
......@@ -2,8 +2,8 @@
# Copyright 2019 Marcus Folkesson <marcus.folkesson@gmail.com>
%YAML 1.2
---
$id: "http://devicetree.org/schemas/iio/adc/microchip,mcp3911.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/iio/adc/microchip,mcp3911.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip MCP3911 Dual channel analog front end (ADC)
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/nxp,imx93-adc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP iMX93 ADC
maintainers:
- Haibo Chen <haibo.chen@nxp.com>
description:
The ADC on iMX93 is a 8-channel 12-bit 1MS/s ADC with 4 channels
connected to pins. it support normal and inject mode, include
One-Shot and Scan (continuous) conversions. Programmable DMA
enables for each channel Also this ADC contain alternate analog
watchdog thresholds, select threshold through input ports. And
also has Self-test logic and Software-initiated calibration.
properties:
compatible:
const: nxp,imx93-adc
reg:
maxItems: 1
interrupts:
items:
- description: WDGnL, watchdog threshold interrupt requests.
- description: WDGnH, watchdog threshold interrupt requests.
- description: normal conversion, include EOC (End of Conversion),
ECH (End of Chain), JEOC (End of Injected Conversion) and
JECH (End of injected Chain).
- description: Self-testing Interrupts.
clocks:
maxItems: 1
clock-names:
const: ipg
vref-supply:
description:
The reference voltage which used to establish channel scaling.
"#io-channel-cells":
const: 1
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- vref-supply
- "#io-channel-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clock/imx93-clock.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <1>;
#size-cells = <1>;
adc@44530000 {
compatible = "nxp,imx93-adc";
reg = <0x44530000 0x10000>;
interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX93_CLK_ADC1_GATE>;
clock-names = "ipg";
vref-supply = <&reg_vref_1v8>;
#io-channel-cells = <1>;
};
};
...
......@@ -160,7 +160,7 @@ examples:
};
ref_muxoff: adc-channel@f {
reg = <0x00 0x0f>;
};
};
};
};
...
......@@ -20,6 +20,7 @@ properties:
compatible:
items:
- enum:
- qcom,pm8226-iadc
- qcom,pm8941-iadc
- const: qcom,spmi-iadc
......@@ -49,7 +50,7 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
spmi_bus {
spmi {
#address-cells = <1>;
#size-cells = <0>;
pmic_iadc: adc@3600 {
......
......@@ -40,12 +40,12 @@ additionalProperties: false
examples:
- |
pmic {
#address-cells = <1>;
#size-cells = <0>;
pmic_rradc: adc@4500 {
compatible = "qcom,pmi8998-rradc";
reg = <0x4500>;
#io-channel-cells = <1>;
};
#address-cells = <1>;
#size-cells = <0>;
pmic_rradc: adc@4500 {
compatible = "qcom,pmi8998-rradc";
reg = <0x4500>;
#io-channel-cells = <1>;
};
};
......@@ -69,7 +69,7 @@ required:
patternProperties:
"^channel@[0-7]$":
$ref: "adc.yaml"
$ref: adc.yaml
type: object
description: |
Represents the external channels which are connected to the ADC.
......
......@@ -52,7 +52,7 @@ properties:
vdd-supply: true
samsung,syscon-phandle:
$ref: '/schemas/types.yaml#/definitions/phandle'
$ref: /schemas/types.yaml#/definitions/phandle
description:
Phandle to the PMU system controller node (to access the ADC_PHY
register on Exynos3250/4x12/5250/5420/5800).
......@@ -142,7 +142,7 @@ examples:
pullup-ohm = <47000>;
pulldown-ohm = <0>;
io-channels = <&adc 4>;
};
};
};
- |
......@@ -150,7 +150,7 @@ examples:
adc@126c0000 {
compatible = "samsung,exynos3250-adc";
reg = <0x126C0000 0x100>;
reg = <0x126c0000 0x100>;
interrupts = <0 137 0>;
#io-channel-cells = <1>;
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/iio/adc/st,stm32-adc.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/iio/adc/st,stm32-adc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STMicroelectronics STM32 ADC
......@@ -80,7 +80,7 @@ properties:
description:
Phandle to system configuration controller. It can be used to control the
analog circuitry on stm32mp1.
$ref: "/schemas/types.yaml#/definitions/phandle-array"
$ref: /schemas/types.yaml#/definitions/phandle-array
interrupt-controller: true
......@@ -341,7 +341,7 @@ patternProperties:
patternProperties:
"^channel@([0-9]|1[0-9])$":
type: object
$ref: "adc.yaml"
$ref: adc.yaml
description: Represents the external channels which are connected to the ADC.
properties:
......
......@@ -35,10 +35,8 @@ additionalProperties: false
examples:
- |
stmpe {
stmpe_adc {
compatible = "st,stmpe-adc";
st,norequest-mask = <0x0F>; /* dont use ADC CH3-0 */
};
adc {
compatible = "st,stmpe-adc";
st,norequest-mask = <0x0f>; /* dont use ADC CH3-0 */
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/ti,adc081c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI Single-channel I2C ADCs
maintainers:
- Jonathan Cameron <jic23@kernel.org>
- Lars-Peter Clausen <lars@metafoo.de>
description: |
Single-channel ADC supporting 8, 10, or 12-bit samples and high/low alerts.
properties:
compatible:
enum:
- ti,adc081c
- ti,adc101c
- ti,adc121c
reg:
maxItems: 1
interrupts:
maxItems: 1
vref-supply:
description:
Regulator for the combined power supply and voltage reference
"#io-channel-cells":
const: 1
required:
- compatible
- reg
- vref-supply
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@52 {
compatible = "ti,adc081c";
reg = <0x52>;
vref-supply = <&reg_2p5v>;
};
};
...
......@@ -104,12 +104,12 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
reg = <0>;
};
channel@4 {
reg = <4>;
ti,gain = <3>;
ti,datarate = <5>;
reg = <4>;
ti,gain = <3>;
ti,datarate = <5>;
};
};
};
......
......@@ -77,7 +77,7 @@ required:
patternProperties:
"^channel@([0-7])$":
$ref: "adc.yaml"
$ref: adc.yaml
type: object
description: |
Represents the external channels which are connected to the ADC.
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/ti,ads7924.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI ADS7924 4 channels 12 bits I2C analog to digital converter
maintainers:
- Hugo Villeneuve <hvilleneuve@dimonoff.com>
description: |
Texas Instruments ADS7924 4 channels 12 bits I2C analog to digital converter
Specifications:
https://www.ti.com/lit/gpn/ads7924
properties:
compatible:
const: ti,ads7924
reg:
maxItems: 1
vref-supply:
description:
The regulator supply for the ADC reference voltage (AVDD)
reset-gpios:
maxItems: 1
interrupts:
maxItems: 1
"#address-cells":
const: 1
"#size-cells":
const: 0
"#io-channel-cells":
const: 1
patternProperties:
"^channel@[0-3]+$":
$ref: adc.yaml
description: |
Represents the external channels which are connected to the ADC.
properties:
reg:
description: |
The channel number. It can have up to 4 channels numbered from 0 to 3.
items:
- minimum: 0
maximum: 3
label: true
required:
- reg
additionalProperties: false
additionalProperties: false
required:
- compatible
- reg
- vref-supply
- "#address-cells"
- "#size-cells"
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@48 {
compatible = "ti,ads7924";
reg = <0x48>;
vref-supply = <&ads7924_reg>;
reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
label = "CH0";
};
channel@1 {
reg = <1>;
label = "CH1";
};
channel@2 {
reg = <2>;
label = "CH2";
};
channel@3 {
reg = <3>;
label = "CH3";
};
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/ti,lmp92064.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments LMP92064 Precision Current and Voltage Sensor.
maintainers:
- Leonard Göhrs <l.goehrs@pengutronix.de>
description: |
The LMP92064 is a two channel ADC intended for combined voltage and current
measurements.
The device contains two ADCs to allow simultaneous sampling of voltage and
current and thus of instantaneous power consumption.
properties:
compatible:
enum:
- ti,lmp92064
reg:
maxItems: 1
vdd-supply:
description: Regulator that provides power to the main part of the chip
vdig-supply:
description: |
Regulator that provides power to the digital I/O part of the chip
shunt-resistor-micro-ohms:
description: |
Value of the shunt resistor (in µΩ) connected between INCP and INCN,
across which current is measured. Used to provide correct scaling of the
raw ADC measurement.
reset-gpios:
maxItems: 1
required:
- compatible
- reg
- shunt-resistor-micro-ohms
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "ti,lmp92064";
reg = <0>;
vdd-supply = <&vdd>;
vdig-supply = <&vdd>;
spi-max-frequency = <20000000>;
shunt-resistor-micro-ohms = <15000>;
reset-gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>;
};
};
...
......@@ -41,7 +41,7 @@ required:
patternProperties:
"^channel@[0-7]$":
$ref: "adc.yaml"
$ref: adc.yaml
type: object
properties:
......@@ -83,36 +83,36 @@ examples:
#size-cells = <0>;
channel@0 {
reg = <0>;
reg = <0>;
};
channel@1 {
reg = <1>;
settling-time-us = <700>;
oversampling-ratio = <5>;
reg = <1>;
settling-time-us = <700>;
oversampling-ratio = <5>;
};
channel@2 {
reg = <2>;
reg = <2>;
};
channel@3 {
reg = <3>;
settling-time-us = <700>;
oversampling-ratio = <5>;
reg = <3>;
settling-time-us = <700>;
oversampling-ratio = <5>;
};
channel@4 {
reg = <4>;
settling-time-us = <700>;
oversampling-ratio = <5>;
reg = <4>;
settling-time-us = <700>;
oversampling-ratio = <5>;
};
channel@5 {
reg = <5>;
settling-time-us = <700>;
oversampling-ratio = <5>;
reg = <5>;
settling-time-us = <700>;
oversampling-ratio = <5>;
};
channel@6 {
reg = <6>;
reg = <6>;
};
channel@7 {
reg = <7>;
reg = <7>;
};
};
};
......
......@@ -192,26 +192,26 @@ additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
ad3552r@0 {
compatible = "adi,ad3552r";
reg = <0>;
spi-max-frequency = <20000000>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
adi,output-range-microvolt = <0 10000000>;
};
channel@1 {
reg = <1>;
custom-output-range-config {
adi,gain-offset = <5>;
adi,gain-scaling-p-inv-log2 = <1>;
adi,gain-scaling-n-inv-log2 = <2>;
adi,rfb-ohms = <1>;
};
#address-cells = <1>;
#size-cells = <0>;
ad3552r@0 {
compatible = "adi,ad3552r";
reg = <0>;
spi-max-frequency = <20000000>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
adi,output-range-microvolt = <0 10000000>;
};
channel@1 {
reg = <1>;
custom-output-range-config {
adi,gain-offset = <5>;
adi,gain-scaling-p-inv-log2 = <1>;
adi,gain-scaling-n-inv-log2 = <2>;
adi,rfb-ohms = <1>;
};
};
};
};
......
......@@ -12,6 +12,7 @@ maintainers:
description: |
DAC devices supporting both SPI and I2C interfaces.
properties:
compatible:
enum:
......
......@@ -33,6 +33,7 @@ properties:
- description: I2C devices
enum:
- adi,ad5311r
- adi,ad5337r
- adi,ad5338r
- adi,ad5671r
- adi,ad5675r
......
......@@ -51,15 +51,15 @@ additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
ad5766@0 {
compatible = "adi,ad5766";
output-range-microvolts = <(-5000000) 5000000>;
reg = <0>;
spi-cpol;
spi-max-frequency = <1000000>;
reset-gpios = <&gpio 22 0>;
};
};
ad5766@0 {
compatible = "adi,ad5766";
output-range-microvolts = <(-5000000) 5000000>;
reg = <0>;
spi-cpol;
spi-max-frequency = <1000000>;
reset-gpios = <&gpio 22 0>;
};
};
......@@ -147,49 +147,49 @@ unevaluatedProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
ad5770r@0 {
compatible = "adi,ad5770r";
reg = <0>;
spi-max-frequency = <1000000>;
vref-supply = <&vref>;
adi,external-resistor;
reset-gpios = <&gpio 22 0>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
adi,range-microamp = <0 300000>;
};
channel@1 {
reg = <1>;
adi,range-microamp = <0 140000>;
};
channel@2 {
reg = <2>;
adi,range-microamp = <0 55000>;
};
channel@3 {
reg = <3>;
adi,range-microamp = <0 45000>;
};
channel@4 {
reg = <4>;
adi,range-microamp = <0 45000>;
};
channel@5 {
reg = <5>;
adi,range-microamp = <0 45000>;
};
};
spi {
#address-cells = <1>;
#size-cells = <0>;
ad5770r@0 {
compatible = "adi,ad5770r";
reg = <0>;
spi-max-frequency = <1000000>;
vref-supply = <&vref>;
adi,external-resistor;
reset-gpios = <&gpio 22 0>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
adi,range-microamp = <0 300000>;
};
channel@1 {
reg = <1>;
adi,range-microamp = <0 140000>;
};
channel@2 {
reg = <2>;
adi,range-microamp = <0 55000>;
};
channel@3 {
reg = <3>;
adi,range-microamp = <0 45000>;
};
channel@4 {
reg = <4>;
adi,range-microamp = <0 45000>;
};
channel@5 {
reg = <5>;
adi,range-microamp = <0 45000>;
};
};
};
...
......@@ -116,32 +116,32 @@ examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
ltc2688: ltc2688@0 {
compatible = "adi,ltc2688";
reg = <0>;
vcc-supply = <&vcc>;
iovcc-supply = <&vcc>;
vref-supply = <&vref>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
adi,toggle-mode;
adi,overrange;
};
channel@1 {
reg = <1>;
adi,output-range-microvolt = <0 10000000>;
clocks = <&clock_tgp3>;
adi,toggle-dither-input = <2>;
};
};
#address-cells = <1>;
#size-cells = <0>;
ltc2688: ltc2688@0 {
compatible = "adi,ltc2688";
reg = <0>;
vcc-supply = <&vcc>;
iovcc-supply = <&vcc>;
vref-supply = <&vref>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
adi,toggle-mode;
adi,overrange;
};
channel@1 {
reg = <1>;
adi,output-range-microvolt = <0 10000000>;
clocks = <&clock_tgp3>;
adi,toggle-dither-input = <2>;
};
};
};
...
......@@ -2,8 +2,8 @@
# Copyright 2019 Marcus Folkesson <marcus.folkesson@gmail.com>
%YAML 1.2
---
$id: "http://devicetree.org/schemas/iio/dac/lltc,ltc1660.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/iio/dac/lltc,ltc1660.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Linear Technology Micropower octal 8-Bit and 10-Bit DACs
......
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
%YAML 1.2
---
$id: "http://devicetree.org/schemas/iio/dac/lltc,ltc2632.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/iio/dac/lltc,ltc2632.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Linear Technology LTC263x 12-/10-/8-Bit Rail-to-Rail DAC
......@@ -64,14 +64,14 @@ examples:
};
spi {
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
dac@0 {
compatible = "lltc,ltc2632-l12";
reg = <0>; /* CS0 */
spi-max-frequency = <1000000>;
vref-supply = <&vref>;
};
dac@0 {
compatible = "lltc,ltc2632-l12";
reg = <0>; /* CS0 */
spi-max-frequency = <1000000>;
vref-supply = <&vref>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/dac/maxim,max5522.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim Integrated MAX5522 Dual 10-bit Voltage-Output SPI DACs
maintainers:
- Angelo Dureghello <angelo.dureghello@timesys.com>
- Jonathan Cameron <jic23@kernel.org>
description: |
Datasheet available at:
https://www.analog.com/en/products/max5522.html
properties:
compatible:
const: maxim,max5522
reg:
maxItems: 1
vdd-supply: true
vrefin-supply: true
required:
- compatible
- reg
- vrefin-supply
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
dac@0 {
compatible = "maxim,max5522";
reg = <0>;
vrefin-supply = <&vref>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/iio/dac/st,stm32-dac.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/iio/dac/st,stm32-dac.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STMicroelectronics STM32 DAC
......
......@@ -46,7 +46,7 @@ examples:
dac@4c {
compatible = "ti,dac5571";
reg = <0x4C>;
reg = <0x4c>;
vref-supply = <&vdd_supply>;
};
};
......
......@@ -53,16 +53,16 @@ unevaluatedProperties: false
examples:
- |
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
frequency@0 {
compatible = "adi,adf4371";
reg = <0>;
spi-max-frequency = <1000000>;
clocks = <&adf4371_clkin>;
clock-names = "clkin";
compatible = "adi,adf4371";
reg = <0>;
spi-max-frequency = <1000000>;
clocks = <&adf4371_clkin>;
clock-names = "clkin";
};
};
...
......@@ -50,13 +50,13 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
gyro@0 {
compatible = "adi,adxrs290";
reg = <0>;
spi-max-frequency = <5000000>;
spi-cpol;
spi-cpha;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
compatible = "adi,adxrs290";
reg = <0>;
spi-max-frequency = <5000000>;
spi-cpol;
spi-cpha;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
};
};
...
......@@ -65,34 +65,34 @@ examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
gyroscope@20 {
compatible = "nxp,fxas21002c";
reg = <0x20>;
compatible = "nxp,fxas21002c";
reg = <0x20>;
vdd-supply = <&reg_peri_3p15v>;
vddio-supply = <&reg_peri_3p15v>;
vdd-supply = <&reg_peri_3p15v>;
vddio-supply = <&reg_peri_3p15v>;
interrupt-parent = <&gpio1>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
interrupt-parent = <&gpio1>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
};
};
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
gyroscope@0 {
compatible = "nxp,fxas21002c";
reg = <0x0>;
compatible = "nxp,fxas21002c";
reg = <0x0>;
spi-max-frequency = <2000000>;
spi-max-frequency = <2000000>;
interrupt-parent = <&gpio2>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT2";
interrupt-parent = <&gpio2>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT2";
};
};
......@@ -42,7 +42,7 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
heart_mon@0 {
heart-mon@0 {
compatible = "ti,afe4403";
reg = <0>;
spi-max-frequency = <10000000>;
......
......@@ -39,7 +39,7 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
heart_mon@58 {
heart-mon@58 {
compatible = "ti,afe4404";
reg = <0x58>;
tx-supply = <&vbat>;
......
......@@ -34,7 +34,7 @@ additionalProperties: false
examples:
- |
humidity_sensor {
humidity-sensor {
compatible = "dht11";
gpios = <&gpio0 6 0>;
};
......
......@@ -35,12 +35,12 @@ additionalProperties: false
examples:
- |
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
humidity@40 {
compatible = "ti,hdc2010";
reg = <0x40>;
};
i2c {
#address-cells = <1>;
#size-cells = <0>;
humidity@40 {
compatible = "ti,hdc2010";
reg = <0x40>;
};
};
......@@ -42,7 +42,7 @@ examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -114,17 +114,17 @@ examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
adis16475: adis16475-3@0 {
compatible = "adi,adis16475-3";
reg = <0>;
spi-cpha;
spi-cpol;
spi-max-frequency = <2000000>;
interrupts = <4 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpio>;
};
#address-cells = <1>;
#size-cells = <0>;
adis16475: adis16475-3@0 {
compatible = "adi,adis16475-3";
reg = <0>;
spi-cpha;
spi-cpol;
spi-max-frequency = <2000000>;
interrupts = <4 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpio>;
};
};
...
......@@ -64,16 +64,16 @@ examples:
#size-cells = <0>;
bmi160@68 {
compatible = "bosch,bmi160";
reg = <0x68>;
vdd-supply = <&pm8916_l17>;
vddio-supply = <&pm8916_l6>;
interrupt-parent = <&gpio4>;
interrupts = <12 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
mount-matrix = "0", "1", "0",
"-1", "0", "0",
"0", "0", "1";
compatible = "bosch,bmi160";
reg = <0x68>;
vdd-supply = <&pm8916_l17>;
vddio-supply = <&pm8916_l6>;
interrupt-parent = <&gpio4>;
interrupts = <12 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
mount-matrix = "0", "1", "0",
"-1", "0", "0",
"0", "0", "1";
};
};
- |
......@@ -84,11 +84,11 @@ examples:
#size-cells = <0>;
bmi160@0 {
compatible = "bosch,bmi160";
reg = <0>;
spi-max-frequency = <10000000>;
interrupt-parent = <&gpio2>;
interrupts = <12 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT2";
compatible = "bosch,bmi160";
reg = <0>;
spi-max-frequency = <10000000>;
interrupt-parent = <&gpio2>;
interrupts = <12 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT2";
};
};
......@@ -65,35 +65,35 @@ examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
icm42605@68 {
compatible = "invensense,icm42605";
reg = <0x68>;
interrupt-parent = <&gpio2>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
vdd-supply = <&vdd>;
vddio-supply = <&vddio>;
compatible = "invensense,icm42605";
reg = <0x68>;
interrupt-parent = <&gpio2>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
vdd-supply = <&vdd>;
vddio-supply = <&vddio>;
};
};
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
icm42602@0 {
compatible = "invensense,icm42602";
reg = <0>;
spi-max-frequency = <24000000>;
spi-cpha;
spi-cpol;
interrupt-parent = <&gpio1>;
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
vdd-supply = <&vdd>;
vddio-supply = <&vddio>;
compatible = "invensense,icm42602";
reg = <0>;
spi-max-frequency = <24000000>;
spi-cpha;
spi-cpol;
interrupt-parent = <&gpio1>;
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
vdd-supply = <&vdd>;
vddio-supply = <&vddio>;
};
};
......@@ -49,33 +49,33 @@ examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
fxos8700@1e {
compatible = "nxp,fxos8700";
reg = <0x1e>;
compatible = "nxp,fxos8700";
reg = <0x1e>;
interrupt-parent = <&gpio2>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
interrupt-parent = <&gpio2>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
};
};
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
spi {
#address-cells = <1>;
#size-cells = <0>;
fxos8700@0 {
compatible = "nxp,fxos8700";
reg = <0>;
compatible = "nxp,fxos8700";
reg = <0>;
spi-max-frequency = <1000000>;
interrupt-parent = <&gpio1>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT2";
spi-max-frequency = <1000000>;
interrupt-parent = <&gpio1>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT2";
};
};
......@@ -63,7 +63,7 @@ properties:
description: if defined provides VDD IO power to the sensor.
st,drdy-int-pin:
$ref: '/schemas/types.yaml#/definitions/uint32'
$ref: /schemas/types.yaml#/definitions/uint32
description: |
The pin on the package that will be used to signal data ready
enum:
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/magnetometer/ti,tmag5273.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor
maintainers:
- Gerald Loacker <gerald.loacker@wolfvision.net>
description:
The TI TMAG5273 is a low-power linear 3D Hall-effect sensor. This device
integrates three independent Hall-effect sensors in the X, Y, and Z axes.
The device has an integrated temperature sensor available. The TMAG5273
can be configured through the I2C interface to enable any combination of
magnetic axes and temperature measurements. An integrated angle calculation
engine (CORDIC) provides full 360° angular position information for both
on-axis and off-axis angle measurement topologies. The angle calculation is
performed using two user-selected magnetic axes.
properties:
compatible:
const: ti,tmag5273
reg:
maxItems: 1
"#io-channel-cells":
const: 1
ti,angle-measurement:
$ref: /schemas/types.yaml#/definitions/string
description:
Enables angle measurement in the selected plane.
If not specified, "x-y" will be anables as default.
enum:
- off
- x-y
- y-z
- x-z
vcc-supply:
description:
A regulator providing 1.7 V to 3.6 V supply voltage on the VCC pin,
typically 3.3 V.
interrupts:
description:
The low active interrupt can be configured to be fixed width or latched.
Interrupt events can be configured to be generated from magnetic
thresholds or when a conversion is completed.
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
magnetometer@35 {
compatible = "ti,tmag5273";
reg = <0x35>;
#io-channel-cells = <1>;
ti,angle-measurement = "x-z";
vcc-supply = <&vcc3v3>;
};
};
...
......@@ -91,12 +91,12 @@ examples:
#size-cells = <0>;
magnetometer@2e {
compatible = "yamaha,yas530";
reg = <0x2e>;
vdd-supply = <&ldo1_reg>;
iovdd-supply = <&ldo2_reg>;
reset-gpios = <&gpio6 12 GPIO_ACTIVE_LOW>;
interrupts = <13 IRQ_TYPE_EDGE_RISING>;
compatible = "yamaha,yas530";
reg = <0x2e>;
vdd-supply = <&ldo1_reg>;
iovdd-supply = <&ldo2_reg>;
reset-gpios = <&gpio6 12 GPIO_ACTIVE_LOW>;
interrupts = <13 IRQ_TYPE_EDGE_RISING>;
};
};
......@@ -105,8 +105,8 @@ examples:
#size-cells = <0>;
magnetometer@2e {
compatible = "yamaha,yas539";
reg = <0x2e>;
vdd-supply = <&ldo1_reg>;
compatible = "yamaha,yas539";
reg = <0x2e>;
vdd-supply = <&ldo1_reg>;
};
};
......@@ -44,7 +44,7 @@ examples:
potentiometer@2f {
compatible = "adi,ad5272-020";
reg = <0x2F>;
reg = <0x2f>;
reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
};
};
......
......@@ -39,7 +39,7 @@ examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -60,16 +60,16 @@ examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
pressure@77 {
compatible = "bosch,bmp085";
reg = <0x77>;
interrupt-parent = <&gpio0>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>;
vddd-supply = <&foo>;
vdda-supply = <&bar>;
};
i2c {
#address-cells = <1>;
#size-cells = <0>;
pressure@77 {
compatible = "bosch,bmp085";
reg = <0x77>;
interrupt-parent = <&gpio0>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>;
vddd-supply = <&foo>;
vdda-supply = <&bar>;
};
};
......@@ -60,7 +60,7 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
lightning@0 {
lightning@0 {
compatible = "ams,as3935";
reg = <0>;
spi-max-frequency = <400000>;
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/proximity/google,cros-ec-mkbp-proximity.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
......
......@@ -36,7 +36,7 @@ properties:
const: 1
semtech,resolution:
$ref: /schemas/types.yaml#/definitions/uint32-array
$ref: /schemas/types.yaml#/definitions/uint32
enum: [8, 16, 32, 64, 128, 256, 512, 1024]
description:
Capacitance measurement resolution. For both phases, "reference" and
......
......@@ -39,6 +39,7 @@ properties:
- st,lis3lv02dl-accel
- st,lng2dm-accel
- st,lsm303agr-accel
- st,lsm303c-accel
- st,lsm303dl-accel
- st,lsm303dlh-accel
- st,lsm303dlhc-accel
......@@ -66,6 +67,7 @@ properties:
- st,lis2mdl
- st,lis3mdl-magn
- st,lsm303agr-magn
- st,lsm303c-magn
- st,lsm303dlh-magn
- st,lsm303dlhc-magn
- st,lsm303dlm-magn
......
......@@ -472,75 +472,74 @@ examples:
#size-cells = <0>;
temperature-sensor@0 {
compatible = "adi,ltc2983";
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <20 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpio>;
thermocouple@18 {
reg = <18>;
adi,sensor-type = <8>; //Type B
adi,sensor-oc-current-microamp = <10>;
adi,cold-junction-handle = <&diode5>;
};
diode5: diode@5 {
reg = <5>;
adi,sensor-type = <28>;
};
rsense2: rsense@2 {
reg = <2>;
adi,sensor-type = <29>;
adi,rsense-val-milli-ohms = <1200000>; //1.2Kohms
};
rtd@14 {
reg = <14>;
adi,sensor-type = <15>; //PT1000
/*2-wire, internal gnd, no current rotation*/
adi,number-of-wires = <2>;
adi,rsense-share;
adi,excitation-current-microamp = <500>;
adi,rsense-handle = <&rsense2>;
};
adc@10 {
reg = <10>;
adi,sensor-type = <30>;
adi,single-ended;
};
thermistor@12 {
reg = <12>;
adi,sensor-type = <26>; //Steinhart
adi,rsense-handle = <&rsense2>;
adi,custom-steinhart = <0x00F371EC 0x12345678
0x2C0F8733 0x10018C66 0xA0FEACCD
0x90021D99>; //6 entries
};
thermocouple@20 {
reg = <20>;
adi,sensor-type = <9>; //custom thermocouple
adi,single-ended;
adi,custom-thermocouple =
/bits/ 64 <(-50220000) 0>,
/bits/ 64 <(-30200000) 99100000>,
/bits/ 64 <(-5300000) 135400000>,
/bits/ 64 <0 273150000>,
/bits/ 64 <40200000 361200000>,
/bits/ 64 <55300000 522100000>,
/bits/ 64 <88300000 720300000>,
/bits/ 64 <132200000 811200000>,
/bits/ 64 <188700000 922500000>,
/bits/ 64 <460400000 1000000000>; //10 pairs
};
compatible = "adi,ltc2983";
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <20 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpio>;
thermocouple@18 {
reg = <18>;
adi,sensor-type = <8>; //Type B
adi,sensor-oc-current-microamp = <10>;
adi,cold-junction-handle = <&diode5>;
};
diode5: diode@5 {
reg = <5>;
adi,sensor-type = <28>;
};
rsense2: rsense@2 {
reg = <2>;
adi,sensor-type = <29>;
adi,rsense-val-milli-ohms = <1200000>; //1.2Kohms
};
rtd@14 {
reg = <14>;
adi,sensor-type = <15>; //PT1000
/*2-wire, internal gnd, no current rotation*/
adi,number-of-wires = <2>;
adi,rsense-share;
adi,excitation-current-microamp = <500>;
adi,rsense-handle = <&rsense2>;
};
adc@10 {
reg = <10>;
adi,sensor-type = <30>;
adi,single-ended;
};
thermistor@12 {
reg = <12>;
adi,sensor-type = <26>; //Steinhart
adi,rsense-handle = <&rsense2>;
adi,custom-steinhart = <0x00f371ec 0x12345678
0x2c0f8733 0x10018c66 0xa0feaccd
0x90021d99>; //6 entries
};
thermocouple@20 {
reg = <20>;
adi,sensor-type = <9>; //custom thermocouple
adi,single-ended;
adi,custom-thermocouple =
/bits/ 64 <(-50220000) 0>,
/bits/ 64 <(-30200000) 99100000>,
/bits/ 64 <(-5300000) 135400000>,
/bits/ 64 <0 273150000>,
/bits/ 64 <40200000 361200000>,
/bits/ 64 <55300000 522100000>,
/bits/ 64 <88300000 720300000>,
/bits/ 64 <132200000 811200000>,
/bits/ 64 <188700000 922500000>,
/bits/ 64 <460400000 1000000000>; //10 pairs
};
};
};
...
......@@ -43,12 +43,12 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
temp_sensor@0 {
compatible = "maxim,max31865";
reg = <0>;
spi-max-frequency = <400000>;
spi-cpha;
maxim,3-wire;
temperature-sensor@0 {
compatible = "maxim,max31865";
reg = <0>;
spi-max-frequency = <400000>;
spi-cpha;
maxim,3-wire;
};
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/iio/temperature/ti,tmp117.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/iio/temperature/ti,tmp117.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: "TI TMP117 - Digital temperature sensor with integrated NV memory"
title: TI TMP117 - Digital temperature sensor with integrated NV memory
description: |
TI TMP117 - Digital temperature sensor with integrated NV memory that supports
......
......@@ -2090,8 +2090,10 @@ M: Hartley Sweeten <hsweeten@visionengravers.com>
M: Alexander Sverdlin <alexander.sverdlin@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/iio/adc/cirrus,ep9301-adc.yaml
F: arch/arm/mach-ep93xx/
F: arch/arm/mach-ep93xx/include/mach/
F: drivers/iio/adc/ep93xx_adc.c
ARM/CLKDEV SUPPORT
M: Russell King <linux@armlinux.org.uk>
......@@ -15038,14 +15040,16 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/adc/nxp,imx8qxp-adc.yaml
F: drivers/iio/adc/imx8qxp-adc.c
NXP i.MX 7D/6SX/6UL AND VF610 ADC DRIVER
NXP i.MX 7D/6SX/6UL/93 AND VF610 ADC DRIVER
M: Haibo Chen <haibo.chen@nxp.com>
L: linux-iio@vger.kernel.org
L: linux-imx@nxp.com
S: Maintained
F: Documentation/devicetree/bindings/iio/adc/fsl,imx7d-adc.yaml
F: Documentation/devicetree/bindings/iio/adc/fsl,vf610-adc.yaml
F: Documentation/devicetree/bindings/iio/adc/nxp,imx93-adc.yaml
F: drivers/iio/adc/imx7d_adc.c
F: drivers/iio/adc/imx93_adc.c
F: drivers/iio/adc/vf610_adc.c
NXP PF8100/PF8121A/PF8200 PMIC REGULATOR DEVICE DRIVER
......@@ -20814,6 +20818,13 @@ M: Robert Richter <rric@kernel.org>
S: Odd Fixes
F: drivers/gpio/gpio-thunderx.c
TI ADS7924 ADC DRIVER
M: Hugo Villeneuve <hvilleneuve@dimonoff.com>
L: linux-iio@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/iio/adc/ti,ads7924.yaml
F: drivers/iio/adc/ti-ads7924.c
TI AM437X VPFE DRIVER
M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
L: linux-media@vger.kernel.org
......@@ -20934,6 +20945,14 @@ S: Maintained
F: sound/soc/codecs/isabelle*
F: sound/soc/codecs/lm49453*
TI LMP92064 ADC DRIVER
M: Leonard Göhrs <l.goehrs@pengutronix.de>
R: kernel@pengutronix.de
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/adc/ti,lmp92064.yaml
F: drivers/iio/adc/ti-lmp92064.c
TI PCM3060 ASoC CODEC DRIVER
M: Kirill Marinushkin <kmarinushkin@birdec.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
......@@ -20947,6 +20966,13 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Odd Fixes
F: sound/soc/codecs/tas571x*
TI TMAG5273 MAGNETOMETER DRIVER
M: Gerald Loacker <gerald.loacker@wolfvision.net>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/magnetometer/ti,tmag5273.yaml
F: drivers/iio/magnetometer/tmag5273.c
TI TRF7970A NFC DRIVER
M: Mark Greer <mgreer@animalcreek.com>
L: linux-wireless@vger.kernel.org
......
......@@ -380,7 +380,7 @@ config IIO_ST_ACCEL_3AXIS
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics accelerometers:
LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
LSM303C, LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL,
LNG2DM, LIS3DE, LIS2DE12, LIS2HH12
......
......@@ -141,10 +141,6 @@
#define BMA400_SCALE_MIN 9577
#define BMA400_SCALE_MAX 76617
#define BMA400_NUM_REGULATORS 2
#define BMA400_VDD_REGULATOR 0
#define BMA400_VDDIO_REGULATOR 1
extern const struct regmap_config bma400_regmap_config;
int bma400_probe(struct device *dev, struct regmap *regmap, int irq,
......
......@@ -98,7 +98,6 @@ enum bma400_activity {
struct bma400_data {
struct device *dev;
struct regmap *regmap;
struct regulator_bulk_data regulators[BMA400_NUM_REGULATORS];
struct mutex mutex; /* data register lock */
struct iio_mount_matrix orientation;
enum bma400_power_mode power_mode;
......@@ -832,13 +831,6 @@ static void bma400_init_tables(void)
}
}
static void bma400_regulators_disable(void *data_ptr)
{
struct bma400_data *data = data_ptr;
regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
}
static void bma400_power_disable(void *data_ptr)
{
struct bma400_data *data = data_ptr;
......@@ -868,30 +860,17 @@ static enum iio_modifier bma400_act_to_mod(enum bma400_activity activity)
static int bma400_init(struct bma400_data *data)
{
static const char * const regulator_names[] = { "vdd", "vddio" };
unsigned int val;
int ret;
data->regulators[BMA400_VDD_REGULATOR].supply = "vdd";
data->regulators[BMA400_VDDIO_REGULATOR].supply = "vddio";
ret = devm_regulator_bulk_get(data->dev,
ARRAY_SIZE(data->regulators),
data->regulators);
ret = devm_regulator_bulk_get_enable(data->dev,
ARRAY_SIZE(regulator_names),
regulator_names);
if (ret)
return dev_err_probe(data->dev, ret, "Failed to get regulators: %d\n",
ret);
ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
data->regulators);
if (ret) {
dev_err(data->dev, "Failed to enable regulators: %d\n",
ret);
return ret;
}
ret = devm_add_action_or_reset(data->dev, bma400_regulators_disable, data);
if (ret)
return ret;
/* Try to read chip_id register. It must return 0x90. */
ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val);
if (ret) {
......
......@@ -296,9 +296,12 @@ int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
reg, NULL, 0, (u8 *)&v, 2);
if (ret < 0)
return ret;
*val = be16_to_cpu(v);
return ret;
return 0;
}
EXPORT_SYMBOL_NS(mma9551_read_config_word, IIO_MMA9551);
......@@ -354,9 +357,12 @@ int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
reg, NULL, 0, (u8 *)&v, 2);
if (ret < 0)
return ret;
*val = be16_to_cpu(v);
return ret;
return 0;
}
EXPORT_SYMBOL_NS(mma9551_read_status_word, IIO_MMA9551);
......
......@@ -37,6 +37,7 @@
#define LIS2DE12_ACCEL_DEV_NAME "lis2de12"
#define LIS2HH12_ACCEL_DEV_NAME "lis2hh12"
#define LIS302DL_ACCEL_DEV_NAME "lis302dl"
#define LSM303C_ACCEL_DEV_NAME "lsm303c_accel"
#define SC7A20_ACCEL_DEV_NAME "sc7a20"
......
......@@ -929,6 +929,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS2HH12_ACCEL_DEV_NAME,
[1] = LSM303C_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_16bit_channels,
.odr = {
......
......@@ -111,6 +111,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lis302dl",
.data = LIS302DL_ACCEL_DEV_NAME,
},
{
.compatible = "st,lsm303c-accel",
.data = LSM303C_ACCEL_DEV_NAME,
},
{
.compatible = "silan,sc7a20",
.data = SC7A20_ACCEL_DEV_NAME,
......@@ -151,6 +155,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ LIS2DE12_ACCEL_DEV_NAME },
{ LIS2HH12_ACCEL_DEV_NAME },
{ LIS302DL_ACCEL_DEV_NAME },
{ LSM303C_ACCEL_DEV_NAME },
{ SC7A20_ACCEL_DEV_NAME },
{},
};
......
......@@ -96,6 +96,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lis302dl",
.data = LIS302DL_ACCEL_DEV_NAME,
},
{
.compatible = "st,lsm303c-accel",
.data = LSM303C_ACCEL_DEV_NAME,
},
{}
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
......@@ -152,6 +156,7 @@ static const struct spi_device_id st_accel_id_table[] = {
{ LIS3DHH_ACCEL_DEV_NAME },
{ LIS3DE_ACCEL_DEV_NAME },
{ LIS302DL_ACCEL_DEV_NAME },
{ LSM303C_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
......
......@@ -441,7 +441,8 @@ config ENVELOPE_DETECTOR
config EP93XX_ADC
tristate "Cirrus Logic EP93XX ADC driver"
depends on ARCH_EP93XX
depends on ARCH_EP93XX || COMPILE_TEST
depends on HAS_IOMEM
help
Driver for the ADC module on the EP93XX series of SoC from Cirrus Logic.
It's recommended to switch on CONFIG_HIGH_RES_TIMERS option, in this
......@@ -565,6 +566,16 @@ config IMX8QXP_ADC
This driver can also be built as a module. If so, the module will be
called imx8qxp-adc.
config IMX93_ADC
tristate "IMX93 ADC driver"
depends on ARCH_MXC || COMPILE_TEST
depends on HAS_IOMEM
help
Say yes here to build support for IMX93 ADC.
This driver can also be built as a module. If so, the module will be
called imx93_adc.
config LP8788_ADC
tristate "LP8788 ADC driver"
depends on MFD_LP8788
......@@ -1207,6 +1218,17 @@ config TI_ADS1015
This driver can also be built as a module. If so, the module will be
called ti-ads1015.
config TI_ADS7924
tristate "Texas Instruments ADS7924 ADC"
depends on I2C
select REGMAP_I2C
help
If you say yes here you get support for Texas Instruments ADS7924
4 channels, 12-bit I2C ADC chip.
This driver can also be built as a module. If so, the module will be
called ti-ads7924.
config TI_ADS7950
tristate "Texas Instruments ADS7950 ADC driver"
depends on SPI && GPIOLIB
......@@ -1274,6 +1296,16 @@ config TI_AM335X_ADC
To compile this driver as a module, choose M here: the module will be
called ti_am335x_adc.
config TI_LMP92064
tristate "Texas Instruments LMP92064 ADC driver"
depends on SPI
help
Say yes here to build support for the LMP92064 Precision Current and Voltage
sensor.
This driver can also be built as a module. If so, the module will be called
ti-lmp92064.
config TI_TLC4541
tristate "Texas Instruments TLC4541 ADC driver"
depends on SPI
......
......@@ -49,6 +49,7 @@ obj-$(CONFIG_HI8435) += hi8435.o
obj-$(CONFIG_HX711) += hx711.o
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
obj-$(CONFIG_IMX8QXP_ADC) += imx8qxp-adc.o
obj-$(CONFIG_IMX93_ADC) += imx93_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_INGENIC_ADC) += ingenic-adc.o
obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o
......@@ -107,12 +108,14 @@ obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o
obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TI_LMP92064) += ti-lmp92064.o
obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
obj-$(CONFIG_TI_TSC2046) += ti-tsc2046.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
......
......@@ -179,7 +179,7 @@ static unsigned int ad7291_threshold_reg(const struct iio_chan_spec *chan,
offset = AD7291_VOLTAGE_OFFSET;
break;
default:
return 0;
return 0;
}
switch (info) {
......
......@@ -2181,7 +2181,7 @@ static ssize_t at91_adc_get_fifo_state(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct at91_adc_state *st = iio_priv(indio_dev);
return scnprintf(buf, PAGE_SIZE, "%d\n", !!st->dma_st.dma_chan);
return sysfs_emit(buf, "%d\n", !!st->dma_st.dma_chan);
}
static ssize_t at91_adc_get_watermark(struct device *dev,
......@@ -2190,7 +2190,7 @@ static ssize_t at91_adc_get_watermark(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct at91_adc_state *st = iio_priv(indio_dev);
return scnprintf(buf, PAGE_SIZE, "%d\n", st->dma_st.watermark);
return sysfs_emit(buf, "%d\n", st->dma_st.watermark);
}
static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
......
......@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/of.h>
/*
* This code could benefit from real HR Timers, but jiffy granularity would
......@@ -227,9 +228,16 @@ static int ep93xx_adc_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id ep93xx_adc_of_ids[] = {
{ .compatible = "cirrus,ep9301-adc" },
{}
};
MODULE_DEVICE_TABLE(of, ep93xx_adc_of_ids);
static struct platform_driver ep93xx_adc_driver = {
.driver = {
.name = "ep93xx-adc",
.of_match_table = ep93xx_adc_of_ids,
},
.probe = ep93xx_adc_probe,
.remove = ep93xx_adc_remove,
......
// SPDX-License-Identifier: GPL-2.0+
/*
* NXP i.MX93 ADC driver
*
* Copyright 2023 NXP
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/err.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>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#define IMX93_ADC_DRIVER_NAME "imx93-adc"
/* Register map definition */
#define IMX93_ADC_MCR 0x00
#define IMX93_ADC_MSR 0x04
#define IMX93_ADC_ISR 0x10
#define IMX93_ADC_IMR 0x20
#define IMX93_ADC_CIMR0 0x24
#define IMX93_ADC_CTR0 0x94
#define IMX93_ADC_NCMR0 0xA4
#define IMX93_ADC_PCDR0 0x100
#define IMX93_ADC_PCDR1 0x104
#define IMX93_ADC_PCDR2 0x108
#define IMX93_ADC_PCDR3 0x10c
#define IMX93_ADC_PCDR4 0x110
#define IMX93_ADC_PCDR5 0x114
#define IMX93_ADC_PCDR6 0x118
#define IMX93_ADC_PCDR7 0x11c
#define IMX93_ADC_CALSTAT 0x39C
/* ADC bit shift */
#define IMX93_ADC_MCR_MODE_MASK BIT(29)
#define IMX93_ADC_MCR_NSTART_MASK BIT(24)
#define IMX93_ADC_MCR_CALSTART_MASK BIT(14)
#define IMX93_ADC_MCR_ADCLKSE_MASK BIT(8)
#define IMX93_ADC_MCR_PWDN_MASK BIT(0)
#define IMX93_ADC_MSR_CALFAIL_MASK BIT(30)
#define IMX93_ADC_MSR_CALBUSY_MASK BIT(29)
#define IMX93_ADC_MSR_ADCSTATUS_MASK GENMASK(2, 0)
#define IMX93_ADC_ISR_ECH_MASK BIT(0)
#define IMX93_ADC_ISR_EOC_MASK BIT(1)
#define IMX93_ADC_ISR_EOC_ECH_MASK (IMX93_ADC_ISR_EOC_MASK | \
IMX93_ADC_ISR_ECH_MASK)
#define IMX93_ADC_IMR_JEOC_MASK BIT(3)
#define IMX93_ADC_IMR_JECH_MASK BIT(2)
#define IMX93_ADC_IMR_EOC_MASK BIT(1)
#define IMX93_ADC_IMR_ECH_MASK BIT(0)
#define IMX93_ADC_PCDR_CDATA_MASK GENMASK(11, 0)
/* ADC status */
#define IMX93_ADC_MSR_ADCSTATUS_IDLE 0
#define IMX93_ADC_MSR_ADCSTATUS_POWER_DOWN 1
#define IMX93_ADC_MSR_ADCSTATUS_WAIT_STATE 2
#define IMX93_ADC_MSR_ADCSTATUS_BUSY_IN_CALIBRATION 3
#define IMX93_ADC_MSR_ADCSTATUS_SAMPLE 4
#define IMX93_ADC_MSR_ADCSTATUS_CONVERSION 6
#define IMX93_ADC_TIMEOUT msecs_to_jiffies(100)
struct imx93_adc {
struct device *dev;
void __iomem *regs;
struct clk *ipg_clk;
int irq;
struct regulator *vref;
/* lock to protect against multiple access to the device */
struct mutex lock;
struct completion completion;
};
#define IMX93_ADC_CHAN(_idx) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
static const struct iio_chan_spec imx93_adc_iio_channels[] = {
IMX93_ADC_CHAN(0),
IMX93_ADC_CHAN(1),
IMX93_ADC_CHAN(2),
IMX93_ADC_CHAN(3),
};
static void imx93_adc_power_down(struct imx93_adc *adc)
{
u32 mcr, msr;
int ret;
mcr = readl(adc->regs + IMX93_ADC_MCR);
mcr |= FIELD_PREP(IMX93_ADC_MCR_PWDN_MASK, 1);
writel(mcr, adc->regs + IMX93_ADC_MCR);
ret = readl_poll_timeout(adc->regs + IMX93_ADC_MSR, msr,
((msr & IMX93_ADC_MSR_ADCSTATUS_MASK) ==
IMX93_ADC_MSR_ADCSTATUS_POWER_DOWN),
1, 50);
if (ret == -ETIMEDOUT)
dev_warn(adc->dev,
"ADC do not in power down mode, current MSR is %x\n",
msr);
}
static void imx93_adc_power_up(struct imx93_adc *adc)
{
u32 mcr;
/* bring ADC out of power down state, in idle state */
mcr = readl(adc->regs + IMX93_ADC_MCR);
mcr &= ~FIELD_PREP(IMX93_ADC_MCR_PWDN_MASK, 1);
writel(mcr, adc->regs + IMX93_ADC_MCR);
}
static void imx93_adc_config_ad_clk(struct imx93_adc *adc)
{
u32 mcr;
/* put adc in power down mode */
imx93_adc_power_down(adc);
/* config the AD_CLK equal to bus clock */
mcr = readl(adc->regs + IMX93_ADC_MCR);
mcr |= FIELD_PREP(IMX93_ADC_MCR_ADCLKSE_MASK, 1);
writel(mcr, adc->regs + IMX93_ADC_MCR);
imx93_adc_power_up(adc);
}
static int imx93_adc_calibration(struct imx93_adc *adc)
{
u32 mcr, msr;
int ret;
/* make sure ADC in power down mode */
imx93_adc_power_down(adc);
/* config SAR controller operating clock */
mcr = readl(adc->regs + IMX93_ADC_MCR);
mcr &= ~FIELD_PREP(IMX93_ADC_MCR_ADCLKSE_MASK, 1);
writel(mcr, adc->regs + IMX93_ADC_MCR);
imx93_adc_power_up(adc);
/*
* TODO: we use the default TSAMP/NRSMPL/AVGEN in MCR,
* can add the setting of these bit if need in future.
*/
/* run calibration */
mcr = readl(adc->regs + IMX93_ADC_MCR);
mcr |= FIELD_PREP(IMX93_ADC_MCR_CALSTART_MASK, 1);
writel(mcr, adc->regs + IMX93_ADC_MCR);
/* wait calibration to be finished */
ret = readl_poll_timeout(adc->regs + IMX93_ADC_MSR, msr,
!(msr & IMX93_ADC_MSR_CALBUSY_MASK), 1000, 2000000);
if (ret == -ETIMEDOUT) {
dev_warn(adc->dev, "ADC do not finish calibration in 2 min!\n");
imx93_adc_power_down(adc);
return ret;
}
/* check whether calbration is success or not */
msr = readl(adc->regs + IMX93_ADC_MSR);
if (msr & IMX93_ADC_MSR_CALFAIL_MASK) {
dev_warn(adc->dev, "ADC calibration failed!\n");
imx93_adc_power_down(adc);
return -EAGAIN;
}
return 0;
}
static int imx93_adc_read_channel_conversion(struct imx93_adc *adc,
int channel_number,
int *result)
{
u32 channel;
u32 imr, mcr, pcda;
long ret;
reinit_completion(&adc->completion);
/* config channel mask register */
channel = 1 << channel_number;
writel(channel, adc->regs + IMX93_ADC_NCMR0);
/* TODO: can config desired sample time in CTRn if need */
/* config interrupt mask */
imr = FIELD_PREP(IMX93_ADC_IMR_EOC_MASK, 1);
writel(imr, adc->regs + IMX93_ADC_IMR);
writel(channel, adc->regs + IMX93_ADC_CIMR0);
/* config one-shot mode */
mcr = readl(adc->regs + IMX93_ADC_MCR);
mcr &= ~FIELD_PREP(IMX93_ADC_MCR_MODE_MASK, 1);
writel(mcr, adc->regs + IMX93_ADC_MCR);
/* start normal conversion */
mcr = readl(adc->regs + IMX93_ADC_MCR);
mcr |= FIELD_PREP(IMX93_ADC_MCR_NSTART_MASK, 1);
writel(mcr, adc->regs + IMX93_ADC_MCR);
ret = wait_for_completion_interruptible_timeout(&adc->completion,
IMX93_ADC_TIMEOUT);
if (ret == 0)
return -ETIMEDOUT;
if (ret < 0)
return ret;
pcda = readl(adc->regs + IMX93_ADC_PCDR0 + channel_number * 4);
*result = FIELD_GET(IMX93_ADC_PCDR_CDATA_MASK, pcda);
return ret;
}
static int imx93_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct imx93_adc *adc = iio_priv(indio_dev);
struct device *dev = adc->dev;
long ret;
u32 vref_uv;
switch (mask) {
case IIO_CHAN_INFO_RAW:
pm_runtime_get_sync(dev);
mutex_lock(&adc->lock);
ret = imx93_adc_read_channel_conversion(adc, chan->channel, val);
mutex_unlock(&adc->lock);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_sync_autosuspend(dev);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = vref_uv = regulator_get_voltage(adc->vref);
if (ret < 0)
return ret;
*val = vref_uv / 1000;
*val2 = 12;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = clk_get_rate(adc->ipg_clk);
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static irqreturn_t imx93_adc_isr(int irq, void *dev_id)
{
struct imx93_adc *adc = dev_id;
u32 isr, eoc, unexpected;
isr = readl(adc->regs + IMX93_ADC_ISR);
if (FIELD_GET(IMX93_ADC_ISR_EOC_ECH_MASK, isr)) {
eoc = isr & IMX93_ADC_ISR_EOC_ECH_MASK;
writel(eoc, adc->regs + IMX93_ADC_ISR);
complete(&adc->completion);
}
unexpected = isr & ~IMX93_ADC_ISR_EOC_ECH_MASK;
if (unexpected) {
writel(unexpected, adc->regs + IMX93_ADC_ISR);
dev_err(adc->dev, "Unexpected interrupt 0x%08x.\n", unexpected);
return IRQ_NONE;
}
return IRQ_HANDLED;
}
static const struct iio_info imx93_adc_iio_info = {
.read_raw = &imx93_adc_read_raw,
};
static int imx93_adc_probe(struct platform_device *pdev)
{
struct imx93_adc *adc;
struct iio_dev *indio_dev;
struct device *dev = &pdev->dev;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
if (!indio_dev)
return dev_err_probe(dev, -ENOMEM,
"Failed allocating iio device\n");
adc = iio_priv(indio_dev);
adc->dev = dev;
mutex_init(&adc->lock);
adc->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(adc->regs))
return dev_err_probe(dev, PTR_ERR(adc->regs),
"Failed getting ioremap resource\n");
/* The third irq is for ADC conversion usage */
adc->irq = platform_get_irq(pdev, 2);
if (adc->irq < 0)
return adc->irq;
adc->ipg_clk = devm_clk_get(dev, "ipg");
if (IS_ERR(adc->ipg_clk))
return dev_err_probe(dev, PTR_ERR(adc->ipg_clk),
"Failed getting clock.\n");
adc->vref = devm_regulator_get(dev, "vref");
if (IS_ERR(adc->vref))
return dev_err_probe(dev, PTR_ERR(adc->vref),
"Failed getting reference voltage.\n");
ret = regulator_enable(adc->vref);
if (ret)
return dev_err_probe(dev, ret,
"Failed to enable reference voltage.\n");
platform_set_drvdata(pdev, indio_dev);
init_completion(&adc->completion);
indio_dev->name = "imx93-adc";
indio_dev->info = &imx93_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = imx93_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(imx93_adc_iio_channels);
ret = clk_prepare_enable(adc->ipg_clk);
if (ret) {
dev_err_probe(dev, ret,
"Failed to enable ipg clock.\n");
goto error_regulator_disable;
}
ret = request_irq(adc->irq, imx93_adc_isr, 0, IMX93_ADC_DRIVER_NAME, adc);
if (ret < 0) {
dev_err_probe(dev, ret,
"Failed requesting irq, irq = %d\n", adc->irq);
goto error_ipg_clk_disable;
}
ret = imx93_adc_calibration(adc);
if (ret < 0)
goto error_free_adc_irq;
imx93_adc_config_ad_clk(adc);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err_probe(dev, ret,
"Failed to register this iio device.\n");
goto error_adc_power_down;
}
pm_runtime_set_active(dev);
pm_runtime_set_autosuspend_delay(dev, 50);
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
return 0;
error_adc_power_down:
imx93_adc_power_down(adc);
error_free_adc_irq:
free_irq(adc->irq, adc);
error_ipg_clk_disable:
clk_disable_unprepare(adc->ipg_clk);
error_regulator_disable:
regulator_disable(adc->vref);
return ret;
}
static int imx93_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct imx93_adc *adc = iio_priv(indio_dev);
struct device *dev = adc->dev;
/* adc power down need clock on */
pm_runtime_get_sync(dev);
pm_runtime_disable(dev);
pm_runtime_dont_use_autosuspend(dev);
pm_runtime_put_noidle(dev);
iio_device_unregister(indio_dev);
imx93_adc_power_down(adc);
free_irq(adc->irq, adc);
clk_disable_unprepare(adc->ipg_clk);
regulator_disable(adc->vref);
return 0;
}
static int imx93_adc_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct imx93_adc *adc = iio_priv(indio_dev);
imx93_adc_power_down(adc);
clk_disable_unprepare(adc->ipg_clk);
regulator_disable(adc->vref);
return 0;
}
static int imx93_adc_runtime_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct imx93_adc *adc = iio_priv(indio_dev);
int ret;
ret = regulator_enable(adc->vref);
if (ret) {
dev_err(dev,
"Can't enable adc reference top voltage, err = %d\n",
ret);
return ret;
}
ret = clk_prepare_enable(adc->ipg_clk);
if (ret) {
dev_err(dev, "Could not prepare or enable clock.\n");
goto err_disable_reg;
}
imx93_adc_power_up(adc);
return 0;
err_disable_reg:
regulator_disable(adc->vref);
return ret;
}
static DEFINE_RUNTIME_DEV_PM_OPS(imx93_adc_pm_ops,
imx93_adc_runtime_suspend,
imx93_adc_runtime_resume, NULL);
static const struct of_device_id imx93_adc_match[] = {
{ .compatible = "nxp,imx93-adc", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx93_adc_match);
static struct platform_driver imx93_adc_driver = {
.probe = imx93_adc_probe,
.remove = imx93_adc_remove,
.driver = {
.name = IMX93_ADC_DRIVER_NAME,
.of_match_table = imx93_adc_match,
.pm = pm_ptr(&imx93_adc_pm_ops),
},
};
module_platform_driver(imx93_adc_driver);
MODULE_DESCRIPTION("NXP i.MX93 ADC driver");
MODULE_AUTHOR("Haibo Chen <haibo.chen@nxp.com>");
MODULE_LICENSE("GPL");
......@@ -4,7 +4,6 @@
*
* Copyright 2022 Analog Devices Inc.
*/
#include <asm-generic/unaligned.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/device.h>
......@@ -16,6 +15,8 @@
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <asm/unaligned.h>
#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
......
......@@ -543,6 +543,8 @@ static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = {
SCALE_HW_CALIB_DEFAULT)
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 0,
SCALE_HW_CALIB_XOTHERM)
[ADC5_BAT_ID_100K_PU] = ADC5_CHAN_TEMP("bat_id", 0,
SCALE_HW_CALIB_DEFAULT)
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 0,
......@@ -894,10 +896,8 @@ static int adc5_probe(struct platform_device *pdev)
mutex_init(&adc->lock);
ret = adc5_get_fw_data(adc);
if (ret) {
dev_err(dev, "adc get dt data failed\n");
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "adc get dt data failed\n");
irq_eoc = platform_get_irq(pdev, 0);
if (irq_eoc < 0) {
......
......@@ -6,6 +6,7 @@
* Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com> for STMicroelectronics.
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
......@@ -19,7 +20,15 @@
#include "stm32-dfsdm.h"
/**
* struct stm32_dfsdm_dev_data - DFSDM compatible configuration data
* @ipid: DFSDM identification number. Used only if hardware provides identification registers
* @num_filters: DFSDM number of filters. Unused if identification registers are available
* @num_channels: DFSDM number of channels. Unused if identification registers are available
* @regmap_cfg: SAI register map configuration pointer
*/
struct stm32_dfsdm_dev_data {
u32 ipid;
unsigned int num_filters;
unsigned int num_channels;
const struct regmap_config *regmap_cfg;
......@@ -27,8 +36,6 @@ struct stm32_dfsdm_dev_data {
#define STM32H7_DFSDM_NUM_FILTERS 4
#define STM32H7_DFSDM_NUM_CHANNELS 8
#define STM32MP1_DFSDM_NUM_FILTERS 6
#define STM32MP1_DFSDM_NUM_CHANNELS 8
static bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg)
{
......@@ -75,8 +82,7 @@ static const struct regmap_config stm32mp1_dfsdm_regmap_cfg = {
};
static const struct stm32_dfsdm_dev_data stm32mp1_dfsdm_data = {
.num_filters = STM32MP1_DFSDM_NUM_FILTERS,
.num_channels = STM32MP1_DFSDM_NUM_CHANNELS,
.ipid = STM32MP15_IPIDR_NUMBER,
.regmap_cfg = &stm32mp1_dfsdm_regmap_cfg,
};
......@@ -295,6 +301,65 @@ static const struct of_device_id stm32_dfsdm_of_match[] = {
};
MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match);
static int stm32_dfsdm_probe_identification(struct platform_device *pdev,
struct dfsdm_priv *priv,
const struct stm32_dfsdm_dev_data *dev_data)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
struct stm32_dfsdm *dfsdm = &priv->dfsdm;
const char *compat;
int ret, count = 0;
u32 id, val;
if (!dev_data->ipid) {
dfsdm->num_fls = dev_data->num_filters;
dfsdm->num_chs = dev_data->num_channels;
return 0;
}
ret = regmap_read(dfsdm->regmap, DFSDM_IPIDR, &id);
if (ret)
return ret;
if (id != dev_data->ipid) {
dev_err(&pdev->dev, "Unexpected IP version: 0x%x", id);
return -EINVAL;
}
for_each_child_of_node(np, child) {
ret = of_property_read_string(child, "compatible", &compat);
if (ret)
continue;
/* Count only child nodes with dfsdm compatible */
if (strstr(compat, "dfsdm"))
count++;
}
ret = regmap_read(dfsdm->regmap, DFSDM_HWCFGR, &val);
if (ret)
return ret;
dfsdm->num_fls = FIELD_GET(DFSDM_HWCFGR_NBF_MASK, val);
dfsdm->num_chs = FIELD_GET(DFSDM_HWCFGR_NBT_MASK, val);
if (count > dfsdm->num_fls) {
dev_err(&pdev->dev, "Unexpected child number: %d", count);
return -EINVAL;
}
ret = regmap_read(dfsdm->regmap, DFSDM_VERR, &val);
if (ret)
return ret;
dev_dbg(&pdev->dev, "DFSDM version: %lu.%lu. %d channels/%d filters\n",
FIELD_GET(DFSDM_VERR_MAJREV_MASK, val),
FIELD_GET(DFSDM_VERR_MINREV_MASK, val),
dfsdm->num_chs, dfsdm->num_fls);
return 0;
}
static int stm32_dfsdm_probe(struct platform_device *pdev)
{
struct dfsdm_priv *priv;
......@@ -311,18 +376,6 @@ static int stm32_dfsdm_probe(struct platform_device *pdev)
dev_data = of_device_get_match_data(&pdev->dev);
dfsdm = &priv->dfsdm;
dfsdm->fl_list = devm_kcalloc(&pdev->dev, dev_data->num_filters,
sizeof(*dfsdm->fl_list), GFP_KERNEL);
if (!dfsdm->fl_list)
return -ENOMEM;
dfsdm->num_fls = dev_data->num_filters;
dfsdm->ch_list = devm_kcalloc(&pdev->dev, dev_data->num_channels,
sizeof(*dfsdm->ch_list),
GFP_KERNEL);
if (!dfsdm->ch_list)
return -ENOMEM;
dfsdm->num_chs = dev_data->num_channels;
ret = stm32_dfsdm_parse_of(pdev, priv);
if (ret < 0)
......@@ -338,6 +391,20 @@ static int stm32_dfsdm_probe(struct platform_device *pdev)
return ret;
}
ret = stm32_dfsdm_probe_identification(pdev, priv, dev_data);
if (ret < 0)
return ret;
dfsdm->fl_list = devm_kcalloc(&pdev->dev, dfsdm->num_fls,
sizeof(*dfsdm->fl_list), GFP_KERNEL);
if (!dfsdm->fl_list)
return -ENOMEM;
dfsdm->ch_list = devm_kcalloc(&pdev->dev, dfsdm->num_chs,
sizeof(*dfsdm->ch_list), GFP_KERNEL);
if (!dfsdm->ch_list)
return -ENOMEM;
platform_set_drvdata(pdev, dfsdm);
ret = stm32_dfsdm_clk_prepare_enable(dfsdm);
......
......@@ -13,25 +13,29 @@
/*
* STM32 DFSDM - global register map
* ________________________________________________________
* | Offset | Registers block |
* --------------------------------------------------------
* | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS |
* --------------------------------------------------------
* | 0x020 | CHANNEL 1 |
* --------------------------------------------------------
* | ... | ..... |
* --------------------------------------------------------
* | 0x0E0 | CHANNEL 7 |
* --------------------------------------------------------
* | 0x100 | FILTER 0 + COMMON FILTER FIELDs |
* --------------------------------------------------------
* | 0x200 | FILTER 1 |
* --------------------------------------------------------
* | 0x300 | FILTER 2 |
* --------------------------------------------------------
* | 0x400 | FILTER 3 |
* --------------------------------------------------------
* __________________________________________________________
* | Offset | Registers block |
* ----------------------------------------------------------
* | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS |
* ----------------------------------------------------------
* | 0x020 | CHANNEL 1 |
* ----------------------------------------------------------
* | ... | ..... |
* ----------------------------------------------------------
* | 0x20 x n | CHANNEL n |
* ----------------------------------------------------------
* | 0x100 | FILTER 0 + COMMON FILTER FIELDs |
* ----------------------------------------------------------
* | 0x200 | FILTER 1 |
* ----------------------------------------------------------
* | | ..... |
* ----------------------------------------------------------
* | 0x100 x m | FILTER m |
* ----------------------------------------------------------
* | | ..... |
* ----------------------------------------------------------
* | 0x7F0-7FC | Identification registers |
* ----------------------------------------------------------
*/
/*
......@@ -231,6 +235,24 @@
#define DFSDM_AWCFR_AWHTF_MASK GENMASK(15, 8)
#define DFSDM_AWCFR_AWHTF(v) FIELD_PREP(DFSDM_AWCFR_AWHTF_MASK, v)
/*
* Identification register definitions
*/
#define DFSDM_HWCFGR 0x7F0
#define DFSDM_VERR 0x7F4
#define DFSDM_IPIDR 0x7F8
#define DFSDM_SIDR 0x7FC
/* HWCFGR: Hardware configuration register */
#define DFSDM_HWCFGR_NBT_MASK GENMASK(7, 0)
#define DFSDM_HWCFGR_NBF_MASK GENMASK(15, 8)
/* VERR: Version register */
#define DFSDM_VERR_MINREV_MASK GENMASK(3, 0)
#define DFSDM_VERR_MAJREV_MASK GENMASK(7, 4)
#define STM32MP15_IPIDR_NUMBER 0x00110031
/* DFSDM filter order */
enum stm32_dfsdm_sinc_order {
DFSDM_FASTSINC_ORDER, /* FastSinc filter type */
......
......@@ -9,14 +9,13 @@
* https://www.ti.com/lit/ds/symlink/adc124s021.pdf
*/
#include <linux/acpi.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
struct adc128_configuration {
const struct iio_chan_spec *channels;
......@@ -139,16 +138,11 @@ static void adc128_disable_regulator(void *reg)
static int adc128_probe(struct spi_device *spi)
{
const struct adc128_configuration *config;
struct iio_dev *indio_dev;
unsigned int config;
struct adc128 *adc;
int ret;
if (dev_fwnode(&spi->dev))
config = (unsigned long) device_get_match_data(&spi->dev);
else
config = spi_get_device_id(spi)->driver_data;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
......@@ -160,8 +154,10 @@ static int adc128_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &adc128_info;
indio_dev->channels = adc128_config[config].channels;
indio_dev->num_channels = adc128_config[config].num_channels;
config = spi_get_device_match_data(spi);
indio_dev->channels = config->channels;
indio_dev->num_channels = config->num_channels;
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
......@@ -181,42 +177,40 @@ static int adc128_probe(struct spi_device *spi)
}
static const struct of_device_id adc128_of_match[] = {
{ .compatible = "ti,adc128s052", .data = (void*)0L, },
{ .compatible = "ti,adc122s021", .data = (void*)1L, },
{ .compatible = "ti,adc122s051", .data = (void*)1L, },
{ .compatible = "ti,adc122s101", .data = (void*)1L, },
{ .compatible = "ti,adc124s021", .data = (void*)2L, },
{ .compatible = "ti,adc124s051", .data = (void*)2L, },
{ .compatible = "ti,adc124s101", .data = (void*)2L, },
{ .compatible = "ti,adc128s052", .data = &adc128_config[0] },
{ .compatible = "ti,adc122s021", .data = &adc128_config[1] },
{ .compatible = "ti,adc122s051", .data = &adc128_config[1] },
{ .compatible = "ti,adc122s101", .data = &adc128_config[1] },
{ .compatible = "ti,adc124s021", .data = &adc128_config[2] },
{ .compatible = "ti,adc124s051", .data = &adc128_config[2] },
{ .compatible = "ti,adc124s101", .data = &adc128_config[2] },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, adc128_of_match);
static const struct spi_device_id adc128_id[] = {
{ "adc128s052", 0 }, /* index into adc128_config */
{ "adc122s021", 1 },
{ "adc122s051", 1 },
{ "adc122s101", 1 },
{ "adc124s021", 2 },
{ "adc124s051", 2 },
{ "adc124s101", 2 },
{ "adc128s052", (kernel_ulong_t)&adc128_config[0] },
{ "adc122s021", (kernel_ulong_t)&adc128_config[1] },
{ "adc122s051", (kernel_ulong_t)&adc128_config[1] },
{ "adc122s101", (kernel_ulong_t)&adc128_config[1] },
{ "adc124s021", (kernel_ulong_t)&adc128_config[2] },
{ "adc124s051", (kernel_ulong_t)&adc128_config[2] },
{ "adc124s101", (kernel_ulong_t)&adc128_config[2] },
{ }
};
MODULE_DEVICE_TABLE(spi, adc128_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id adc128_acpi_match[] = {
{ "AANT1280", 2 }, /* ADC124S021 compatible ACPI ID */
{ "AANT1280", (kernel_ulong_t)&adc128_config[2] },
{ }
};
MODULE_DEVICE_TABLE(acpi, adc128_acpi_match);
#endif
static struct spi_driver adc128_driver = {
.driver = {
.name = "adc128s052",
.of_match_table = adc128_of_match,
.acpi_match_table = ACPI_PTR(adc128_acpi_match),
.acpi_match_table = adc128_acpi_match,
},
.probe = adc128_probe,
.id_table = adc128_id,
......
// SPDX-License-Identifier: GPL-2.0
/*
* IIO driver for Texas Instruments ADS7924 ADC, 12-bit, 4-Channels, I2C
*
* Author: Hugo Villeneuve <hvilleneuve@dimonoff.com>
* Copyright 2022 DimOnOff
*
* based on iio/adc/ti-ads1015.c
* Copyright (c) 2016, Intel Corporation.
*
* Datasheet: https://www.ti.com/lit/gpn/ads7924
*/
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#define ADS7924_CHANNELS 4
#define ADS7924_BITS 12
#define ADS7924_DATA_SHIFT 4
/* Registers. */
#define ADS7924_MODECNTRL_REG 0x00
#define ADS7924_INTCNTRL_REG 0x01
#define ADS7924_DATA0_U_REG 0x02
#define ADS7924_DATA0_L_REG 0x03
#define ADS7924_DATA1_U_REG 0x04
#define ADS7924_DATA1_L_REG 0x05
#define ADS7924_DATA2_U_REG 0x06
#define ADS7924_DATA2_L_REG 0x07
#define ADS7924_DATA3_U_REG 0x08
#define ADS7924_DATA3_L_REG 0x09
#define ADS7924_ULR0_REG 0x0A
#define ADS7924_LLR0_REG 0x0B
#define ADS7924_ULR1_REG 0x0C
#define ADS7924_LLR1_REG 0x0D
#define ADS7924_ULR2_REG 0x0E
#define ADS7924_LLR2_REG 0x0F
#define ADS7924_ULR3_REG 0x10
#define ADS7924_LLR3_REG 0x11
#define ADS7924_INTCONFIG_REG 0x12
#define ADS7924_SLPCONFIG_REG 0x13
#define ADS7924_ACQCONFIG_REG 0x14
#define ADS7924_PWRCONFIG_REG 0x15
#define ADS7924_RESET_REG 0x16
/*
* Register address INC bit: when set to '1', the register address is
* automatically incremented after every register read which allows convenient
* reading of multiple registers. Set INC to '0' when reading a single register.
*/
#define ADS7924_AUTO_INCREMENT_BIT BIT(7)
#define ADS7924_MODECNTRL_MODE_MASK GENMASK(7, 2)
#define ADS7924_MODECNTRL_SEL_MASK GENMASK(1, 0)
#define ADS7924_CFG_INTPOL_BIT 1
#define ADS7924_CFG_INTTRIG_BIT 0
#define ADS7924_CFG_INTPOL_MASK BIT(ADS7924_CFG_INTPOL_BIT)
#define ADS7924_CFG_INTTRIG_MASK BIT(ADS7924_CFG_INTTRIG_BIT)
/* Interrupt pin polarity */
#define ADS7924_CFG_INTPOL_LOW 0
#define ADS7924_CFG_INTPOL_HIGH 1
/* Interrupt pin signaling */
#define ADS7924_CFG_INTTRIG_LEVEL 0
#define ADS7924_CFG_INTTRIG_EDGE 1
/* Mode control values */
#define ADS7924_MODECNTRL_IDLE 0x00
#define ADS7924_MODECNTRL_AWAKE 0x20
#define ADS7924_MODECNTRL_MANUAL_SINGLE 0x30
#define ADS7924_MODECNTRL_MANUAL_SCAN 0x32
#define ADS7924_MODECNTRL_AUTO_SINGLE 0x31
#define ADS7924_MODECNTRL_AUTO_SCAN 0x33
#define ADS7924_MODECNTRL_AUTO_SINGLE_SLEEP 0x39
#define ADS7924_MODECNTRL_AUTO_SCAN_SLEEP 0x3B
#define ADS7924_MODECNTRL_AUTO_BURST_SLEEP 0x3F
#define ADS7924_ACQTIME_MASK GENMASK(4, 0)
#define ADS7924_PWRUPTIME_MASK GENMASK(4, 0)
/*
* The power-up time is allowed to elapse whenever the device has been shutdown
* in idle mode. Power-up time can allow external circuits, such as an
* operational amplifier, between the MUXOUT and ADCIN pins to turn on.
* The nominal time programmed by the PUTIME[4:0] register bits is given by:
* t PU = PWRUPTIME[4:0] × 2 μs
* If a power-up time is not required, set the bits to '0' to effectively bypass.
*/
#define ADS7924_PWRUPTIME_US 0 /* Bypass (0us). */
/*
* Acquisition Time according to ACQTIME[4:0] register bits.
* The Acquisition Time is given by:
* t ACQ = (ACQTIME[4:0] × 2 μs) + 6 μs
* Using default value of 0 for ACQTIME[4:0] results in a minimum acquisition
* time of 6us.
*/
#define ADS7924_ACQTIME_US 6
/* The conversion time is always 4μs and cannot be programmed by the user. */
#define ADS7924_CONVTIME_US 4
#define ADS7924_TOTAL_CONVTIME_US (ADS7924_PWRUPTIME_US + ADS7924_ACQTIME_US + \
ADS7924_CONVTIME_US)
#define ADS7924_V_CHAN(_chan, _addr) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _chan, \
.address = _addr, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = "AIN"#_chan, \
}
struct ads7924_data {
struct device *dev;
struct regmap *regmap;
struct regulator *vref_reg;
/* GPIO descriptor for device hard-reset pin. */
struct gpio_desc *reset_gpio;
/*
* Protects ADC ops, e.g: concurrent sysfs/buffered
* data reads, configuration updates
*/
struct mutex lock;
/*
* Set to true when the ADC is switched to the continuous-conversion
* mode and exits from a power-down state. This flag is used to avoid
* getting the stale result from the conversion register.
*/
bool conv_invalid;
};
static bool ads7924_is_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case ADS7924_MODECNTRL_REG:
case ADS7924_INTCNTRL_REG:
case ADS7924_ULR0_REG:
case ADS7924_LLR0_REG:
case ADS7924_ULR1_REG:
case ADS7924_LLR1_REG:
case ADS7924_ULR2_REG:
case ADS7924_LLR2_REG:
case ADS7924_ULR3_REG:
case ADS7924_LLR3_REG:
case ADS7924_INTCONFIG_REG:
case ADS7924_SLPCONFIG_REG:
case ADS7924_ACQCONFIG_REG:
case ADS7924_PWRCONFIG_REG:
case ADS7924_RESET_REG:
return true;
default:
return false;
}
}
static const struct regmap_config ads7924_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ADS7924_RESET_REG,
.writeable_reg = ads7924_is_writeable_reg,
};
static const struct iio_chan_spec ads7924_channels[] = {
ADS7924_V_CHAN(0, ADS7924_DATA0_U_REG),
ADS7924_V_CHAN(1, ADS7924_DATA1_U_REG),
ADS7924_V_CHAN(2, ADS7924_DATA2_U_REG),
ADS7924_V_CHAN(3, ADS7924_DATA3_U_REG),
};
static int ads7924_get_adc_result(struct ads7924_data *data,
struct iio_chan_spec const *chan, int *val)
{
int ret;
__be16 be_val;
if (chan->channel < 0 || chan->channel >= ADS7924_CHANNELS)
return -EINVAL;
if (data->conv_invalid) {
int conv_time;
conv_time = ADS7924_TOTAL_CONVTIME_US;
/* Allow 10% for internal clock inaccuracy. */
conv_time += conv_time / 10;
usleep_range(conv_time, conv_time + 1);
data->conv_invalid = false;
}
ret = regmap_raw_read(data->regmap, ADS7924_AUTO_INCREMENT_BIT |
chan->address, &be_val, sizeof(be_val));
if (ret)
return ret;
*val = be16_to_cpu(be_val) >> ADS7924_DATA_SHIFT;
return 0;
}
static int ads7924_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
int ret, vref_uv;
struct ads7924_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->lock);
ret = ads7924_get_adc_result(data, chan, val);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
vref_uv = regulator_get_voltage(data->vref_reg);
if (vref_uv < 0)
return vref_uv;
*val = vref_uv / 1000; /* Convert reg voltage to mV */
*val2 = ADS7924_BITS;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static const struct iio_info ads7924_info = {
.read_raw = ads7924_read_raw,
};
static int ads7924_get_channels_config(struct i2c_client *client,
struct iio_dev *indio_dev)
{
struct ads7924_data *priv = iio_priv(indio_dev);
struct device *dev = priv->dev;
struct fwnode_handle *node;
int num_channels = 0;
device_for_each_child_node(dev, node) {
u32 pval;
unsigned int channel;
if (fwnode_property_read_u32(node, "reg", &pval)) {
dev_err(dev, "invalid reg on %pfw\n", node);
continue;
}
channel = pval;
if (channel >= ADS7924_CHANNELS) {
dev_err(dev, "invalid channel index %d on %pfw\n",
channel, node);
continue;
}
num_channels++;
}
if (!num_channels)
return -EINVAL;
return 0;
}
static int ads7924_set_conv_mode(struct ads7924_data *data, int mode)
{
int ret;
unsigned int mode_field;
struct device *dev = data->dev;
/*
* When switching between modes, be sure to first select the Awake mode
* and then switch to the desired mode. This procedure ensures the
* internal control logic is properly synchronized.
*/
if (mode != ADS7924_MODECNTRL_IDLE) {
mode_field = FIELD_PREP(ADS7924_MODECNTRL_MODE_MASK,
ADS7924_MODECNTRL_AWAKE);
ret = regmap_update_bits(data->regmap, ADS7924_MODECNTRL_REG,
ADS7924_MODECNTRL_MODE_MASK,
mode_field);
if (ret) {
dev_err(dev, "failed to set awake mode (%pe)\n",
ERR_PTR(ret));
return ret;
}
}
mode_field = FIELD_PREP(ADS7924_MODECNTRL_MODE_MASK, mode);
ret = regmap_update_bits(data->regmap, ADS7924_MODECNTRL_REG,
ADS7924_MODECNTRL_MODE_MASK, mode_field);
if (ret)
dev_err(dev, "failed to set mode %d (%pe)\n", mode,
ERR_PTR(ret));
return ret;
}
static int ads7924_reset(struct iio_dev *indio_dev)
{
struct ads7924_data *data = iio_priv(indio_dev);
if (data->reset_gpio) {
gpiod_set_value(data->reset_gpio, 1); /* Assert. */
/* Educated guess: assert time not specified in datasheet... */
mdelay(100);
gpiod_set_value(data->reset_gpio, 0); /* Deassert. */
return 0;
}
/*
* A write of 10101010 to this register will generate a
* software reset of the ADS7924.
*/
return regmap_write(data->regmap, ADS7924_RESET_REG, 0b10101010);
};
static void ads7924_reg_disable(void *data)
{
regulator_disable(data);
}
static void ads7924_set_idle_mode(void *data)
{
ads7924_set_conv_mode(data, ADS7924_MODECNTRL_IDLE);
}
static int ads7924_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct ads7924_data *data;
struct device *dev = &client->dev;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return dev_err_probe(dev, -ENOMEM,
"failed to allocate iio device\n");
data = iio_priv(indio_dev);
data->dev = dev;
/* Initialize the reset GPIO as output with an initial value of 0. */
data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(data->reset_gpio))
return dev_err_probe(dev, PTR_ERR(data->reset_gpio),
"failed to get request reset GPIO\n");
mutex_init(&data->lock);
indio_dev->name = "ads7924";
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ads7924_channels;
indio_dev->num_channels = ARRAY_SIZE(ads7924_channels);
indio_dev->info = &ads7924_info;
ret = ads7924_get_channels_config(client, indio_dev);
if (ret < 0)
return dev_err_probe(dev, ret,
"failed to get channels configuration\n");
data->regmap = devm_regmap_init_i2c(client, &ads7924_regmap_config);
if (IS_ERR(data->regmap))
return dev_err_probe(dev, PTR_ERR(data->regmap),
"failed to init regmap\n");
data->vref_reg = devm_regulator_get(dev, "vref");
if (IS_ERR(data->vref_reg))
return dev_err_probe(dev, PTR_ERR(data->vref_reg),
"failed to get vref regulator\n");
ret = regulator_enable(data->vref_reg);
if (ret)
return dev_err_probe(dev, ret,
"failed to enable regulator\n");
ret = devm_add_action_or_reset(dev, ads7924_reg_disable, data->vref_reg);
if (ret)
return dev_err_probe(dev, ret,
"failed to add regulator disable action\n");
ret = ads7924_reset(indio_dev);
if (ret < 0)
return dev_err_probe(dev, ret,
"failed to reset device\n");
ret = ads7924_set_conv_mode(data, ADS7924_MODECNTRL_AUTO_SCAN);
if (ret)
return dev_err_probe(dev, ret,
"failed to set conversion mode\n");
ret = devm_add_action_or_reset(dev, ads7924_set_idle_mode, data);
if (ret)
return dev_err_probe(dev, ret,
"failed to add idle mode action\n");
/* Use minimum signal acquire time. */
ret = regmap_update_bits(data->regmap, ADS7924_ACQCONFIG_REG,
ADS7924_ACQTIME_MASK,
FIELD_PREP(ADS7924_ACQTIME_MASK, 0));
if (ret < 0)
return dev_err_probe(dev, ret,
"failed to configure signal acquire time\n");
/* Disable power-up time. */
ret = regmap_update_bits(data->regmap, ADS7924_PWRCONFIG_REG,
ADS7924_PWRUPTIME_MASK,
FIELD_PREP(ADS7924_PWRUPTIME_MASK, 0));
if (ret < 0)
return dev_err_probe(dev, ret,
"failed to configure power-up time\n");
data->conv_invalid = true;
ret = devm_iio_device_register(dev, indio_dev);
if (ret < 0)
return dev_err_probe(dev, ret,
"failed to register IIO device\n");
return 0;
}
static const struct i2c_device_id ads7924_id[] = {
{ "ads7924", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, ads7924_id);
static const struct of_device_id ads7924_of_match[] = {
{ .compatible = "ti,ads7924", },
{}
};
MODULE_DEVICE_TABLE(of, ads7924_of_match);
static struct i2c_driver ads7924_driver = {
.driver = {
.name = "ads7924",
.of_match_table = ads7924_of_match,
},
.probe_new = ads7924_probe,
.id_table = ads7924_id,
};
module_i2c_driver(ads7924_driver);
MODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@dimonoff.com>");
MODULE_DESCRIPTION("Texas Instruments ADS7924 ADC I2C driver");
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0
/*
* Texas Instruments LMP92064 SPI ADC driver
*
* Copyright (c) 2022 Leonard Göhrs <kernel@pengutronix.de>, Pengutronix
*
* Based on linux/drivers/iio/adc/ti-tsc2046.c
* Copyright (c) 2021 Oleksij Rempel <kernel@pengutronix.de>, Pengutronix
*/
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#define TI_LMP92064_REG_CONFIG_A 0x0000
#define TI_LMP92064_REG_CONFIG_B 0x0001
#define TI_LMP92064_REG_CHIP_REV 0x0006
#define TI_LMP92064_REG_MFR_ID1 0x000C
#define TI_LMP92064_REG_MFR_ID2 0x000D
#define TI_LMP92064_REG_REG_UPDATE 0x000F
#define TI_LMP92064_REG_CONFIG_REG 0x0100
#define TI_LMP92064_REG_STATUS 0x0103
#define TI_LMP92064_REG_DATA_VOUT_LSB 0x0200
#define TI_LMP92064_REG_DATA_VOUT_MSB 0x0201
#define TI_LMP92064_REG_DATA_COUT_LSB 0x0202
#define TI_LMP92064_REG_DATA_COUT_MSB 0x0203
#define TI_LMP92064_VAL_CONFIG_A 0x99
#define TI_LMP92064_VAL_CONFIG_B 0x00
#define TI_LMP92064_VAL_STATUS_OK 0x01
/*
* Channel number definitions for the two channels of the device
* - IN Current (INC)
* - IN Voltage (INV)
*/
#define TI_LMP92064_CHAN_INC 0
#define TI_LMP92064_CHAN_INV 1
static const struct regmap_range lmp92064_readable_reg_ranges[] = {
regmap_reg_range(TI_LMP92064_REG_CONFIG_A, TI_LMP92064_REG_CHIP_REV),
regmap_reg_range(TI_LMP92064_REG_MFR_ID1, TI_LMP92064_REG_MFR_ID2),
regmap_reg_range(TI_LMP92064_REG_REG_UPDATE, TI_LMP92064_REG_REG_UPDATE),
regmap_reg_range(TI_LMP92064_REG_CONFIG_REG, TI_LMP92064_REG_CONFIG_REG),
regmap_reg_range(TI_LMP92064_REG_STATUS, TI_LMP92064_REG_STATUS),
regmap_reg_range(TI_LMP92064_REG_DATA_VOUT_LSB, TI_LMP92064_REG_DATA_COUT_MSB),
};
static const struct regmap_access_table lmp92064_readable_regs = {
.yes_ranges = lmp92064_readable_reg_ranges,
.n_yes_ranges = ARRAY_SIZE(lmp92064_readable_reg_ranges),
};
static const struct regmap_range lmp92064_writable_reg_ranges[] = {
regmap_reg_range(TI_LMP92064_REG_CONFIG_A, TI_LMP92064_REG_CONFIG_B),
regmap_reg_range(TI_LMP92064_REG_REG_UPDATE, TI_LMP92064_REG_REG_UPDATE),
regmap_reg_range(TI_LMP92064_REG_CONFIG_REG, TI_LMP92064_REG_CONFIG_REG),
};
static const struct regmap_access_table lmp92064_writable_regs = {
.yes_ranges = lmp92064_writable_reg_ranges,
.n_yes_ranges = ARRAY_SIZE(lmp92064_writable_reg_ranges),
};
static const struct regmap_config lmp92064_spi_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.max_register = TI_LMP92064_REG_DATA_COUT_MSB,
.rd_table = &lmp92064_readable_regs,
.wr_table = &lmp92064_writable_regs,
};
struct lmp92064_adc_priv {
int shunt_resistor_uohm;
struct spi_device *spi;
struct regmap *regmap;
};
static const struct iio_chan_spec lmp92064_adc_channels[] = {
{
.type = IIO_CURRENT,
.address = TI_LMP92064_CHAN_INC,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.datasheet_name = "INC",
},
{
.type = IIO_VOLTAGE,
.address = TI_LMP92064_CHAN_INV,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.datasheet_name = "INV",
},
};
static int lmp92064_read_meas(struct lmp92064_adc_priv *priv, u16 *res)
{
__be16 raw[2];
int ret;
/*
* The ADC only latches in new samples if all DATA registers are read
* in descending sequential order.
* The ADC auto-decrements the register index with each clocked byte.
* Read both channels in single SPI transfer by selecting the highest
* register using the command below and clocking out all four data
* bytes.
*/
ret = regmap_bulk_read(priv->regmap, TI_LMP92064_REG_DATA_COUT_MSB,
&raw, sizeof(raw));
if (ret) {
dev_err(&priv->spi->dev, "regmap_bulk_read failed: %pe\n",
ERR_PTR(ret));
return ret;
}
res[0] = be16_to_cpu(raw[0]);
res[1] = be16_to_cpu(raw[1]);
return 0;
}
static int lmp92064_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct lmp92064_adc_priv *priv = iio_priv(indio_dev);
u16 raw[2];
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = lmp92064_read_meas(priv, raw);
if (ret < 0)
return ret;
*val = (chan->address == TI_LMP92064_CHAN_INC) ? raw[0] : raw[1];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (chan->address == TI_LMP92064_CHAN_INC) {
/*
* processed (mA) = raw * current_lsb (mA)
* current_lsb (mA) = shunt_voltage_lsb (nV) / shunt_resistor (uOhm)
* shunt_voltage_lsb (nV) = 81920000 / 4096 = 20000
*/
*val = 20000;
*val2 = priv->shunt_resistor_uohm;
} else {
/*
* processed (mV) = raw * voltage_lsb (mV)
* voltage_lsb (mV) = 2048 / 4096
*/
*val = 2048;
*val2 = 4096;
}
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
}
static int lmp92064_reset(struct lmp92064_adc_priv *priv,
struct gpio_desc *gpio_reset)
{
unsigned int status;
int ret, i;
if (gpio_reset) {
/*
* Perform a hard reset if gpio_reset is available.
* The datasheet specifies a very low 3.5ns reset pulse duration and does not
* specify how long to wait after a reset to access the device.
* Use more conservative pulse lengths to allow analog RC filtering of the
* reset line at the board level (as recommended in the datasheet).
*/
gpiod_set_value_cansleep(gpio_reset, 1);
usleep_range(1, 10);
gpiod_set_value_cansleep(gpio_reset, 0);
usleep_range(500, 750);
} else {
/*
* Perform a soft-reset if not.
* Also write default values to the config registers that are not
* affected by soft reset.
*/
ret = regmap_write(priv->regmap, TI_LMP92064_REG_CONFIG_A,
TI_LMP92064_VAL_CONFIG_A);
if (ret < 0)
return ret;
ret = regmap_write(priv->regmap, TI_LMP92064_REG_CONFIG_B,
TI_LMP92064_VAL_CONFIG_B);
if (ret < 0)
return ret;
}
/*
* Wait for the device to signal readiness to prevent reading bogus data
* and make sure device is actually connected.
* The datasheet does not specify how long this takes but usually it is
* not more than 3-4 iterations of this loop.
*/
for (i = 0; i < 10; i++) {
ret = regmap_read(priv->regmap, TI_LMP92064_REG_STATUS, &status);
if (ret < 0)
return ret;
if (status == TI_LMP92064_VAL_STATUS_OK)
return 0;
usleep_range(1000, 2000);
}
/*
* No (correct) response received.
* Device is mostly likely not connected to the bus.
*/
return -ENXIO;
}
static const struct iio_info lmp92064_adc_info = {
.read_raw = lmp92064_read_raw,
};
static int lmp92064_adc_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct lmp92064_adc_priv *priv;
struct gpio_desc *gpio_reset;
struct iio_dev *indio_dev;
u32 shunt_resistor_uohm;
struct regmap *regmap;
int ret;
ret = spi_setup(spi);
if (ret < 0)
return dev_err_probe(dev, ret, "Error in SPI setup\n");
regmap = devm_regmap_init_spi(spi, &lmp92064_spi_regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to set up SPI regmap\n");
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
priv = iio_priv(indio_dev);
priv->spi = spi;
priv->regmap = regmap;
ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms",
&shunt_resistor_uohm);
if (ret < 0)
return dev_err_probe(dev, ret,
"Failed to get shunt-resistor value\n");
/*
* The shunt resistance is passed to userspace as the denominator of an iio
* fraction. Make sure it is in range for that.
*/
if (shunt_resistor_uohm == 0 || shunt_resistor_uohm > INT_MAX) {
dev_err(dev, "Shunt resistance is out of range\n");
return -EINVAL;
}
priv->shunt_resistor_uohm = shunt_resistor_uohm;
ret = devm_regulator_get_enable(dev, "vdd");
if (ret)
return ret;
ret = devm_regulator_get_enable(dev, "vdig");
if (ret)
return ret;
gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpio_reset))
return dev_err_probe(dev, PTR_ERR(gpio_reset),
"Failed to get GPIO reset pin\n");
ret = lmp92064_reset(priv, gpio_reset);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to reset device\n");
indio_dev->name = "lmp92064";
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = lmp92064_adc_channels;
indio_dev->num_channels = ARRAY_SIZE(lmp92064_adc_channels);
indio_dev->info = &lmp92064_adc_info;
return devm_iio_device_register(dev, indio_dev);
}
static const struct spi_device_id lmp92064_id_table[] = {
{ "lmp92064" },
{}
};
MODULE_DEVICE_TABLE(spi, lmp92064_id_table);
static const struct of_device_id lmp92064_of_table[] = {
{ .compatible = "ti,lmp92064" },
{}
};
MODULE_DEVICE_TABLE(of, lmp92064_of_table);
static struct spi_driver lmp92064_adc_driver = {
.driver = {
.name = "lmp92064",
.of_match_table = lmp92064_of_table,
},
.probe = lmp92064_adc_probe,
.id_table = lmp92064_id_table,
};
module_spi_driver(lmp92064_adc_driver);
MODULE_AUTHOR("Leonard Göhrs <kernel@pengutronix.de>");
MODULE_DESCRIPTION("TI LMP92064 ADC");
MODULE_LICENSE("GPL");
......@@ -1220,8 +1220,7 @@ static int ams_init_module(struct iio_dev *indio_dev,
int num_channels = 0;
int ret;
if (fwnode_property_match_string(fwnode, "compatible",
"xlnx,zynqmp-ams-ps") == 0) {
if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams-ps")) {
ams->ps_base = fwnode_iomap(fwnode, 0);
if (!ams->ps_base)
return -ENXIO;
......@@ -1232,8 +1231,7 @@ static int ams_init_module(struct iio_dev *indio_dev,
/* add PS channels to iio device channels */
memcpy(channels, ams_ps_channels, sizeof(ams_ps_channels));
num_channels = ARRAY_SIZE(ams_ps_channels);
} else if (fwnode_property_match_string(fwnode, "compatible",
"xlnx,zynqmp-ams-pl") == 0) {
} else if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams-pl")) {
ams->pl_base = fwnode_iomap(fwnode, 0);
if (!ams->pl_base)
return -ENXIO;
......@@ -1247,8 +1245,7 @@ static int ams_init_module(struct iio_dev *indio_dev,
num_channels += AMS_PL_MAX_FIXED_CHANNEL;
num_channels = ams_get_ext_chan(fwnode, channels,
num_channels);
} else if (fwnode_property_match_string(fwnode, "compatible",
"xlnx,zynqmp-ams") == 0) {
} else if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams")) {
/* add AMS channels to iio device channels */
memcpy(channels, ams_ctrl_channels, sizeof(ams_ctrl_channels));
num_channels += ARRAY_SIZE(ams_ctrl_channels);
......
......@@ -285,8 +285,7 @@ static int ad7746_select_channel(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
if (chip->capdac_set != chan->channel)
chip->capdac_set = chan->channel;
chip->capdac_set = chan->channel;
break;
case IIO_VOLTAGE:
case IIO_TEMP:
......
......@@ -354,7 +354,7 @@ static ssize_t sampling_frequency_available_show(struct device *dev, struct devi
ssize_t len = 0;
do {
len += scnprintf(buf + len, PAGE_SIZE - len, "0.%09u ", 1000000000 / i);
len += sysfs_emit_at(buf, len, "0.%09u ", 1000000000 / i);
/*
* Not all values fit PAGE_SIZE buffer hence print every 6th
* (each frequency differs by 6s in time domain from the
......@@ -380,7 +380,7 @@ static ssize_t calibration_auto_enable_show(struct device *dev, struct device_at
ret = scd30_command_read(state, CMD_ASC, &val);
mutex_unlock(&state->lock);
return ret ?: sprintf(buf, "%d\n", val);
return ret ?: sysfs_emit(buf, "%d\n", val);
}
static ssize_t calibration_auto_enable_store(struct device *dev, struct device_attribute *attr,
......@@ -414,7 +414,7 @@ static ssize_t calibration_forced_value_show(struct device *dev, struct device_a
ret = scd30_command_read(state, CMD_FRC, &val);
mutex_unlock(&state->lock);
return ret ?: sprintf(buf, "%d\n", val);
return ret ?: sysfs_emit(buf, "%d\n", val);
}
static ssize_t calibration_forced_value_store(struct device *dev, struct device_attribute *attr,
......@@ -642,10 +642,8 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev)
trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
iio_device_id(indio_dev));
if (!trig) {
dev_err(dev, "failed to allocate trigger\n");
return -ENOMEM;
}
if (!trig)
return dev_err_probe(dev, -ENOMEM, "failed to allocate trigger\n");
trig->ops = &scd30_trigger_ops;
iio_trigger_set_drvdata(trig, indio_dev);
......@@ -667,9 +665,9 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev)
IRQF_NO_AUTOEN,
indio_dev->name, indio_dev);
if (ret)
dev_err(dev, "failed to request irq\n");
return dev_err_probe(dev, ret, "failed to request irq\n");
return ret;
return 0;
}
int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
......@@ -717,17 +715,13 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
return ret;
ret = scd30_reset(state);
if (ret) {
dev_err(dev, "failed to reset device: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "failed to reset device\n");
if (state->irq > 0) {
ret = scd30_setup_trigger(indio_dev);
if (ret) {
dev_err(dev, "failed to setup trigger: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "failed to setup trigger\n");
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, scd30_trigger_handler, NULL);
......@@ -735,23 +729,17 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
return ret;
ret = scd30_command_read(state, CMD_FW_VERSION, &val);
if (ret) {
dev_err(dev, "failed to read firmware version: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "failed to read firmware version\n");
dev_info(dev, "firmware version: %d.%d\n", val >> 8, (char)val);
ret = scd30_command_write(state, CMD_MEAS_INTERVAL, state->meas_interval);
if (ret) {
dev_err(dev, "failed to set measurement interval: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "failed to set measurement interval\n");
ret = scd30_command_write(state, CMD_START_MEAS, state->pressure_comp);
if (ret) {
dev_err(dev, "failed to start measurement: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "failed to start measurement\n");
ret = devm_add_action_or_reset(dev, scd30_stop_meas, state);
if (ret)
......
......@@ -400,12 +400,12 @@ static ssize_t scmi_iio_get_raw_available(struct iio_dev *iio_dev,
rem = do_div(resolution,
int_pow(10, abs(exponent))
);
len = scnprintf(buf, PAGE_SIZE,
len = sysfs_emit(buf,
"[%lld %llu.%llu %lld]\n", min_range,
resolution, rem, max_range);
} else {
resolution = resolution * int_pow(10, exponent);
len = scnprintf(buf, PAGE_SIZE, "[%lld %llu %lld]\n",
len = sysfs_emit(buf, "[%lld %llu %lld]\n",
min_range, resolution, max_range);
}
}
......
......@@ -162,10 +162,10 @@ config AD5696_I2C
depends on I2C
select AD5686
help
Say yes here to build support for Analog Devices AD5311R, AD5338R,
AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693, AD5693R,
AD5694, AD5694R, AD5695R, AD5696, and AD5696R Digital to Analog
converters.
Say yes here to build support for Analog Devices AD5311R, AD5337,
AD5338R, AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693,
AD5693R, AD5694, AD5694R, AD5695R, AD5696, and AD5696R Digital to
Analog converters.
To compile this driver as a module, choose M here: the module will be
called ad5696.
......@@ -357,6 +357,19 @@ config MAX517
This driver can also be built as a module. If so, the module
will be called max517.
config MAX5522
tristate "Maxim MAX5522 DAC driver"
depends on SPI_MASTER
select REGMAP_SPI
help
Say Y here if you want to build a driver for the Maxim MAX5522.
MAX5522 is a dual, ultra-low-power, 10-Bit, voltage-output
digital to analog converter (DAC) offering rail-to-rail buffered
voltage outputs.
If compiled as a module, it will be called max5522.
config MAX5821
tristate "Maxim MAX5821 DAC driver"
depends on I2C
......
......@@ -38,6 +38,7 @@ obj-$(CONFIG_LTC2632) += ltc2632.o
obj-$(CONFIG_LTC2688) += ltc2688.o
obj-$(CONFIG_M62332) += m62332.o
obj-$(CONFIG_MAX517) += max517.o
obj-$(CONFIG_MAX5522) += max5522.o
obj-$(CONFIG_MAX5821) += max5821.o
obj-$(CONFIG_MCP4725) += mcp4725.o
obj-$(CONFIG_MCP4922) += mcp4922.o
......
......@@ -258,6 +258,7 @@ static const struct iio_chan_spec name[] = { \
DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2);
DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6);
DECLARE_AD5338_CHANNELS(ad5337r_channels, 8, 8);
DECLARE_AD5338_CHANNELS(ad5338r_channels, 10, 6);
DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4);
......@@ -283,6 +284,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
.num_channels = 1,
.regmap_type = AD5693_REGMAP,
},
[ID_AD5337R] = {
.channels = ad5337r_channels,
.int_vref_mv = 2500,
.num_channels = 2,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5338R] = {
.channels = ad5338r_channels,
.int_vref_mv = 2500,
......
......@@ -54,6 +54,7 @@
enum ad5686_supported_device_ids {
ID_AD5310R,
ID_AD5311R,
ID_AD5337R,
ID_AD5338R,
ID_AD5671R,
ID_AD5672R,
......
......@@ -72,6 +72,7 @@ static void ad5686_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id ad5686_i2c_id[] = {
{"ad5311r", ID_AD5311R},
{"ad5337r", ID_AD5337R},
{"ad5338r", ID_AD5338R},
{"ad5671r", ID_AD5671R},
{"ad5673r", ID_AD5673R},
......@@ -92,6 +93,7 @@ MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id);
static const struct of_device_id ad5686_of_match[] = {
{ .compatible = "adi,ad5311r" },
{ .compatible = "adi,ad5337r" },
{ .compatible = "adi,ad5338r" },
{ .compatible = "adi,ad5671r" },
{ .compatible = "adi,ad5675r" },
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Maxim MAX5522
* Dual, Ultra-Low-Power 10-Bit, Voltage-Output DACs
*
* Copyright 2022 Timesys Corp.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#define MAX5522_MAX_ADDR 15
#define MAX5522_CTRL_NONE 0
#define MAX5522_CTRL_LOAD_IN_A 9
#define MAX5522_CTRL_LOAD_IN_B 10
#define MAX5522_REG_DATA(x) ((x) + MAX5522_CTRL_LOAD_IN_A)
struct max5522_chip_info {
const char *name;
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
struct max5522_state {
struct regmap *regmap;
const struct max5522_chip_info *chip_info;
unsigned short dac_cache[2];
struct regulator *vrefin_reg;
};
#define MAX5522_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 'u', \
.realbits = 10, \
.storagebits = 16, \
.shift = 2, \
} \
}
const struct iio_chan_spec max5522_channels[] = {
MAX5522_CHANNEL(0),
MAX5522_CHANNEL(1),
};
enum max5522_type {
ID_MAX5522,
};
static const struct max5522_chip_info max5522_chip_info_tbl[] = {
[ID_MAX5522] = {
.name = "max5522",
.channels = max5522_channels,
.num_channels = 2,
},
};
static inline int max5522_info_to_reg(struct iio_chan_spec const *chan)
{
return MAX5522_REG_DATA(chan->channel);
}
static int max5522_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long info)
{
struct max5522_state *state = iio_priv(indio_dev);
int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
*val = state->dac_cache[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(state->vrefin_reg);
if (ret < 0)
return -EINVAL;
*val = ret / 1000;
*val2 = 10;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
return -EINVAL;
}
static int max5522_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long info)
{
struct max5522_state *state = iio_priv(indio_dev);
int rval;
if (val > 1023 || val < 0)
return -EINVAL;
rval = regmap_write(state->regmap, max5522_info_to_reg(chan),
val << chan->scan_type.shift);
if (rval < 0)
return rval;
state->dac_cache[chan->channel] = val;
return 0;
}
static const struct iio_info max5522_info = {
.read_raw = max5522_read_raw,
.write_raw = max5522_write_raw,
};
static const struct regmap_config max5522_regmap_config = {
.reg_bits = 4,
.val_bits = 12,
.max_register = MAX5522_MAX_ADDR,
};
static int max5522_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct iio_dev *indio_dev;
struct max5522_state *state;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
if (indio_dev == NULL) {
dev_err(&spi->dev, "failed to allocate iio device\n");
return -ENOMEM;
}
state = iio_priv(indio_dev);
state->chip_info = device_get_match_data(&spi->dev);
if (!state->chip_info) {
state->chip_info =
(struct max5522_chip_info *)(id->driver_data);
if (!state->chip_info)
return -EINVAL;
}
state->vrefin_reg = devm_regulator_get(&spi->dev, "vrefin");
if (IS_ERR(state->vrefin_reg))
return dev_err_probe(&spi->dev, PTR_ERR(state->vrefin_reg),
"Vrefin regulator not specified\n");
ret = regulator_enable(state->vrefin_reg);
if (ret) {
return dev_err_probe(&spi->dev, ret,
"Failed to enable vref regulators\n");
}
state->regmap = devm_regmap_init_spi(spi, &max5522_regmap_config);
if (IS_ERR(state->regmap))
return PTR_ERR(state->regmap);
indio_dev->info = &max5522_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = max5522_channels;
indio_dev->num_channels = ARRAY_SIZE(max5522_channels);
indio_dev->name = max5522_chip_info_tbl[ID_MAX5522].name;
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id max5522_ids[] = {
{ "max5522", (kernel_ulong_t)&max5522_chip_info_tbl[ID_MAX5522] },
{}
};
MODULE_DEVICE_TABLE(spi, max5522_ids);
static const struct of_device_id max5522_of_match[] = {
{
.compatible = "maxim,max5522",
.data = &max5522_chip_info_tbl[ID_MAX5522],
},
{}
};
MODULE_DEVICE_TABLE(of, max5522_of_match);
static struct spi_driver max5522_spi_driver = {
.driver = {
.name = "max5522",
.of_match_table = max5522_of_match,
},
.probe = max5522_spi_probe,
.id_table = max5522_ids,
};
module_spi_driver(max5522_spi_driver);
MODULE_AUTHOR("Angelo Dureghello <angelo.dureghello@timesys.com");
MODULE_DESCRIPTION("MAX5522 DAC driver");
MODULE_LICENSE("GPL");
//SPDX-License-Identifier: GPL-2.0
// SPDX-License-Identifier: GPL-2.0
/*
* bno055_ser Trace Support
......
......@@ -649,7 +649,7 @@ static int kmx61_chip_update_thresholds(struct kmx61_data *data)
KMX61_REG_WUF_TIMER,
data->wake_duration);
if (ret < 0) {
dev_err(&data->client->dev, "Errow writing reg_wuf_timer\n");
dev_err(&data->client->dev, "Error writing reg_wuf_timer\n");
return ret;
}
......
......@@ -93,7 +93,7 @@ enum st_lsm6dsx_hw_id {
.endianness = IIO_LE, \
}, \
.event_spec = &st_lsm6dsx_event, \
.ext_info = st_lsm6dsx_accel_ext_info, \
.ext_info = st_lsm6dsx_ext_info, \
.num_event_specs = 1, \
}
......@@ -113,6 +113,7 @@ enum st_lsm6dsx_hw_id {
.storagebits = 16, \
.endianness = IIO_LE, \
}, \
.ext_info = st_lsm6dsx_ext_info, \
}
struct st_lsm6dsx_reg {
......@@ -528,7 +529,7 @@ st_lsm6dsx_device_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable)
}
static const
struct iio_chan_spec_ext_info __maybe_unused st_lsm6dsx_accel_ext_info[] = {
struct iio_chan_spec_ext_info __maybe_unused st_lsm6dsx_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_lsm6dsx_get_mount_matrix),
{ }
};
......
......@@ -704,18 +704,18 @@ static ssize_t st_lsm6dsx_shub_scale_avail(struct device *dev,
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_shub_sampling_freq_avail);
static IIO_DEVICE_ATTR(in_scale_available, 0444,
st_lsm6dsx_shub_scale_avail, NULL, 0);
static struct attribute *st_lsm6dsx_ext_attributes[] = {
static struct attribute *st_lsm6dsx_shub_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group st_lsm6dsx_ext_attribute_group = {
.attrs = st_lsm6dsx_ext_attributes,
static const struct attribute_group st_lsm6dsx_shub_attribute_group = {
.attrs = st_lsm6dsx_shub_attributes,
};
static const struct iio_info st_lsm6dsx_ext_info = {
.attrs = &st_lsm6dsx_ext_attribute_group,
static const struct iio_info st_lsm6dsx_shub_info = {
.attrs = &st_lsm6dsx_shub_attribute_group,
.read_raw = st_lsm6dsx_shub_read_raw,
.write_raw = st_lsm6dsx_shub_write_raw,
.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
......@@ -737,7 +737,7 @@ st_lsm6dsx_shub_alloc_iiodev(struct st_lsm6dsx_hw *hw,
return NULL;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->info = &st_lsm6dsx_ext_info;
iio_dev->info = &st_lsm6dsx_shub_info;
sensor = iio_priv(iio_dev);
sensor->id = id;
......
......@@ -8,30 +8,32 @@
#define pr_fmt(fmt) "iio-core: " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/idr.h>
#include <linux/kdev_t.h>
#include <linux/err.h>
#include <linux/anon_inodes.h>
#include <linux/cdev.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/idr.h>
#include <linux/kdev_t.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/property.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/anon_inodes.h>
#include <linux/debugfs.h>
#include <linux/mutex.h>
#include <linux/iio/iio.h>
#include <linux/wait.h>
#include <linux/iio/buffer.h>
#include <linux/iio/buffer_impl.h>
#include <linux/iio/events.h>
#include <linux/iio/iio-opaque.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include "iio_core.h"
#include "iio_core_trigger.h"
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/buffer.h>
#include <linux/iio/buffer_impl.h>
/* IDA to assign each registered device a unique id */
static DEFINE_IDA(iio_ida);
......@@ -205,36 +207,6 @@ bool iio_buffer_enabled(struct iio_dev *indio_dev)
}
EXPORT_SYMBOL_GPL(iio_buffer_enabled);
/**
* iio_sysfs_match_string_with_gaps - matches given string in an array with gaps
* @array: array of strings
* @n: number of strings in the array
* @str: string to match with
*
* Returns index of @str in the @array or -EINVAL, similar to match_string().
* Uses sysfs_streq instead of strcmp for matching.
*
* This routine will look for a string in an array of strings.
* The search will continue until the element is found or the n-th element
* is reached, regardless of any NULL elements in the array.
*/
static int iio_sysfs_match_string_with_gaps(const char * const *array, size_t n,
const char *str)
{
const char *item;
int index;
for (index = 0; index < n; index++) {
item = array[index];
if (!item)
continue;
if (sysfs_streq(item, str))
return index;
}
return -EINVAL;
}
#if defined(CONFIG_DEBUG_FS)
/*
* There's also a CONFIG_DEBUG_FS guard in include/linux/iio/iio.h for
......@@ -569,7 +541,7 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
if (!e->set)
return -EINVAL;
ret = iio_sysfs_match_string_with_gaps(e->items, e->num_items, buf);
ret = __sysfs_match_string(e->items, e->num_items, buf);
if (ret < 0)
return ret;
......
......@@ -39,7 +39,6 @@ obj-$(CONFIG_NOA1305) += noa1305.o
obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_PA12203001) += pa12203001.o
obj-$(CONFIG_RPR0521) += rpr0521.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_SI1133) += si1133.o
obj-$(CONFIG_SI1145) += si1145.o
obj-$(CONFIG_STK3310) += stk3310.o
......@@ -48,6 +47,7 @@ obj-$(CONFIG_ST_UVIS25_I2C) += st_uvis25_i2c.o
obj-$(CONFIG_ST_UVIS25_SPI) += st_uvis25_spi.o
obj-$(CONFIG_TCS3414) += tcs3414.o
obj-$(CONFIG_TCS3472) += tcs3472.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_TSL2583) += tsl2583.o
obj-$(CONFIG_TSL2591) += tsl2591.o
obj-$(CONFIG_TSL2772) += tsl2772.o
......
......@@ -487,8 +487,7 @@ static irqreturn_t max44009_threaded_irq_handler(int irq, void *p)
return IRQ_NONE;
}
static int max44009_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int max44009_probe(struct i2c_client *client)
{
struct max44009_data *data;
struct iio_dev *indio_dev;
......@@ -538,7 +537,7 @@ static struct i2c_driver max44009_driver = {
.driver = {
.name = MAX44009_DRV_NAME,
},
.probe = max44009_probe,
.probe_new = max44009_probe,
.id_table = max44009_id,
};
module_i2c_driver(max44009_driver);
......
......@@ -11,69 +11,63 @@
* Amit Kucheria <amit.kucheria@verdurent.com>
*/
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/math.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/err.h>
#include <linux/property.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/platform_data/tsl2563.h>
/* Use this many bits for fraction part. */
#define ADC_FRAC_BITS 14
/* Given number of 1/10000's in ADC_FRAC_BITS precision. */
#define FRAC10K(f) (((f) * (1L << (ADC_FRAC_BITS))) / (10000))
#define FRAC10K(f) (((f) * BIT(ADC_FRAC_BITS)) / (10000))
/* Bits used for fraction in calibration coefficients.*/
#define CALIB_FRAC_BITS 10
/* 0.5 in CALIB_FRAC_BITS precision */
#define CALIB_FRAC_HALF (1 << (CALIB_FRAC_BITS - 1))
/* Make a fraction from a number n that was multiplied with b. */
#define CALIB_FRAC(n, b) (((n) << CALIB_FRAC_BITS) / (b))
/* Decimal 10^(digits in sysfs presentation) */
#define CALIB_BASE_SYSFS 1000
#define TSL2563_CMD 0x80
#define TSL2563_CLEARINT 0x40
#define TSL2563_CMD BIT(7)
#define TSL2563_CLEARINT BIT(6)
#define TSL2563_REG_CTRL 0x00
#define TSL2563_REG_TIMING 0x01
#define TSL2563_REG_LOWLOW 0x02 /* data0 low threshold, 2 bytes */
#define TSL2563_REG_LOWHIGH 0x03
#define TSL2563_REG_HIGHLOW 0x04 /* data0 high threshold, 2 bytes */
#define TSL2563_REG_HIGHHIGH 0x05
#define TSL2563_REG_LOW 0x02 /* data0 low threshold, 2 bytes */
#define TSL2563_REG_HIGH 0x04 /* data0 high threshold, 2 bytes */
#define TSL2563_REG_INT 0x06
#define TSL2563_REG_ID 0x0a
#define TSL2563_REG_DATA0LOW 0x0c /* broadband sensor value, 2 bytes */
#define TSL2563_REG_DATA0HIGH 0x0d
#define TSL2563_REG_DATA1LOW 0x0e /* infrared sensor value, 2 bytes */
#define TSL2563_REG_DATA1HIGH 0x0f
#define TSL2563_REG_DATA0 0x0c /* broadband sensor value, 2 bytes */
#define TSL2563_REG_DATA1 0x0e /* infrared sensor value, 2 bytes */
#define TSL2563_CMD_POWER_ON 0x03
#define TSL2563_CMD_POWER_OFF 0x00
#define TSL2563_CTRL_POWER_MASK 0x03
#define TSL2563_CTRL_POWER_MASK GENMASK(1, 0)
#define TSL2563_TIMING_13MS 0x00
#define TSL2563_TIMING_100MS 0x01
#define TSL2563_TIMING_400MS 0x02
#define TSL2563_TIMING_MASK 0x03
#define TSL2563_TIMING_MASK GENMASK(1, 0)
#define TSL2563_TIMING_GAIN16 0x10
#define TSL2563_TIMING_GAIN1 0x00
#define TSL2563_INT_DISABLED 0x00
#define TSL2563_INT_LEVEL 0x10
#define TSL2563_INT_PERSIST(n) ((n) & 0x0F)
#define TSL2563_INT_MASK GENMASK(5, 4)
#define TSL2563_INT_PERSIST(n) ((n) & GENMASK(3, 0))
struct tsl2563_gainlevel_coeff {
u8 gaintime;
......@@ -161,24 +155,16 @@ static int tsl2563_configure(struct tsl2563_chip *chip)
chip->gainlevel->gaintime);
if (ret)
goto error_ret;
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_HIGHLOW,
chip->high_thres & 0xFF);
if (ret)
goto error_ret;
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_HIGHHIGH,
(chip->high_thres >> 8) & 0xFF);
ret = i2c_smbus_write_word_data(chip->client,
TSL2563_CMD | TSL2563_REG_HIGH,
chip->high_thres);
if (ret)
goto error_ret;
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_LOWLOW,
chip->low_thres & 0xFF);
ret = i2c_smbus_write_word_data(chip->client,
TSL2563_CMD | TSL2563_REG_LOW,
chip->low_thres);
if (ret)
goto error_ret;
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_LOWHIGH,
(chip->low_thres >> 8) & 0xFF);
/*
* Interrupt register is automatically written anyway if it is relevant
* so is not here.
......@@ -223,6 +209,24 @@ static int tsl2563_read_id(struct tsl2563_chip *chip, u8 *id)
return 0;
}
static int tsl2563_configure_irq(struct tsl2563_chip *chip, bool enable)
{
int ret;
chip->intr &= ~TSL2563_INT_MASK;
if (enable)
chip->intr |= TSL2563_INT_LEVEL;
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_INT,
chip->intr);
if (ret < 0)
return ret;
chip->int_enabled = enable;
return 0;
}
/*
* "Normalized" ADC value is one obtained with 400ms of integration time and
* 16x gain. This function returns the number of bits of shift needed to
......@@ -325,13 +329,13 @@ static int tsl2563_get_adc(struct tsl2563_chip *chip)
while (retry) {
ret = i2c_smbus_read_word_data(client,
TSL2563_CMD | TSL2563_REG_DATA0LOW);
TSL2563_CMD | TSL2563_REG_DATA0);
if (ret < 0)
goto out;
adc0 = ret;
ret = i2c_smbus_read_word_data(client,
TSL2563_CMD | TSL2563_REG_DATA1LOW);
TSL2563_CMD | TSL2563_REG_DATA1);
if (ret < 0)
goto out;
adc1 = ret;
......@@ -352,12 +356,12 @@ static int tsl2563_get_adc(struct tsl2563_chip *chip)
static inline int tsl2563_calib_to_sysfs(u32 calib)
{
return (int) (((calib * CALIB_BASE_SYSFS) +
CALIB_FRAC_HALF) >> CALIB_FRAC_BITS);
return (int)DIV_ROUND_CLOSEST(calib * CALIB_BASE_SYSFS, BIT(CALIB_FRAC_BITS));
}
static inline u32 tsl2563_calib_from_sysfs(int value)
{
/* Make a fraction from a number n that was multiplied with b. */
return (((u32) value) << CALIB_FRAC_BITS) / CALIB_BASE_SYSFS;
}
......@@ -584,20 +588,18 @@ static int tsl2563_write_thresh(struct iio_dev *indio_dev,
{
struct tsl2563_chip *chip = iio_priv(indio_dev);
int ret;
u8 address;
mutex_lock(&chip->lock);
if (dir == IIO_EV_DIR_RISING)
address = TSL2563_REG_HIGHLOW;
ret = i2c_smbus_write_word_data(chip->client,
TSL2563_CMD | TSL2563_REG_HIGH, val);
else
address = TSL2563_REG_LOWLOW;
mutex_lock(&chip->lock);
ret = i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | address,
val & 0xFF);
ret = i2c_smbus_write_word_data(chip->client,
TSL2563_CMD | TSL2563_REG_LOW, val);
if (ret)
goto error_ret;
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | (address + 1),
(val >> 8) & 0xFF);
if (dir == IIO_EV_DIR_RISING)
chip->high_thres = val;
else
......@@ -634,9 +636,7 @@ static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev,
int ret = 0;
mutex_lock(&chip->lock);
if (state && !(chip->intr & 0x30)) {
chip->intr &= ~0x30;
chip->intr |= 0x10;
if (state && !(chip->intr & TSL2563_INT_MASK)) {
/* ensure the chip is actually on */
cancel_delayed_work_sync(&chip->poweroff_work);
if (!tsl2563_get_power(chip)) {
......@@ -647,18 +647,11 @@ static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev,
if (ret)
goto out;
}
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_INT,
chip->intr);
chip->int_enabled = true;
ret = tsl2563_configure_irq(chip, true);
}
if (!state && (chip->intr & 0x30)) {
chip->intr &= ~0x30;
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_INT,
chip->intr);
chip->int_enabled = false;
if (!state && (chip->intr & TSL2563_INT_MASK)) {
ret = tsl2563_configure_irq(chip, false);
/* now the interrupt is not enabled, we can go to sleep */
schedule_delayed_work(&chip->poweroff_work, 5 * HZ);
}
......@@ -682,7 +675,7 @@ static int tsl2563_read_interrupt_config(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
return !!(ret & 0x30);
return !!(ret & TSL2563_INT_MASK);
}
static const struct iio_info tsl2563_info_no_irq = {
......@@ -701,13 +694,14 @@ static const struct iio_info tsl2563_info = {
static int tsl2563_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct tsl2563_chip *chip;
struct tsl2563_platform_data *pdata = client->dev.platform_data;
int err = 0;
unsigned long irq_flags;
u8 id = 0;
int err;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
indio_dev = devm_iio_device_alloc(dev, sizeof(*chip));
if (!indio_dev)
return -ENOMEM;
......@@ -717,16 +711,12 @@ static int tsl2563_probe(struct i2c_client *client)
chip->client = client;
err = tsl2563_detect(chip);
if (err) {
dev_err(&client->dev, "detect error %d\n", -err);
return err;
}
if (err)
return dev_err_probe(dev, err, "detect error\n");
err = tsl2563_read_id(chip, &id);
if (err) {
dev_err(&client->dev, "read id error %d\n", -err);
return err;
}
if (err)
return dev_err_probe(dev, err, "read id error\n");
mutex_init(&chip->lock);
......@@ -738,16 +728,10 @@ static int tsl2563_probe(struct i2c_client *client)
chip->calib0 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS);
chip->calib1 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS);
if (pdata) {
chip->cover_comp_gain = pdata->cover_comp_gain;
} else {
err = device_property_read_u32(&client->dev, "amstaos,cover-comp-gain",
&chip->cover_comp_gain);
if (err)
chip->cover_comp_gain = 1;
}
chip->cover_comp_gain = 1;
device_property_read_u32(dev, "amstaos,cover-comp-gain", &chip->cover_comp_gain);
dev_info(&client->dev, "model %d, rev. %d\n", id >> 4, id & 0x0f);
dev_info(dev, "model %d, rev. %d\n", id >> 4, id & 0x0f);
indio_dev->name = client->name;
indio_dev->channels = tsl2563_channels;
indio_dev->num_channels = ARRAY_SIZE(tsl2563_channels);
......@@ -759,23 +743,24 @@ static int tsl2563_probe(struct i2c_client *client)
indio_dev->info = &tsl2563_info_no_irq;
if (client->irq) {
err = devm_request_threaded_irq(&client->dev, client->irq,
irq_flags = irq_get_trigger_type(client->irq);
if (irq_flags == IRQF_TRIGGER_NONE)
irq_flags = IRQF_TRIGGER_RISING;
irq_flags |= IRQF_ONESHOT;
err = devm_request_threaded_irq(dev, client->irq,
NULL,
&tsl2563_event_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
irq_flags,
"tsl2563_event",
indio_dev);
if (err) {
dev_err(&client->dev, "irq request error %d\n", -err);
return err;
}
if (err)
return dev_err_probe(dev, err, "irq request error\n");
}
err = tsl2563_configure(chip);
if (err) {
dev_err(&client->dev, "configure error %d\n", -err);
return err;
}
if (err)
return dev_err_probe(dev, err, "configure error\n");
INIT_DELAYED_WORK(&chip->poweroff_work, tsl2563_poweroff_work);
......@@ -784,7 +769,7 @@ static int tsl2563_probe(struct i2c_client *client)
err = iio_device_register(indio_dev);
if (err) {
dev_err(&client->dev, "iio registration error %d\n", -err);
dev_err_probe(dev, err, "iio registration error\n");
goto fail;
}
......@@ -804,15 +789,13 @@ static void tsl2563_remove(struct i2c_client *client)
if (!chip->int_enabled)
cancel_delayed_work_sync(&chip->poweroff_work);
/* Ensure that interrupts are disabled - then flush any bottom halves */
chip->intr &= ~0x30;
i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | TSL2563_REG_INT,
chip->intr);
tsl2563_configure_irq(chip, false);
tsl2563_set_power(chip, 0);
}
static int tsl2563_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tsl2563_chip *chip = iio_priv(indio_dev);
int ret;
......@@ -831,7 +814,7 @@ static int tsl2563_suspend(struct device *dev)
static int tsl2563_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tsl2563_chip *chip = iio_priv(indio_dev);
int ret;
......
......@@ -60,8 +60,11 @@
#define VCNL4200_AL_CONF 0x00 /* Ambient light configuration */
#define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */
#define VCNL4040_PS_THDL_LM 0x06 /* Proximity threshold low */
#define VCNL4040_PS_THDH_LM 0x07 /* Proximity threshold high */
#define VCNL4200_PS_DATA 0x08 /* Proximity data */
#define VCNL4200_AL_DATA 0x09 /* Ambient light data */
#define VCNL4040_INT_FLAGS 0x0b /* Interrupt register */
#define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */
#define VCNL4040_DEV_ID 0x0c /* Device ID and version */
......@@ -78,6 +81,9 @@
#define VCNL4040_ALS_CONF_ALS_SHUTDOWN BIT(0)
#define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0)
#define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */
#define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */
#define VCNL4040_PS_IF_AWAY BIT(8) /* Proximity event cross low threshold */
#define VCNL4040_PS_IF_CLOSE BIT(9) /* Proximity event cross high threshold */
/* Bit masks for interrupt registers. */
#define VCNL4010_INT_THR_SEL BIT(0) /* Select threshold interrupt source */
......@@ -138,6 +144,7 @@ struct vcnl4000_data {
enum vcnl4000_device_ids id;
int rev;
int al_scale;
u8 ps_int; /* proximity interrupt mode */
const struct vcnl4000_chip_spec *chip_spec;
struct mutex vcnl4000_lock;
struct vcnl4200_channel vcnl4200_al;
......@@ -150,11 +157,13 @@ struct vcnl4000_chip_spec {
struct iio_chan_spec const *channels;
const int num_channels;
const struct iio_info *info;
bool irq_support;
const struct iio_buffer_setup_ops *buffer_setup_ops;
int (*init)(struct vcnl4000_data *data);
int (*measure_light)(struct vcnl4000_data *data, int *val);
int (*measure_proximity)(struct vcnl4000_data *data, int *val);
int (*set_power_state)(struct vcnl4000_data *data, bool on);
irqreturn_t (*irq_thread)(int irq, void *priv);
irqreturn_t (*trig_buffer_func)(int irq, void *priv);
};
static const struct i2c_device_id vcnl4000_id[] = {
......@@ -254,6 +263,10 @@ static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
{
int ret;
/* Do not power down if interrupts are enabled */
if (!on && data->ps_int)
return 0;
ret = vcnl4000_write_als_enable(data, on);
if (ret < 0)
return ret;
......@@ -295,6 +308,7 @@ static int vcnl4200_init(struct vcnl4000_data *data)
dev_dbg(&data->client->dev, "device id 0x%x", id);
data->rev = (ret >> 8) & 0xf;
data->ps_int = 0;
data->vcnl4200_al.reg = VCNL4200_AL_DATA;
data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
......@@ -795,6 +809,64 @@ static int vcnl4010_write_event(struct iio_dev *indio_dev,
}
}
static int vcnl4040_read_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
int ret;
struct vcnl4000_data *data = iio_priv(indio_dev);
switch (dir) {
case IIO_EV_DIR_RISING:
ret = i2c_smbus_read_word_data(data->client,
VCNL4040_PS_THDH_LM);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_EV_DIR_FALLING:
ret = i2c_smbus_read_word_data(data->client,
VCNL4040_PS_THDL_LM);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int vcnl4040_write_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
int ret;
struct vcnl4000_data *data = iio_priv(indio_dev);
switch (dir) {
case IIO_EV_DIR_RISING:
ret = i2c_smbus_write_word_data(data->client,
VCNL4040_PS_THDH_LM, val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_EV_DIR_FALLING:
ret = i2c_smbus_write_word_data(data->client,
VCNL4040_PS_THDL_LM, val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static bool vcnl4010_is_thr_enabled(struct vcnl4000_data *data)
{
int ret;
......@@ -877,6 +949,86 @@ static int vcnl4010_write_event_config(struct iio_dev *indio_dev,
}
}
static int vcnl4040_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
int ret;
struct vcnl4000_data *data = iio_priv(indio_dev);
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
if (ret < 0)
return ret;
data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, ret);
return (dir == IIO_EV_DIR_RISING) ?
FIELD_GET(VCNL4040_PS_IF_AWAY, ret) :
FIELD_GET(VCNL4040_PS_IF_CLOSE, ret);
}
static int vcnl4040_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir, int state)
{
int ret;
u16 val, mask;
struct vcnl4000_data *data = iio_priv(indio_dev);
mutex_lock(&data->vcnl4000_lock);
ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
if (ret < 0)
goto out;
if (dir == IIO_EV_DIR_RISING)
mask = VCNL4040_PS_IF_AWAY;
else
mask = VCNL4040_PS_IF_CLOSE;
val = state ? (ret | mask) : (ret & ~mask);
data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, val);
ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val);
out:
mutex_unlock(&data->vcnl4000_lock);
data->chip_spec->set_power_state(data, data->ps_int != 0);
return ret;
}
static irqreturn_t vcnl4040_irq_thread(int irq, void *p)
{
struct iio_dev *indio_dev = p;
struct vcnl4000_data *data = iio_priv(indio_dev);
int ret;
ret = i2c_smbus_read_word_data(data->client, VCNL4040_INT_FLAGS);
if (ret < 0)
return IRQ_HANDLED;
if (ret & VCNL4040_PS_IF_CLOSE) {
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
iio_get_time_ns(indio_dev));
}
if (ret & VCNL4040_PS_IF_AWAY) {
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
iio_get_time_ns(indio_dev));
}
return IRQ_HANDLED;
}
static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,
uintptr_t priv,
const struct iio_chan_spec *chan,
......@@ -887,6 +1039,134 @@ static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,
return sprintf(buf, "%u\n", data->near_level);
}
static irqreturn_t vcnl4010_irq_thread(int irq, void *p)
{
struct iio_dev *indio_dev = p;
struct vcnl4000_data *data = iio_priv(indio_dev);
unsigned long isr;
int ret;
ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
if (ret < 0)
goto end;
isr = ret;
if (isr & VCNL4010_INT_THR) {
if (test_bit(VCNL4010_INT_THR_LOW, &isr)) {
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(
IIO_PROXIMITY,
1,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
iio_get_time_ns(indio_dev));
}
if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) {
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(
IIO_PROXIMITY,
1,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
iio_get_time_ns(indio_dev));
}
i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
isr & VCNL4010_INT_THR);
}
if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev))
iio_trigger_poll_chained(indio_dev->trig);
end:
return IRQ_HANDLED;
}
static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct vcnl4000_data *data = iio_priv(indio_dev);
const unsigned long *active_scan_mask = indio_dev->active_scan_mask;
u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */
bool data_read = false;
unsigned long isr;
int val = 0;
int ret;
ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
if (ret < 0)
goto end;
isr = ret;
if (test_bit(0, active_scan_mask)) {
if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) {
ret = vcnl4000_read_data(data,
VCNL4000_PS_RESULT_HI,
&val);
if (ret < 0)
goto end;
buffer[0] = val;
data_read = true;
}
}
ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
isr & VCNL4010_INT_DRDY);
if (ret < 0)
goto end;
if (!data_read)
goto end;
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
iio_get_time_ns(indio_dev));
end:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev)
{
struct vcnl4000_data *data = iio_priv(indio_dev);
int ret;
int cmd;
/* Do not enable the buffer if we are already capturing events. */
if (vcnl4010_is_in_periodic_mode(data))
return -EBUSY;
ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL,
VCNL4010_INT_PROX_EN);
if (ret < 0)
return ret;
cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd);
}
static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev)
{
struct vcnl4000_data *data = iio_priv(indio_dev);
int ret;
ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0);
if (ret < 0)
return ret;
return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0);
}
static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = {
.postenable = &vcnl4010_buffer_postenable,
.predisable = &vcnl4010_buffer_predisable,
};
static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = {
{
.name = "nearlevel",
......@@ -912,6 +1192,18 @@ static const struct iio_event_spec vcnl4000_event_spec[] = {
}
};
static const struct iio_event_spec vcnl4040_event_spec[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
},
};
static const struct iio_chan_spec vcnl4000_channels[] = {
{
.type = IIO_LIGHT,
......@@ -960,6 +1252,8 @@ static const struct iio_chan_spec vcnl4040_channels[] = {
BIT(IIO_CHAN_INFO_INT_TIME),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME),
.ext_info = vcnl4000_ext_info,
.event_spec = vcnl4040_event_spec,
.num_event_specs = ARRAY_SIZE(vcnl4040_event_spec),
}
};
......@@ -980,6 +1274,10 @@ static const struct iio_info vcnl4010_info = {
static const struct iio_info vcnl4040_info = {
.read_raw = vcnl4000_read_raw,
.write_raw = vcnl4040_write_raw,
.read_event_value = vcnl4040_read_event,
.write_event_value = vcnl4040_write_event,
.read_event_config = vcnl4040_read_event_config,
.write_event_config = vcnl4040_write_event_config,
.read_avail = vcnl4040_read_avail,
};
......@@ -993,7 +1291,6 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.channels = vcnl4000_channels,
.num_channels = ARRAY_SIZE(vcnl4000_channels),
.info = &vcnl4000_info,
.irq_support = false,
},
[VCNL4010] = {
.prod = "VCNL4010/4020",
......@@ -1004,7 +1301,9 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.channels = vcnl4010_channels,
.num_channels = ARRAY_SIZE(vcnl4010_channels),
.info = &vcnl4010_info,
.irq_support = true,
.irq_thread = vcnl4010_irq_thread,
.trig_buffer_func = vcnl4010_trigger_handler,
.buffer_setup_ops = &vcnl4010_buffer_ops,
},
[VCNL4040] = {
.prod = "VCNL4040",
......@@ -1015,7 +1314,7 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.channels = vcnl4040_channels,
.num_channels = ARRAY_SIZE(vcnl4040_channels),
.info = &vcnl4040_info,
.irq_support = false,
.irq_thread = vcnl4040_irq_thread,
},
[VCNL4200] = {
.prod = "VCNL4200",
......@@ -1026,138 +1325,9 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.channels = vcnl4000_channels,
.num_channels = ARRAY_SIZE(vcnl4000_channels),
.info = &vcnl4000_info,
.irq_support = false,
},
};
static irqreturn_t vcnl4010_irq_thread(int irq, void *p)
{
struct iio_dev *indio_dev = p;
struct vcnl4000_data *data = iio_priv(indio_dev);
unsigned long isr;
int ret;
ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
if (ret < 0)
goto end;
isr = ret;
if (isr & VCNL4010_INT_THR) {
if (test_bit(VCNL4010_INT_THR_LOW, &isr)) {
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(
IIO_PROXIMITY,
1,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
iio_get_time_ns(indio_dev));
}
if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) {
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(
IIO_PROXIMITY,
1,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
iio_get_time_ns(indio_dev));
}
i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
isr & VCNL4010_INT_THR);
}
if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev))
iio_trigger_poll_chained(indio_dev->trig);
end:
return IRQ_HANDLED;
}
static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct vcnl4000_data *data = iio_priv(indio_dev);
const unsigned long *active_scan_mask = indio_dev->active_scan_mask;
u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */
bool data_read = false;
unsigned long isr;
int val = 0;
int ret;
ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
if (ret < 0)
goto end;
isr = ret;
if (test_bit(0, active_scan_mask)) {
if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) {
ret = vcnl4000_read_data(data,
VCNL4000_PS_RESULT_HI,
&val);
if (ret < 0)
goto end;
buffer[0] = val;
data_read = true;
}
}
ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
isr & VCNL4010_INT_DRDY);
if (ret < 0)
goto end;
if (!data_read)
goto end;
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
iio_get_time_ns(indio_dev));
end:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev)
{
struct vcnl4000_data *data = iio_priv(indio_dev);
int ret;
int cmd;
/* Do not enable the buffer if we are already capturing events. */
if (vcnl4010_is_in_periodic_mode(data))
return -EBUSY;
ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL,
VCNL4010_INT_PROX_EN);
if (ret < 0)
return ret;
cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd);
}
static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev)
{
struct vcnl4000_data *data = iio_priv(indio_dev);
int ret;
ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0);
if (ret < 0)
return ret;
return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0);
}
static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = {
.postenable = &vcnl4010_buffer_postenable,
.predisable = &vcnl4010_buffer_predisable,
};
static const struct iio_trigger_ops vcnl4010_trigger_ops = {
.validate_device = iio_trigger_validate_own_device,
};
......@@ -1214,22 +1384,25 @@ static int vcnl4000_probe(struct i2c_client *client)
indio_dev->name = VCNL4000_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
if (client->irq && data->chip_spec->irq_support) {
if (data->chip_spec->trig_buffer_func &&
data->chip_spec->buffer_setup_ops) {
ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
NULL,
vcnl4010_trigger_handler,
&vcnl4010_buffer_ops);
data->chip_spec->trig_buffer_func,
data->chip_spec->buffer_setup_ops);
if (ret < 0) {
dev_err(&client->dev,
"unable to setup iio triggered buffer\n");
return ret;
}
}
if (client->irq && data->chip_spec->irq_thread) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, vcnl4010_irq_thread,
NULL, data->chip_spec->irq_thread,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"vcnl4010_irq",
"vcnl4000_irq",
indio_dev);
if (ret < 0) {
dev_err(&client->dev, "irq request failed\n");
......
......@@ -119,7 +119,7 @@ config IIO_ST_MAGN_3AXIS
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics magnetometers:
LSM303DLHC, LSM303DLM, LIS3MDL.
LSM303C, LSM303DLHC, LSM303DLM, LIS3MDL.
Also need to enable at least one of I2C and SPI interface drivers
below.
......@@ -208,6 +208,18 @@ config SENSORS_RM3100_SPI
To compile this driver as a module, choose M here: the module
will be called rm3100-spi.
config TI_TMAG5273
tristate "TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor"
depends on I2C
select REGMAP_I2C
help
Say Y here to add support for the TI TMAG5273 Low-Power
Linear 3D Hall-Effect Sensor.
This driver can also be compiled as a module.
To compile this driver as a module, choose M here: the module
will be called tmag5273.
config YAMAHA_YAS530
tristate "Yamaha YAS530 family of 3-Axis Magnetometers (I2C)"
depends on I2C
......
......@@ -29,4 +29,6 @@ obj-$(CONFIG_SENSORS_RM3100) += rm3100-core.o
obj-$(CONFIG_SENSORS_RM3100_I2C) += rm3100-i2c.o
obj-$(CONFIG_SENSORS_RM3100_SPI) += rm3100-spi.o
obj-$(CONFIG_TI_TMAG5273) += tmag5273.o
obj-$(CONFIG_YAMAHA_YAS530) += yamaha-yas530.o
......@@ -22,6 +22,7 @@
#define LIS2MDL_MAGN_DEV_NAME "lis2mdl"
#define LSM9DS1_MAGN_DEV_NAME "lsm9ds1_magn"
#define IIS2MDC_MAGN_DEV_NAME "iis2mdc"
#define LSM303C_MAGN_DEV_NAME "lsm303c_magn"
#ifdef CONFIG_IIO_BUFFER
int st_magn_allocate_ring(struct iio_dev *indio_dev);
......
......@@ -305,6 +305,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
.sensors_supported = {
[0] = LIS3MDL_MAGN_DEV_NAME,
[1] = LSM9DS1_MAGN_DEV_NAME,
[2] = LSM303C_MAGN_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_magn_2_16bit_channels,
.odr = {
......
......@@ -50,6 +50,10 @@ static const struct of_device_id st_magn_of_match[] = {
.compatible = "st,iis2mdc",
.data = IIS2MDC_MAGN_DEV_NAME,
},
{
.compatible = "st,lsm303c-magn",
.data = LSM303C_MAGN_DEV_NAME,
},
{},
};
MODULE_DEVICE_TABLE(of, st_magn_of_match);
......@@ -97,6 +101,7 @@ static const struct i2c_device_id st_magn_id_table[] = {
{ LIS2MDL_MAGN_DEV_NAME },
{ LSM9DS1_MAGN_DEV_NAME },
{ IIS2MDC_MAGN_DEV_NAME },
{ LSM303C_MAGN_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
......
......@@ -45,6 +45,10 @@ static const struct of_device_id st_magn_of_match[] = {
.compatible = "st,iis2mdc",
.data = IIS2MDC_MAGN_DEV_NAME,
},
{
.compatible = "st,lsm303c-magn",
.data = LSM303C_MAGN_DEV_NAME,
},
{}
};
MODULE_DEVICE_TABLE(of, st_magn_of_match);
......@@ -89,6 +93,7 @@ static const struct spi_device_id st_magn_id_table[] = {
{ LIS2MDL_MAGN_DEV_NAME },
{ LSM9DS1_MAGN_DEV_NAME },
{ IIS2MDC_MAGN_DEV_NAME },
{ LSM303C_MAGN_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_magn_id_table);
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor
*
* Copyright (C) 2022 WolfVision GmbH
*
* Author: Gerald Loacker <gerald.loacker@wolfvision.net>
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define TMAG5273_DEVICE_CONFIG_1 0x00
#define TMAG5273_DEVICE_CONFIG_2 0x01
#define TMAG5273_SENSOR_CONFIG_1 0x02
#define TMAG5273_SENSOR_CONFIG_2 0x03
#define TMAG5273_X_THR_CONFIG 0x04
#define TMAG5273_Y_THR_CONFIG 0x05
#define TMAG5273_Z_THR_CONFIG 0x06
#define TMAG5273_T_CONFIG 0x07
#define TMAG5273_INT_CONFIG_1 0x08
#define TMAG5273_MAG_GAIN_CONFIG 0x09
#define TMAG5273_MAG_OFFSET_CONFIG_1 0x0A
#define TMAG5273_MAG_OFFSET_CONFIG_2 0x0B
#define TMAG5273_I2C_ADDRESS 0x0C
#define TMAG5273_DEVICE_ID 0x0D
#define TMAG5273_MANUFACTURER_ID_LSB 0x0E
#define TMAG5273_MANUFACTURER_ID_MSB 0x0F
#define TMAG5273_T_MSB_RESULT 0x10
#define TMAG5273_T_LSB_RESULT 0x11
#define TMAG5273_X_MSB_RESULT 0x12
#define TMAG5273_X_LSB_RESULT 0x13
#define TMAG5273_Y_MSB_RESULT 0x14
#define TMAG5273_Y_LSB_RESULT 0x15
#define TMAG5273_Z_MSB_RESULT 0x16
#define TMAG5273_Z_LSB_RESULT 0x17
#define TMAG5273_CONV_STATUS 0x18
#define TMAG5273_ANGLE_RESULT_MSB 0x19
#define TMAG5273_ANGLE_RESULT_LSB 0x1A
#define TMAG5273_MAGNITUDE_RESULT 0x1B
#define TMAG5273_DEVICE_STATUS 0x1C
#define TMAG5273_MAX_REG TMAG5273_DEVICE_STATUS
#define TMAG5273_AUTOSLEEP_DELAY_MS 5000
#define TMAG5273_MAX_AVERAGE 32
/*
* bits in the TMAG5273_MANUFACTURER_ID_LSB / MSB register
* 16-bit unique manufacturer ID 0x49 / 0x54 = "TI"
*/
#define TMAG5273_MANUFACTURER_ID 0x5449
/* bits in the TMAG5273_DEVICE_CONFIG_1 register */
#define TMAG5273_AVG_MODE_MASK GENMASK(4, 2)
#define TMAG5273_AVG_1_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 0)
#define TMAG5273_AVG_2_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 1)
#define TMAG5273_AVG_4_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 2)
#define TMAG5273_AVG_8_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 3)
#define TMAG5273_AVG_16_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 4)
#define TMAG5273_AVG_32_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 5)
/* bits in the TMAG5273_DEVICE_CONFIG_2 register */
#define TMAG5273_OP_MODE_MASK GENMASK(1, 0)
#define TMAG5273_OP_MODE_STANDBY FIELD_PREP(TMAG5273_OP_MODE_MASK, 0)
#define TMAG5273_OP_MODE_SLEEP FIELD_PREP(TMAG5273_OP_MODE_MASK, 1)
#define TMAG5273_OP_MODE_CONT FIELD_PREP(TMAG5273_OP_MODE_MASK, 2)
#define TMAG5273_OP_MODE_WAKEUP FIELD_PREP(TMAG5273_OP_MODE_MASK, 3)
/* bits in the TMAG5273_SENSOR_CONFIG_1 register */
#define TMAG5273_MAG_CH_EN_MASK GENMASK(7, 4)
#define TMAG5273_MAG_CH_EN_X_Y_Z 7
/* bits in the TMAG5273_SENSOR_CONFIG_2 register */
#define TMAG5273_Z_RANGE_MASK BIT(0)
#define TMAG5273_X_Y_RANGE_MASK BIT(1)
#define TMAG5273_ANGLE_EN_MASK GENMASK(3, 2)
#define TMAG5273_ANGLE_EN_OFF 0
#define TMAG5273_ANGLE_EN_X_Y 1
#define TMAG5273_ANGLE_EN_Y_Z 2
#define TMAG5273_ANGLE_EN_X_Z 3
/* bits in the TMAG5273_T_CONFIG register */
#define TMAG5273_T_CH_EN BIT(0)
/* bits in the TMAG5273_DEVICE_ID register */
#define TMAG5273_VERSION_MASK GENMASK(1, 0)
/* bits in the TMAG5273_CONV_STATUS register */
#define TMAG5273_CONV_STATUS_COMPLETE BIT(0)
enum tmag5273_channels {
TEMPERATURE = 0,
AXIS_X,
AXIS_Y,
AXIS_Z,
ANGLE,
MAGNITUDE,
};
enum tmag5273_scale_index {
MAGN_RANGE_LOW = 0,
MAGN_RANGE_HIGH,
MAGN_RANGE_NUM
};
/* state container for the TMAG5273 driver */
struct tmag5273_data {
struct device *dev;
unsigned int devid;
unsigned int version;
char name[16];
unsigned int conv_avg;
unsigned int scale;
enum tmag5273_scale_index scale_index;
unsigned int angle_measurement;
struct regmap *map;
struct regulator *vcc;
/*
* Locks the sensor for exclusive use during a measurement (which
* involves several register transactions so the regmap lock is not
* enough) so that measurements get serialized in a
* first-come-first-serve manner.
*/
struct mutex lock;
};
static const char *const tmag5273_angle_names[] = { "off", "x-y", "y-z", "x-z" };
/*
* Averaging enables additional sampling of the sensor data to reduce the noise
* effect, but also increases conversion time.
*/
static const unsigned int tmag5273_avg_table[] = {
1, 2, 4, 8, 16, 32,
};
/*
* Magnetic resolution in Gauss for different TMAG5273 versions.
* Scale[Gauss] = Range[mT] * 1000 / 2^15 * 10, (1 mT = 10 Gauss)
* Only version 1 and 2 are valid, version 0 and 3 are reserved.
*/
static const struct iio_val_int_plus_micro tmag5273_scale[][MAGN_RANGE_NUM] = {
{ { 0, 0 }, { 0, 0 } },
{ { 0, 12200 }, { 0, 24400 } },
{ { 0, 40600 }, { 0, 81200 } },
{ { 0, 0 }, { 0, 0 } },
};
static int tmag5273_get_measure(struct tmag5273_data *data, s16 *t, s16 *x,
s16 *y, s16 *z, u16 *angle, u16 *magnitude)
{
unsigned int status, val;
__be16 reg_data[4];
int ret;
mutex_lock(&data->lock);
/*
* Max. conversion time is 2425 us in 32x averaging mode for all three
* channels. Since we are in continuous measurement mode, a measurement
* may already be there, so poll for completed measurement with
* timeout.
*/
ret = regmap_read_poll_timeout(data->map, TMAG5273_CONV_STATUS, status,
status & TMAG5273_CONV_STATUS_COMPLETE,
100, 10000);
if (ret) {
dev_err(data->dev, "timeout waiting for measurement\n");
goto out_unlock;
}
ret = regmap_bulk_read(data->map, TMAG5273_T_MSB_RESULT, reg_data,
sizeof(reg_data));
if (ret)
goto out_unlock;
*t = be16_to_cpu(reg_data[0]);
*x = be16_to_cpu(reg_data[1]);
*y = be16_to_cpu(reg_data[2]);
*z = be16_to_cpu(reg_data[3]);
ret = regmap_bulk_read(data->map, TMAG5273_ANGLE_RESULT_MSB,
&reg_data[0], sizeof(reg_data[0]));
if (ret)
goto out_unlock;
/*
* angle has 9 bits integer value and 4 bits fractional part
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* 0 0 0 a a a a a a a a a f f f f
*/
*angle = be16_to_cpu(reg_data[0]);
ret = regmap_read(data->map, TMAG5273_MAGNITUDE_RESULT, &val);
if (ret < 0)
goto out_unlock;
*magnitude = val;
out_unlock:
mutex_unlock(&data->lock);
return ret;
}
static int tmag5273_write_osr(struct tmag5273_data *data, int val)
{
int i;
if (val == data->conv_avg)
return 0;
for (i = 0; i < ARRAY_SIZE(tmag5273_avg_table); i++) {
if (tmag5273_avg_table[i] == val)
break;
}
if (i == ARRAY_SIZE(tmag5273_avg_table))
return -EINVAL;
data->conv_avg = val;
return regmap_update_bits(data->map, TMAG5273_DEVICE_CONFIG_1,
TMAG5273_AVG_MODE_MASK,
FIELD_PREP(TMAG5273_AVG_MODE_MASK, i));
}
static int tmag5273_write_scale(struct tmag5273_data *data, int scale_micro)
{
u32 value;
int i;
for (i = 0; i < ARRAY_SIZE(tmag5273_scale[0]); i++) {
if (tmag5273_scale[data->version][i].micro == scale_micro)
break;
}
if (i == ARRAY_SIZE(tmag5273_scale[0]))
return -EINVAL;
data->scale_index = i;
if (data->scale_index == MAGN_RANGE_LOW)
value = 0;
else
value = TMAG5273_Z_RANGE_MASK | TMAG5273_X_Y_RANGE_MASK;
return regmap_update_bits(data->map, TMAG5273_SENSOR_CONFIG_2,
TMAG5273_Z_RANGE_MASK | TMAG5273_X_Y_RANGE_MASK, value);
}
static int tmag5273_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
struct tmag5273_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*vals = tmag5273_avg_table;
*type = IIO_VAL_INT;
*length = ARRAY_SIZE(tmag5273_avg_table);
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_MAGN:
*type = IIO_VAL_INT_PLUS_MICRO;
*vals = (int *)tmag5273_scale[data->version];
*length = ARRAY_SIZE(tmag5273_scale[data->version]) *
MAGN_RANGE_NUM;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int tmag5273_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val,
int *val2, long mask)
{
struct tmag5273_data *data = iio_priv(indio_dev);
s16 t, x, y, z;
u16 angle, magnitude;
int ret;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
case IIO_CHAN_INFO_RAW:
ret = pm_runtime_resume_and_get(data->dev);
if (ret < 0)
return ret;
ret = tmag5273_get_measure(data, &t, &x, &y, &z, &angle, &magnitude);
if (ret)
return ret;
pm_runtime_mark_last_busy(data->dev);
pm_runtime_put_autosuspend(data->dev);
switch (chan->address) {
case TEMPERATURE:
*val = t;
return IIO_VAL_INT;
case AXIS_X:
*val = x;
return IIO_VAL_INT;
case AXIS_Y:
*val = y;
return IIO_VAL_INT;
case AXIS_Z:
*val = z;
return IIO_VAL_INT;
case ANGLE:
*val = angle;
return IIO_VAL_INT;
case MAGNITUDE:
*val = magnitude;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_TEMP:
/*
* Convert device specific value to millicelsius.
* Resolution from the sensor is 60.1 LSB/celsius and
* the reference value at 25 celsius is 17508 LSBs.
*/
*val = 10000;
*val2 = 601;
return IIO_VAL_FRACTIONAL;
case IIO_MAGN:
/* Magnetic resolution in uT */
*val = 0;
*val2 = tmag5273_scale[data->version]
[data->scale_index].micro;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_ANGL:
/*
* Angle is in degrees and has four fractional bits,
* therefore use 1/16 * pi/180 to convert to radians.
*/
*val = 1000;
*val2 = 916732;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
switch (chan->type) {
case IIO_TEMP:
*val = -266314;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = data->conv_avg;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int tmag5273_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
{
struct tmag5273_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
return tmag5273_write_osr(data, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_MAGN:
if (val)
return -EINVAL;
return tmag5273_write_scale(data, val2);
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
#define TMAG5273_AXIS_CHANNEL(axis, index) \
{ \
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_type_available = \
BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_all = \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.info_mask_shared_by_all_available = \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.address = index, \
.scan_index = index, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_CPU, \
}, \
}
static const struct iio_chan_spec tmag5273_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.address = TEMPERATURE,
.scan_index = TEMPERATURE,
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
},
TMAG5273_AXIS_CHANNEL(X, AXIS_X),
TMAG5273_AXIS_CHANNEL(Y, AXIS_Y),
TMAG5273_AXIS_CHANNEL(Z, AXIS_Z),
{
.type = IIO_ANGL,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all =
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
.info_mask_shared_by_all_available =
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
.address = ANGLE,
.scan_index = ANGLE,
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
},
{
.type = IIO_DISTANCE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_all =
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
.info_mask_shared_by_all_available =
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
.address = MAGNITUDE,
.scan_index = MAGNITUDE,
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
},
IIO_CHAN_SOFT_TIMESTAMP(6),
};
static const struct iio_info tmag5273_info = {
.read_avail = tmag5273_read_avail,
.read_raw = tmag5273_read_raw,
.write_raw = tmag5273_write_raw,
};
static bool tmag5273_volatile_reg(struct device *dev, unsigned int reg)
{
return reg >= TMAG5273_T_MSB_RESULT && reg <= TMAG5273_MAGNITUDE_RESULT;
}
static const struct regmap_config tmag5273_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = TMAG5273_MAX_REG,
.volatile_reg = tmag5273_volatile_reg,
};
static int tmag5273_set_operating_mode(struct tmag5273_data *data,
unsigned int val)
{
return regmap_write(data->map, TMAG5273_DEVICE_CONFIG_2, val);
}
static void tmag5273_read_device_property(struct tmag5273_data *data)
{
struct device *dev = data->dev;
const char *str;
int ret;
data->angle_measurement = TMAG5273_ANGLE_EN_X_Y;
ret = device_property_read_string(dev, "ti,angle-measurement", &str);
if (ret)
return;
ret = match_string(tmag5273_angle_names,
ARRAY_SIZE(tmag5273_angle_names), str);
if (ret >= 0)
data->angle_measurement = ret;
}
static void tmag5273_wake_up(struct tmag5273_data *data)
{
int val;
/* Wake up the chip by sending a dummy I2C command */
regmap_read(data->map, TMAG5273_DEVICE_ID, &val);
/*
* Time to go to stand-by mode from sleep mode is 50us
* typically, during this time no I2C access is possible.
*/
usleep_range(80, 200);
}
static int tmag5273_chip_init(struct tmag5273_data *data)
{
int ret;
ret = regmap_write(data->map, TMAG5273_DEVICE_CONFIG_1,
TMAG5273_AVG_32_MODE);
if (ret)
return ret;
data->conv_avg = 32;
ret = regmap_write(data->map, TMAG5273_DEVICE_CONFIG_2,
TMAG5273_OP_MODE_CONT);
if (ret)
return ret;
ret = regmap_write(data->map, TMAG5273_SENSOR_CONFIG_1,
FIELD_PREP(TMAG5273_MAG_CH_EN_MASK,
TMAG5273_MAG_CH_EN_X_Y_Z));
if (ret)
return ret;
ret = regmap_write(data->map, TMAG5273_SENSOR_CONFIG_2,
FIELD_PREP(TMAG5273_ANGLE_EN_MASK,
data->angle_measurement));
if (ret)
return ret;
data->scale_index = MAGN_RANGE_LOW;
return regmap_write(data->map, TMAG5273_T_CONFIG, TMAG5273_T_CH_EN);
}
static int tmag5273_check_device_id(struct tmag5273_data *data)
{
__le16 devid;
int val, ret;
ret = regmap_read(data->map, TMAG5273_DEVICE_ID, &val);
if (ret)
return dev_err_probe(data->dev, ret, "failed to power on device\n");
data->version = FIELD_PREP(TMAG5273_VERSION_MASK, val);
ret = regmap_bulk_read(data->map, TMAG5273_MANUFACTURER_ID_LSB, &devid,
sizeof(devid));
if (ret)
return dev_err_probe(data->dev, ret, "failed to read device ID\n");
data->devid = le16_to_cpu(devid);
switch (data->devid) {
case TMAG5273_MANUFACTURER_ID:
/*
* The device name matches the orderable part number. 'x' stands
* for A, B, C or D devices, which have different I2C addresses.
* Versions 1 or 2 (0 and 3 is reserved) stands for different
* magnetic strengths.
*/
snprintf(data->name, sizeof(data->name), "tmag5273x%1u", data->version);
if (data->version < 1 || data->version > 2)
dev_warn(data->dev, "Unsupported device %s\n", data->name);
return 0;
default:
/*
* Only print warning in case of unknown device ID to allow
* fallback compatible in device tree.
*/
dev_warn(data->dev, "Unknown device ID 0x%x\n", data->devid);
return 0;
}
}
static void tmag5273_power_down(void *data)
{
tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_SLEEP);
}
static int tmag5273_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
struct tmag5273_data *data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
data->dev = dev;
i2c_set_clientdata(i2c, indio_dev);
data->map = devm_regmap_init_i2c(i2c, &tmag5273_regmap_config);
if (IS_ERR(data->map))
return dev_err_probe(dev, PTR_ERR(data->map),
"failed to allocate register map\n");
mutex_init(&data->lock);
ret = devm_regulator_get_enable(dev, "vcc");
if (ret)
return dev_err_probe(dev, ret, "failed to enable regulator\n");
tmag5273_wake_up(data);
ret = tmag5273_check_device_id(data);
if (ret)
return ret;
ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_CONT);
if (ret)
return dev_err_probe(dev, ret, "failed to power on device\n");
/*
* Register powerdown deferred callback which suspends the chip
* after module unloaded.
*
* TMAG5273 should be in SUSPEND mode in the two cases:
* 1) When driver is loaded, but we do not have any data or
* configuration requests to it (we are solving it using
* autosuspend feature).
* 2) When driver is unloaded and device is not used (devm action is
* used in this case).
*/
ret = devm_add_action_or_reset(dev, tmag5273_power_down, data);
if (ret)
return dev_err_probe(dev, ret, "failed to add powerdown action\n");
ret = pm_runtime_set_active(dev);
if (ret < 0)
return ret;
ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
pm_runtime_get_noresume(dev);
pm_runtime_set_autosuspend_delay(dev, TMAG5273_AUTOSLEEP_DELAY_MS);
pm_runtime_use_autosuspend(dev);
tmag5273_read_device_property(data);
ret = tmag5273_chip_init(data);
if (ret)
return dev_err_probe(dev, ret, "failed to init device\n");
indio_dev->info = &tmag5273_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->name = data->name;
indio_dev->channels = tmag5273_channels;
indio_dev->num_channels = ARRAY_SIZE(tmag5273_channels);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
return dev_err_probe(dev, ret, "device register failed\n");
return 0;
}
static int tmag5273_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tmag5273_data *data = iio_priv(indio_dev);
int ret;
ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_SLEEP);
if (ret)
dev_err(dev, "failed to power off device (%pe)\n", ERR_PTR(ret));
return ret;
}
static int tmag5273_runtime_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tmag5273_data *data = iio_priv(indio_dev);
int ret;
tmag5273_wake_up(data);
ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_CONT);
if (ret)
dev_err(dev, "failed to power on device (%pe)\n", ERR_PTR(ret));
return ret;
}
static DEFINE_RUNTIME_DEV_PM_OPS(tmag5273_pm_ops,
tmag5273_runtime_suspend, tmag5273_runtime_resume,
NULL);
static const struct i2c_device_id tmag5273_id[] = {
{ "tmag5273" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, tmag5273_id);
static const struct of_device_id tmag5273_of_match[] = {
{ .compatible = "ti,tmag5273" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, tmag5273_of_match);
static struct i2c_driver tmag5273_driver = {
.driver = {
.name = "tmag5273",
.of_match_table = tmag5273_of_match,
.pm = pm_ptr(&tmag5273_pm_ops),
},
.probe_new = tmag5273_probe,
.id_table = tmag5273_id,
};
module_i2c_driver(tmag5273_driver);
MODULE_DESCRIPTION("TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor driver");
MODULE_AUTHOR("Gerald Loacker <gerald.loacker@wolfvision.net>");
MODULE_LICENSE("GPL");
......@@ -13,8 +13,6 @@
#include <linux/iio/iio.h>
#include <linux/mutex.h>
struct regulator;
#define MS5611_RESET 0x1e
#define MS5611_READ_ADC 0x00
#define MS5611_READ_PROM_WORD 0xA0
......@@ -52,11 +50,9 @@ struct ms5611_state {
int (*compensate_temp_and_pressure)(struct ms5611_state *st, s32 *temp,
s32 *pressure);
struct regulator *vdd;
};
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
const char *name, int type);
void ms5611_remove(struct iio_dev *indio_dev);
#endif /* _MS5611_H */
......@@ -380,40 +380,21 @@ static const struct iio_info ms5611_info = {
static int ms5611_init(struct iio_dev *indio_dev)
{
int ret;
struct ms5611_state *st = iio_priv(indio_dev);
/* Enable attached regulator if any. */
st->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd");
if (IS_ERR(st->vdd))
return PTR_ERR(st->vdd);
ret = regulator_enable(st->vdd);
if (ret) {
dev_err(indio_dev->dev.parent,
"failed to enable Vdd supply: %d\n", ret);
ret = devm_regulator_get_enable(indio_dev->dev.parent, "vdd");
if (ret)
return ret;
}
ret = ms5611_reset(indio_dev);
if (ret < 0)
goto err_regulator_disable;
return ret;
ret = ms5611_read_prom(indio_dev);
if (ret < 0)
goto err_regulator_disable;
return ret;
return 0;
err_regulator_disable:
regulator_disable(st->vdd);
return ret;
}
static void ms5611_fini(const struct iio_dev *indio_dev)
{
const struct ms5611_state *st = iio_priv(indio_dev);
regulator_disable(st->vdd);
}
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
......@@ -453,37 +434,23 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
if (ret < 0)
return ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
ms5611_trigger_handler, NULL);
if (ret < 0) {
dev_err(dev, "iio triggered buffer setup failed\n");
goto err_fini;
return ret;
}
ret = iio_device_register(indio_dev);
ret = devm_iio_device_register(dev, indio_dev);
if (ret < 0) {
dev_err(dev, "unable to register iio device\n");
goto err_buffer_cleanup;
return ret;
}
return 0;
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
err_fini:
ms5611_fini(indio_dev);
return ret;
}
EXPORT_SYMBOL_NS(ms5611_probe, IIO_MS5611);
void ms5611_remove(struct iio_dev *indio_dev)
{
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
ms5611_fini(indio_dev);
}
EXPORT_SYMBOL_NS(ms5611_remove, IIO_MS5611);
MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("MS5611 core driver");
MODULE_LICENSE("GPL v2");
......@@ -105,11 +105,6 @@ static int ms5611_i2c_probe(struct i2c_client *client)
return ms5611_probe(indio_dev, &client->dev, id->name, id->driver_data);
}
static void ms5611_i2c_remove(struct i2c_client *client)
{
ms5611_remove(i2c_get_clientdata(client));
}
static const struct of_device_id ms5611_i2c_matches[] = {
{ .compatible = "meas,ms5611" },
{ .compatible = "meas,ms5607" },
......@@ -131,7 +126,6 @@ static struct i2c_driver ms5611_driver = {
},
.id_table = ms5611_id,
.probe_new = ms5611_i2c_probe,
.remove = ms5611_i2c_remove,
};
module_i2c_driver(ms5611_driver);
......
......@@ -107,11 +107,6 @@ static int ms5611_spi_probe(struct spi_device *spi)
spi_get_device_id(spi)->driver_data);
}
static void ms5611_spi_remove(struct spi_device *spi)
{
ms5611_remove(spi_get_drvdata(spi));
}
static const struct of_device_id ms5611_spi_matches[] = {
{ .compatible = "meas,ms5611" },
{ .compatible = "meas,ms5607" },
......@@ -133,7 +128,6 @@ static struct spi_driver ms5611_driver = {
},
.id_table = ms5611_id,
.probe = ms5611_spi_probe,
.remove = ms5611_spi_remove,
};
module_spi_driver(ms5611_driver);
......
......@@ -381,6 +381,11 @@ s64 iio_get_time_ns(const struct iio_dev *indio_dev);
#define INDIO_MAX_RAW_ELEMENTS 4
struct iio_val_int_plus_micro {
int integer;
int micro;
};
struct iio_trigger; /* forward declaration */
/**
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LINUX_TSL2563_H
#define __LINUX_TSL2563_H
struct tsl2563_platform_data {
int cover_comp_gain;
};
#endif /* __LINUX_TSL2563_H */
......@@ -264,6 +264,7 @@ int iioutils_get_param_float(float *output, const char *param_name,
if (fscanf(sysfsfp, "%f", output) != 1)
ret = errno ? -errno : -ENODATA;
fclose(sysfsfp);
break;
}
error_free_filename:
......@@ -345,9 +346,9 @@ int build_channel_array(const char *device_dir, int buffer_idx,
}
sysfsfp = fopen(filename, "r");
free(filename);
if (!sysfsfp) {
ret = -errno;
free(filename);
goto error_close_dir;
}
......@@ -357,7 +358,6 @@ int build_channel_array(const char *device_dir, int buffer_idx,
if (fclose(sysfsfp))
perror("build_channel_array(): Failed to close file");
free(filename);
goto error_close_dir;
}
if (ret == 1)
......@@ -365,11 +365,9 @@ int build_channel_array(const char *device_dir, int buffer_idx,
if (fclose(sysfsfp)) {
ret = -errno;
free(filename);
goto error_close_dir;
}
free(filename);
}
*ci_array = malloc(sizeof(**ci_array) * (*counter));
......@@ -395,9 +393,9 @@ int build_channel_array(const char *device_dir, int buffer_idx,
}
sysfsfp = fopen(filename, "r");
free(filename);
if (!sysfsfp) {
ret = -errno;
free(filename);
count--;
goto error_cleanup_array;
}
......@@ -405,20 +403,17 @@ int build_channel_array(const char *device_dir, int buffer_idx,
errno = 0;
if (fscanf(sysfsfp, "%i", &current_enabled) != 1) {
ret = errno ? -errno : -ENODATA;
free(filename);
count--;
goto error_cleanup_array;
}
if (fclose(sysfsfp)) {
ret = -errno;
free(filename);
count--;
goto error_cleanup_array;
}
if (!current_enabled) {
free(filename);
count--;
continue;
}
......@@ -429,7 +424,6 @@ int build_channel_array(const char *device_dir, int buffer_idx,
strlen(ent->d_name) -
strlen("_en"));
if (!current->name) {
free(filename);
ret = -ENOMEM;
count--;
goto error_cleanup_array;
......@@ -439,7 +433,6 @@ int build_channel_array(const char *device_dir, int buffer_idx,
ret = iioutils_break_up_name(current->name,
&current->generic_name);
if (ret) {
free(filename);
free(current->name);
count--;
goto error_cleanup_array;
......@@ -450,17 +443,16 @@ int build_channel_array(const char *device_dir, int buffer_idx,
scan_el_dir,
current->name);
if (ret < 0) {
free(filename);
ret = -ENOMEM;
goto error_cleanup_array;
}
sysfsfp = fopen(filename, "r");
free(filename);
if (!sysfsfp) {
ret = -errno;
fprintf(stderr, "failed to open %s\n",
filename);
free(filename);
fprintf(stderr, "failed to open %s/%s_index\n",
scan_el_dir, current->name);
goto error_cleanup_array;
}
......@@ -470,17 +462,14 @@ int build_channel_array(const char *device_dir, int buffer_idx,
if (fclose(sysfsfp))
perror("build_channel_array(): Failed to close file");
free(filename);
goto error_cleanup_array;
}
if (fclose(sysfsfp)) {
ret = -errno;
free(filename);
goto error_cleanup_array;
}
free(filename);
/* Find the scale */
ret = iioutils_get_param_float(&current->scale,
"scale",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册