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

New device support
 * bosch,bmp280
   - Add support for BMP580 - includes significant refactoring and general
     driver cleanup + support for non-volatile memory for trimming and config
     parameters.
 * rohm BU27034
   - New driver for this 3 channel ambient light sensor.
   - New support library for devices where both integration time and
     amplifier gain are configurable.  In these cases a scale change
     may require changing bother underlying values. This library module
     provides code to help with this.
 * st,accel
   - Add support for IIS328DQ (ID only as compatible wtih LIS331DL)
 * st,lsm6dsx
   - Add support for ASM330LHB automotive MEMS sensor.
 * ti,ads1100, ads1000
   - New driver for these 16 bit ADCs.
 * ti,tmp117
   - Add support for older tmp116 device. Includes some general driver cleanup.
 
 Staging driver drops
 * adi,ade7854
   - Driver was a very long way from compliant with IIO infrastructure and ABI.
     If anyone wants a non staging version of this driver they are better off
     starting from scratch. Hence drop it and the associated meter.h header.
 
 Features
 * adi,ad7441r
   - Add DT binding to set sink current for digital input.
 * semtech,sx9324,9360
   - Support older register mapping from firmware designed for windows.
 
 Core improvements.
 * Move iio_trigger_poll() docs to next to the implementation and add a note
   on expected caller context.
 * Rename iio_trigger_poll_chained() to iio_trigger_poll_nested() so
   as to use more standard / common terminology.
 * Improve main ABI docs references to offset and scale for raw values by
   making them consistent and clear.
 
 Cleanups and minor fixes:
 * adi,ad5592r
   - Add GPIO names - useful for debug.
 * adi,ad7441r
   - Fix current input, loop powered mode configuration setup.
 * adi,adis16475
   - Fix wrong commented value for minimum advised lower rate.
 * adi,admv1013
   - Use devm_clk_get_enabled() to reduce boilerplate.
 * adi,ads1210
   - Fix wrong bits for writing config register (late fix and has
     been broken a long time so not rushed upstream)
 * amlogic,meson-saradc
   - Improve cleanup in error handling if BL30 handshake fails.
 * apex-embedded,stx104
   - Migrate to regmap and use regmap_read_poll_timeout() to neatly handle
     retries.
   - Add local mutex to close various races.
   - Use define U16_MAX rather than value for limit.
   - Improve code readability with minor reorganization.
 * atmel,ad91-sama5d2
   - Drop trivial dead code.
 * kionix,kx022a
   - Drop unused structure element.
 * linear,ltc2983
   - Reorganize bindings doc to enable unevaluatedProperties to be set
     in one place for all child nodes.
   - Make binding for adi,custom-thermocouple accept signed values.
 * maxim,max44000
   - Add OF Device matching (of_match_table was not correctly set).
 * maxim,max5522
   - Missing static
 * measurement-computing,cio-dac
   - Fix wrong part name in comments.
   - Migrate to regmap.
   - Improve includes by replacing bitops.h with more direct bits.h
 * qcom,pm8xxx-xoadc
   - Remove a check that can never fail.
 * renesas,rcar-gyroadc
   - DT binding documentation improvements.
   - Tidy up an unused warning with __maybe_unused.
 * semtech,sx_common
   - Drop docs for a structure element that doesn't exist.
 * semtech,sx9500
   - Drop ACPI_PTR() and of_match_ptr() protections that just complicate
     the code / block some firmware registration types that would otherwise
     work.
 * sensiron,sps30
   - Comment formatting tidy up.
 * st,sensors
   - Drop duplicate text in DT binding.
 * st,stm32-adc
   - Add some missing static markings.
 * ti,ads1100
   - Use correct return code in dev_err_probe() call.
 * x-powers,axp20x_adc - precursor series to simplify addition of AXP192.
   - General code cleanup / minor refactoring for better readabilty of code.
   - Switch from boolean value to mask for adc_en2 field to avoid hard coding
     a mask that will be different in AXP192
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAmQ0QiIRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0Foh8dhAAlUDsEWKoYc2DMXs//UVh5ortcD/tVMDj
 +Oe6c92vTvZaritF9JN5fS5oO48d2Qx7VC8mIZvsCgLdloYtM8qns8KwPU8W589j
 Mdaq2e/p+CCVLxn+RttiINk7C/okXmc6nh21TABYgaHbi1Yzu0LooTobrdd5GHZX
 l+5n8diTgebkKWLKHtR/Wo0hZVdFtrxOb+bP6Lu+yjwUhlvmnuC18OPthDHBwss1
 3nWL5sAR8DWKTKPwmWl1pnn5fuZXxAnxYhsgzMiC/dNrv4GfjV76xFvwdFG97Qc4
 Qifo/t6AM6g7HplfRjtdGXGnew8RBj9jzw3W8NUzb/7UF0ywF+6KHBrgWVKLumsW
 uGsLGQsOoCVmycnppUZSZV0eI5qT+WS6GT0XucB3wlUriS56YgpMU/RVo9iE8yUd
 VqjacBJrh1SUIPQKXAGb1dlrfgxGRUFcDxea/XuqzXZIn4U3JM1wb0awIlfcrTNm
 4EdVH9r6lwU/7KcrVC10iZz5ZMFy15wNmCl4+Sn56QNIekXYMXFCHsoZs64UMuhU
 leczQdEp/wEG1p0mWdrpC4aEsMfK27RSbTh8AS3LiPHqI9FD+Jg+wULF6wpMIHvY
 rm4kxlznTdKsYOiHsOkYXCi06kS5k2SqQHtbKS3jiSsCw30eX6xzVjG8szivFIS5
 KEKqxRs1BxM=
 =xxs6
 -----END PGP SIGNATURE-----

Merge tag 'iio-for-6.4a' 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.4 cycle.

New device support
* bosch,bmp280
  - Add support for BMP580 - includes significant refactoring and general
    driver cleanup + support for non-volatile memory for trimming and config
    parameters.
* rohm BU27034
  - New driver for this 3 channel ambient light sensor.
  - New support library for devices where both integration time and
    amplifier gain are configurable.  In these cases a scale change
    may require changing bother underlying values. This library module
    provides code to help with this.
* st,accel
  - Add support for IIS328DQ (ID only as compatible wtih LIS331DL)
* st,lsm6dsx
  - Add support for ASM330LHB automotive MEMS sensor.
* ti,ads1100, ads1000
  - New driver for these 16 bit ADCs.
* ti,tmp117
  - Add support for older tmp116 device. Includes some general driver cleanup.

Staging driver drops
* adi,ade7854
  - Driver was a very long way from compliant with IIO infrastructure and ABI.
    If anyone wants a non staging version of this driver they are better off
    starting from scratch. Hence drop it and the associated meter.h header.

Features
* adi,ad7441r
  - Add DT binding to set sink current for digital input.
* semtech,sx9324,9360
  - Support older register mapping from firmware designed for windows.

Core improvements.
* Move iio_trigger_poll() docs to next to the implementation and add a note
  on expected caller context.
* Rename iio_trigger_poll_chained() to iio_trigger_poll_nested() so
  as to use more standard / common terminology.
* Improve main ABI docs references to offset and scale for raw values by
  making them consistent and clear.

Cleanups and minor fixes:
* adi,ad5592r
  - Add GPIO names - useful for debug.
* adi,ad7441r
  - Fix current input, loop powered mode configuration setup.
* adi,adis16475
  - Fix wrong commented value for minimum advised lower rate.
* adi,admv1013
  - Use devm_clk_get_enabled() to reduce boilerplate.
* adi,ads1210
  - Fix wrong bits for writing config register (late fix and has
    been broken a long time so not rushed upstream)
* amlogic,meson-saradc
  - Improve cleanup in error handling if BL30 handshake fails.
* apex-embedded,stx104
  - Migrate to regmap and use regmap_read_poll_timeout() to neatly handle
    retries.
  - Add local mutex to close various races.
  - Use define U16_MAX rather than value for limit.
  - Improve code readability with minor reorganization.
* atmel,ad91-sama5d2
  - Drop trivial dead code.
* kionix,kx022a
  - Drop unused structure element.
* linear,ltc2983
  - Reorganize bindings doc to enable unevaluatedProperties to be set
    in one place for all child nodes.
  - Make binding for adi,custom-thermocouple accept signed values.
* maxim,max44000
  - Add OF Device matching (of_match_table was not correctly set).
* maxim,max5522
  - Missing static
* measurement-computing,cio-dac
  - Fix wrong part name in comments.
  - Migrate to regmap.
  - Improve includes by replacing bitops.h with more direct bits.h
* qcom,pm8xxx-xoadc
  - Remove a check that can never fail.
* renesas,rcar-gyroadc
  - DT binding documentation improvements.
  - Tidy up an unused warning with __maybe_unused.
* semtech,sx_common
  - Drop docs for a structure element that doesn't exist.
* semtech,sx9500
  - Drop ACPI_PTR() and of_match_ptr() protections that just complicate
    the code / block some firmware registration types that would otherwise
    work.
* sensiron,sps30
  - Comment formatting tidy up.
* st,sensors
  - Drop duplicate text in DT binding.
* st,stm32-adc
  - Add some missing static markings.
* ti,ads1100
  - Use correct return code in dev_err_probe() call.
* x-powers,axp20x_adc - precursor series to simplify addition of AXP192.
  - General code cleanup / minor refactoring for better readabilty of code.
  - Switch from boolean value to mask for adc_en2 field to avoid hard coding
    a mask that will be different in AXP192

* tag 'iio-for-6.4a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (63 commits)
  MAINTAINERS: Add ROHM BU27034
  iio: light: ROHM BU27034 Ambient Light Sensor
  dt-bindings: iio: light: Support ROHM BU27034
  MAINTAINERS: Add IIO gain-time-scale helpers
  iio: light: Add gain-time-scale helpers
  doc: Make sysfs-bus-iio doc more exact
  iio: dac: set variable max5522_channels storage-class-specifier to static
  dt-bindings: iio: temperature: ltc2983: Make 'adi,custom-thermocouple' signed
  dt-bindings: iio: temperature: ltc2983: Fix child node unevaluated properties
  iio: addac: stx104: Use regmap_read_poll_timeout() for conversion poll
  iio: addac: stx104: Migrate to the regmap API
  iio: addac: stx104: Improve indentation in stx104_write_raw()
  iio: addac: stx104: Use define rather than hardcoded limit for write val
  iio: addac: stx104: Fix race condition when converting analog-to-digital
  iio: addac: stx104: Fix race condition for stx104_write_raw()
  dt-bindings: iio: st-sensors: Fix repeated text
  staging: iio: resolver: ads1210: fix config mode
  iio: adc: ti-ads1100: fix error code in probe()
  iio: accel: add support for IIS328DQ variant
  dt-bindings: iio: st-sensors: Add IIS328DQ accelerometer
  ...
This commit is contained in:
Greg Kroah-Hartman 2023-04-12 09:45:34 +02:00
commit fba51482b6
91 changed files with 5143 additions and 2235 deletions

View File

@ -1807,8 +1807,8 @@ What: /sys/bus/iio/devices/iio:deviceX/out_resistanceX_raw
KernelVersion: 4.3
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled no offset etc.) resistance reading that can be processed
into an ohm value.
Raw (unscaled no offset etc.) resistance reading.
Units after application of scale and offset are ohms.
What: /sys/bus/iio/devices/iio:deviceX/heater_enable
KernelVersion: 4.1.0
@ -1894,8 +1894,9 @@ What: /sys/bus/iio/devices/iio:deviceX/in_electricalconductivity_raw
KernelVersion: 4.8
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled no offset etc.) electric conductivity reading that
can be processed to siemens per meter.
Raw (unscaled no offset etc.) electric conductivity reading.
Units after application of scale and offset are siemens per
meter.
What: /sys/bus/iio/devices/iio:deviceX/in_countY_raw
KernelVersion: 4.10
@ -1951,8 +1952,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_phaseY_raw
KernelVersion: 4.18
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled) phase difference reading from channel Y
that can be processed to radians.
Raw (unscaled) phase difference reading from channel Y.
Units after application of scale and offset are radians.
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm1_input
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm1_input

View File

@ -34,9 +34,11 @@ properties:
clock-names:
const: fck
power-domains: true
power-domains:
maxItems: 1
resets: true
resets:
maxItems: 1
"#address-cells":
const: 1
@ -51,6 +53,8 @@ required:
- reg
- clocks
- clock-names
- power-domains
- resets
- "#address-cells"
- "#size-cells"
@ -108,36 +112,30 @@ patternProperties:
examples:
- |
#include <dt-bindings/clock/r8a7791-clock.h>
#include <dt-bindings/clock/r8a7791-cpg-mssr.h>
#include <dt-bindings/power/r8a7791-sysc.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
adc@e6e54000 {
compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc";
reg = <0 0xe6e54000 0 64>;
clocks = <&mstp9_clks R8A7791_CLK_GYROADC>;
clock-names = "fck";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
adc@e6e54000 {
compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc";
reg = <0xe6e54000 64>;
clocks = <&cpg CPG_MOD 901>;
clock-names = "fck";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
resets = <&cpg 901>;
pinctrl-0 = <&adc_pins>;
pinctrl-names = "default";
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
reg = <0>;
compatible = "maxim,max1162";
vref-supply = <&vref_max1162>;
};
adc@0 {
reg = <0>;
compatible = "maxim,max1162";
vref-supply = <&vref_max1162>;
};
adc@1 {
reg = <1>;
compatible = "maxim,max1162";
vref-supply = <&vref_max1162>;
};
adc@1 {
reg = <1>;
compatible = "maxim,max1162";
vref-supply = <&vref_max1162>;
};
};
...

View File

@ -0,0 +1,46 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/ti,ads1100.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI ADS1100/ADS1000 single channel I2C analog to digital converter
maintainers:
- Mike Looijmans <mike.looijmans@topic.nl>
description: |
Datasheet at: https://www.ti.com/lit/gpn/ads1100
properties:
compatible:
enum:
- ti,ads1100
- ti,ads1000
reg:
maxItems: 1
vdd-supply: true
"#io-channel-cells":
const: 0
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@49 {
compatible = "ti,ads1100";
reg = <0x49>;
};
};
...

View File

@ -101,6 +101,15 @@ patternProperties:
When not configured as a comparator, the GPO will be treated as an
output-only GPIO.
drive-strength-microamp:
description: |
For channels configured as digital input, this configures the sink
current.
minimum: 0
maximum: 1800
default: 0
multipleOf: 120
required:
- reg

View File

@ -46,6 +46,9 @@ properties:
- items:
- const: st,ism330is
- const: st,lsm6dso16is
- items:
- const: st,asm330lhb
- const: st,asm330lhh
reg:
maxItems: 1

View File

@ -0,0 +1,46 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/light/rohm,bu27034.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ROHM BU27034 ambient light sensor
maintainers:
- Matti Vaittinen <mazziesaccount@gmail.com>
description: |
ROHM BU27034 is an ambient light sesnor with 3 channels and 3 photo diodes
capable of detecting a very wide range of illuminance. Typical application
is adjusting LCD and backlight power of TVs and mobile phones.
https://fscdn.rohm.com/en/products/databook/datasheet/ic/sensor/light/bu27034nuc-e.pdf
properties:
compatible:
const: rohm,bu27034
reg:
maxItems: 1
vdd-supply: true
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
light-sensor@38 {
compatible = "rohm,bu27034";
reg = <0x38>;
vdd-supply = <&vdd>;
};
};
...

View File

@ -17,6 +17,7 @@ description: |
https://www.bosch-sensortec.com/bst/products/all_products/bmp280
https://www.bosch-sensortec.com/bst/products/all_products/bme280
https://www.bosch-sensortec.com/bst/products/all_products/bmp380
https://www.bosch-sensortec.com/bst/products/all_products/bmp580
properties:
compatible:
@ -26,6 +27,7 @@ properties:
- bosch,bmp280
- bosch,bme280
- bosch,bmp380
- bosch,bmp580
reg:
maxItems: 1

View File

@ -11,9 +11,6 @@ description: The STMicroelectronics sensor devices are pretty straight-forward
what type of sensor it is.
Note that whilst this covers many STMicro MEMs sensors, some more complex
IMUs need their own bindings.
The STMicroelectronics sensor devices are pretty straight-forward I2C or
SPI devices, all sharing the same device tree descriptions no matter what
type of sensor it is.
maintainers:
- Denis Ciocca <denis.ciocca@st.com>
@ -48,6 +45,9 @@ properties:
- st,lsm330d-accel
- st,lsm330dl-accel
- st,lsm330dlc-accel
- items:
- const: st,iis328dq
- const: st,h3lis331dl-accel
- description: Silan Accelerometers
enum:
- silan,sc7a20

View File

@ -18,6 +18,28 @@ description: |
https://www.analog.com/media/en/technical-documentation/data-sheets/29861fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ltm2985.pdf
$defs:
sensor-node:
type: object
description: Sensor node common constraints
properties:
reg:
description:
Channel number. Connects the sensor to the channel with this number
of the device.
minimum: 1
maximum: 20
adi,sensor-type:
description: Type of sensor connected to the device.
$ref: /schemas/types.yaml#/definitions/uint32
required:
- reg
- adi,sensor-type
properties:
compatible:
oneOf:
@ -64,28 +86,10 @@ properties:
const: 0
patternProperties:
"@([0-9a-f]+)$":
type: object
description: Sensor.
properties:
reg:
description:
Channel number. Connects the sensor to the channel with this number
of the device.
minimum: 1
maximum: 20
adi,sensor-type:
description: Type of sensor connected to the device.
$ref: /schemas/types.yaml#/definitions/uint32
required:
- reg
- adi,sensor-type
"^thermocouple@":
type: object
$ref: '#/$defs/sensor-node'
unevaluatedProperties: false
description: Thermocouple sensor.
properties:
@ -123,7 +127,7 @@ patternProperties:
description:
Used for digitizing custom thermocouples.
See Page 59 of the datasheet.
$ref: /schemas/types.yaml#/definitions/uint64-matrix
$ref: /schemas/types.yaml#/definitions/int64-matrix
minItems: 3
maxItems: 64
items:
@ -141,7 +145,9 @@ patternProperties:
- adi,custom-thermocouple
"^diode@":
type: object
$ref: '#/$defs/sensor-node'
unevaluatedProperties: false
description: Diode sensor.
properties:
@ -184,7 +190,8 @@ patternProperties:
default: 0
"^rtd@":
type: object
$ref: '#/$defs/sensor-node'
unevaluatedProperties: false
description: RTD sensor.
properties:
@ -282,7 +289,8 @@ patternProperties:
- adi,custom-rtd
"^thermistor@":
type: object
$ref: '#/$defs/sensor-node'
unevaluatedProperties: false
description: Thermistor sensor.
properties:
@ -383,7 +391,8 @@ patternProperties:
- adi,custom-thermistor
"^adc@":
type: object
$ref: '#/$defs/sensor-node'
unevaluatedProperties: false
description: Direct ADC sensor.
properties:
@ -397,7 +406,8 @@ patternProperties:
type: boolean
"^temp@":
type: object
$ref: '#/$defs/sensor-node'
unevaluatedProperties: false
description: Active analog temperature sensor.
properties:
@ -426,7 +436,8 @@ patternProperties:
- adi,custom-temp
"^rsense@":
type: object
$ref: '#/$defs/sensor-node'
unevaluatedProperties: false
description: Sense resistor sensor.
properties:

View File

@ -7,9 +7,10 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI TMP117 - Digital temperature sensor with integrated NV memory
description: |
TI TMP117 - Digital temperature sensor with integrated NV memory that supports
I2C interface.
https://www.ti.com/lit/gpn/tmp1
TI TMP116/117 - Digital temperature sensor with integrated NV memory that
supports I2C interface.
https://www.ti.com/lit/gpn/tmp116
https://www.ti.com/lit/gpn/tmp117
maintainers:
- Puranjay Mohan <puranjay12@gmail.com>
@ -17,6 +18,7 @@ maintainers:
properties:
compatible:
enum:
- ti,tmp116
- ti,tmp117
reg:

View File

@ -9947,6 +9947,13 @@ F: Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector
F: Documentation/devicetree/bindings/iio/adc/envelope-detector.yaml
F: drivers/iio/adc/envelope-detector.c
IIO LIGHT SENSOR GAIN-TIME-SCALE HELPERS
M: Matti Vaittinen <mazziesaccount@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/light/gain-time-scale-helper.c
F: drivers/iio/light/gain-time-scale-helper.h
IIO MULTIPLEXER
M: Peter Rosin <peda@axentia.se>
L: linux-iio@vger.kernel.org
@ -18092,6 +18099,12 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/light/bh1750.yaml
F: drivers/iio/light/bh1750.c
ROHM BU27034 AMBIENT LIGHT SENSOR DRIVER
M: Matti Vaittinen <mazziesaccount@gmail.com>
L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/light/rohm-bu27034.c
ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS
M: Marek Vasut <marek.vasut+renesas@gmail.com>
L: linux-kernel@vger.kernel.org

View File

@ -30,6 +30,9 @@ config IIO_CONFIGFS
(e.g. software triggers). For more info see
Documentation/iio/iio_configfs.rst.
config IIO_GTS_HELPER
tristate
config IIO_TRIGGER
bool "Enable triggered sampling support"
help

View File

@ -9,6 +9,7 @@ industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o
obj-$(CONFIG_IIO_GTS_HELPER) += industrialio-gts-helper.o
obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o
obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o
obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o

View File

@ -1688,7 +1688,7 @@ static irqreturn_t bma400_interrupt(int irq, void *private)
if (FIELD_GET(BMA400_INT_DRDY_MSK, le16_to_cpu(data->status))) {
mutex_unlock(&data->mutex);
iio_trigger_poll_chained(data->trig);
iio_trigger_poll_nested(data->trig);
return IRQ_HANDLED;
}

View File

@ -162,7 +162,6 @@ struct kx022a_data {
int inc_reg;
int ien_reg;
unsigned int g_range;
unsigned int state;
unsigned int odr_ns;
@ -900,7 +899,7 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private)
mutex_lock(&data->mutex);
if (data->trigger_enabled) {
iio_trigger_poll_chained(data->trig);
iio_trigger_poll_nested(data->trig);
ret = IRQ_HANDLED;
}

View File

@ -1067,7 +1067,7 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
return IRQ_NONE;
if (src & MMA8452_INT_DRDY) {
iio_trigger_poll_chained(indio_dev->trig);
iio_trigger_poll_nested(indio_dev->trig);
ret = IRQ_HANDLED;
}

View File

@ -951,7 +951,7 @@ static irqreturn_t msa311_irq_thread(int irq, void *p)
}
if (new_data_int_enabled)
iio_trigger_poll_chained(msa311->new_data_trig);
iio_trigger_poll_nested(msa311->new_data_trig);
return IRQ_HANDLED;
}

View File

@ -39,6 +39,7 @@
#define LIS302DL_ACCEL_DEV_NAME "lis302dl"
#define LSM303C_ACCEL_DEV_NAME "lsm303c_accel"
#define SC7A20_ACCEL_DEV_NAME "sc7a20"
#define IIS328DQ_ACCEL_DEV_NAME "iis328dq"
#ifdef CONFIG_IIO_BUFFER

View File

@ -517,6 +517,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = H3LIS331DL_ACCEL_DEV_NAME,
[1] = IIS328DQ_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {

View File

@ -119,6 +119,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "silan,sc7a20",
.data = SC7A20_ACCEL_DEV_NAME,
},
{
.compatible = "st,iis328dq",
.data = IIS328DQ_ACCEL_DEV_NAME,
},
{},
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
@ -157,6 +161,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ LIS302DL_ACCEL_DEV_NAME },
{ LSM303C_ACCEL_DEV_NAME },
{ SC7A20_ACCEL_DEV_NAME },
{ IIS328DQ_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);

View File

@ -100,6 +100,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lsm303c-accel",
.data = LSM303C_ACCEL_DEV_NAME,
},
{
.compatible = "st,iis328dq",
.data = IIS328DQ_ACCEL_DEV_NAME,
},
{}
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
@ -157,6 +161,7 @@ static const struct spi_device_id st_accel_id_table[] = {
{ LIS3DE_ACCEL_DEV_NAME },
{ LIS302DL_ACCEL_DEV_NAME },
{ LSM303C_ACCEL_DEV_NAME },
{ IIS328DQ_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);

View File

@ -1229,6 +1229,16 @@ config TI_ADS7924
This driver can also be built as a module. If so, the module will be
called ti-ads7924.
config TI_ADS1100
tristate "Texas Instruments ADS1100 and ADS1000 ADC"
depends on I2C
help
If you say yes here you get support for Texas Instruments ADS1100 and
ADS1000 ADC chips.
This driver can also be built as a module. If so, the module will be
called ti-ads1100.
config TI_ADS7950
tristate "Texas Instruments ADS7950 ADC driver"
depends on SPI && GPIOLIB

View File

@ -108,6 +108,7 @@ 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_ADS1100) += ti-ads1100.o
obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o
obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o

View File

@ -477,7 +477,7 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id)
if (iio_buffer_enabled(indio_dev)) {
gpiod_set_value(st->gpio_convst, 0);
iio_trigger_poll_chained(st->trig);
iio_trigger_poll_nested(st->trig);
} else {
complete(&st->completion);
}

View File

@ -1194,7 +1194,7 @@ static void at91_dma_buffer_done(void *data)
{
struct iio_dev *indio_dev = data;
iio_trigger_poll_chained(indio_dev->trig);
iio_trigger_poll_nested(indio_dev->trig);
}
static int at91_adc_dma_start(struct iio_dev *indio_dev)
@ -2400,12 +2400,8 @@ static int at91_adc_probe(struct platform_device *pdev)
st->dma_st.phys_addr = res->start;
st->irq = platform_get_irq(pdev, 0);
if (st->irq <= 0) {
if (!st->irq)
st->irq = -ENXIO;
if (st->irq < 0)
return st->irq;
}
st->per_clk = devm_clk_get(&pdev->dev, "adc_clk");
if (IS_ERR(st->per_clk))

View File

@ -5,6 +5,7 @@
* Quentin Schulz <quentin.schulz@free-electrons.com>
*/
#include <linux/bitfield.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@ -22,20 +23,20 @@
#include <linux/mfd/axp20x.h>
#define AXP20X_ADC_EN1_MASK GENMASK(7, 0)
#define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7))
#define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0))
#define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0)
#define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1)
#define AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(x) ((x) & BIT(0))
#define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x) (((x) & BIT(0)) << 1)
#define AXP20X_ADC_RATE_MASK GENMASK(7, 6)
#define AXP20X_ADC_RATE_HZ(x) ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
#define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
#define AXP813_V_I_ADC_RATE_MASK GENMASK(5, 4)
#define AXP813_ADC_RATE_MASK (AXP20X_ADC_RATE_MASK | AXP813_V_I_ADC_RATE_MASK)
#define AXP20X_ADC_RATE_HZ(x) ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
#define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
#define AXP813_TS_GPIO0_ADC_RATE_HZ(x) AXP20X_ADC_RATE_HZ(x)
#define AXP813_V_I_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 4) & AXP813_V_I_ADC_RATE_MASK)
#define AXP813_ADC_RATE_HZ(x) (AXP20X_ADC_RATE_HZ(x) | AXP813_V_I_ADC_RATE_HZ(x))
@ -234,7 +235,7 @@ static int axp20x_adc_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
int size = 12;
int ret, size;
/*
* N.B.: Unlike the Chinese datasheets tell, the charging current is
@ -246,10 +247,11 @@ static int axp20x_adc_raw(struct iio_dev *indio_dev,
else
size = 12;
*val = axp20x_read_variable_width(info->regmap, chan->address, size);
if (*val < 0)
return *val;
ret = axp20x_read_variable_width(info->regmap, chan->address, size);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
}
@ -257,11 +259,13 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
int ret;
*val = axp20x_read_variable_width(info->regmap, chan->address, 12);
if (*val < 0)
return *val;
ret = axp20x_read_variable_width(info->regmap, chan->address, 12);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
}
@ -269,11 +273,13 @@ static int axp813_adc_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
int ret;
*val = axp20x_read_variable_width(info->regmap, chan->address, 12);
if (*val < 0)
return *val;
ret = axp20x_read_variable_width(info->regmap, chan->address, 12);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
}
@ -443,27 +449,27 @@ static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
int *val)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
unsigned int regval;
int ret;
ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, val);
ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, &regval);
if (ret < 0)
return ret;
switch (channel) {
case AXP20X_GPIO0_V:
*val &= AXP20X_GPIO10_IN_RANGE_GPIO0;
regval = FIELD_GET(AXP20X_GPIO10_IN_RANGE_GPIO0, regval);
break;
case AXP20X_GPIO1_V:
*val &= AXP20X_GPIO10_IN_RANGE_GPIO1;
regval = FIELD_GET(AXP20X_GPIO10_IN_RANGE_GPIO1, regval);
break;
default:
return -EINVAL;
}
*val = *val ? 700000 : 0;
*val = regval ? 700000 : 0;
return IIO_VAL_INT;
}
@ -548,7 +554,7 @@ static int axp20x_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct axp20x_adc_iio *info = iio_priv(indio_dev);
unsigned int reg, regval;
unsigned int regmask, regval;
/*
* The AXP20X PMIC allows the user to choose between 0V and 0.7V offsets
@ -560,25 +566,22 @@ static int axp20x_write_raw(struct iio_dev *indio_dev,
if (val != 0 && val != 700000)
return -EINVAL;
val = val ? 1 : 0;
switch (chan->channel) {
case AXP20X_GPIO0_V:
reg = AXP20X_GPIO10_IN_RANGE_GPIO0;
regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(val);
regmask = AXP20X_GPIO10_IN_RANGE_GPIO0;
regval = FIELD_PREP(AXP20X_GPIO10_IN_RANGE_GPIO0, !!val);
break;
case AXP20X_GPIO1_V:
reg = AXP20X_GPIO10_IN_RANGE_GPIO1;
regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(val);
regmask = AXP20X_GPIO10_IN_RANGE_GPIO1;
regval = FIELD_PREP(AXP20X_GPIO10_IN_RANGE_GPIO1, !!val);
break;
default:
return -EINVAL;
}
return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, reg,
regval);
return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, regmask, regval);
}
static const struct iio_info axp20x_adc_iio_info = {
@ -620,9 +623,9 @@ struct axp_data {
int num_channels;
struct iio_chan_spec const *channels;
unsigned long adc_en1_mask;
unsigned long adc_en2_mask;
int (*adc_rate)(struct axp20x_adc_iio *info,
int rate);
bool adc_en2;
struct iio_map *maps;
};
@ -631,8 +634,8 @@ static const struct axp_data axp20x_data = {
.num_channels = ARRAY_SIZE(axp20x_adc_channels),
.channels = axp20x_adc_channels,
.adc_en1_mask = AXP20X_ADC_EN1_MASK,
.adc_en2_mask = AXP20X_ADC_EN2_MASK,
.adc_rate = axp20x_adc_rate,
.adc_en2 = true,
.maps = axp20x_maps,
};
@ -642,7 +645,6 @@ static const struct axp_data axp22x_data = {
.channels = axp22x_adc_channels,
.adc_en1_mask = AXP22X_ADC_EN1_MASK,
.adc_rate = axp22x_adc_rate,
.adc_en2 = false,
.maps = axp22x_maps,
};
@ -652,7 +654,6 @@ static const struct axp_data axp813_data = {
.channels = axp813_adc_channels,
.adc_en1_mask = AXP22X_ADC_EN1_MASK,
.adc_rate = axp813_adc_rate,
.adc_en2 = false,
.maps = axp22x_maps,
};
@ -710,10 +711,10 @@ static int axp20x_probe(struct platform_device *pdev)
/* Enable the ADCs on IP */
regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask);
if (info->data->adc_en2)
/* Enable GPIO0/1 and internal temperature ADCs */
if (info->data->adc_en2_mask)
regmap_update_bits(info->regmap, AXP20X_ADC_EN2,
AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
info->data->adc_en2_mask,
info->data->adc_en2_mask);
/* Configure ADCs rate */
info->data->adc_rate(info, 100);
@ -738,7 +739,7 @@ fail_register:
fail_map:
regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
if (info->data->adc_en2)
if (info->data->adc_en2_mask)
regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
return ret;
@ -754,7 +755,7 @@ static int axp20x_remove(struct platform_device *pdev)
regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
if (info->data->adc_en2)
if (info->data->adc_en2_mask)
regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
return 0;

View File

@ -682,7 +682,7 @@ static irqreturn_t max11410_interrupt(int irq, void *dev_id)
struct max11410_state *st = iio_priv(indio_dev);
if (iio_buffer_enabled(indio_dev))
iio_trigger_poll_chained(st->trig);
iio_trigger_poll_nested(st->trig);
else
complete(&st->completion);

View File

@ -957,14 +957,18 @@ err_lock:
return ret;
}
static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
static void meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
int ret;
/*
* If taking the lock fails we have to assume that BL30 is broken. The
* best we can do then is to release the resources anyhow.
*/
ret = meson_sar_adc_lock(indio_dev);
if (ret)
return ret;
dev_err(indio_dev->dev.parent, "Failed to lock ADC (%pE)\n", ERR_PTR(ret));
clk_disable_unprepare(priv->adc_clk);
@ -977,9 +981,8 @@ static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
regulator_disable(priv->vref);
meson_sar_adc_unlock(indio_dev);
return 0;
if (!ret)
meson_sar_adc_unlock(indio_dev);
}
static irqreturn_t meson_sar_adc_irq(int irq, void *data)
@ -1283,14 +1286,18 @@ static int meson_sar_adc_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
return meson_sar_adc_hw_disable(indio_dev);
meson_sar_adc_hw_disable(indio_dev);
return 0;
}
static int meson_sar_adc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
return meson_sar_adc_hw_disable(indio_dev);
meson_sar_adc_hw_disable(indio_dev);
return 0;
}
static int meson_sar_adc_resume(struct device *dev)

View File

@ -758,7 +758,7 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev,
/* Find the right channel setting */
chid = 0;
hwchan = &hw_channels[0];
while (hwchan && hwchan->datasheet_name) {
while (hwchan->datasheet_name) {
if (hwchan->pre_scale_mux == pre_scale_mux &&
hwchan->amux_channel == amux_channel)
break;

View File

@ -283,7 +283,7 @@ static const struct of_device_id rcar_gyroadc_match[] = {
MODULE_DEVICE_TABLE(of, rcar_gyroadc_match);
static const struct of_device_id rcar_gyroadc_child_match[] = {
static const struct of_device_id rcar_gyroadc_child_match[] __maybe_unused = {
/* Mode 1 ADCs */
{
.compatible = "fujitsu,mb88101a",

View File

@ -2588,7 +2588,7 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = {
.irq_clear = stm32f4_adc_irq_clear,
};
const unsigned int stm32_adc_min_ts_h7[] = { 0, 0, 0, 4300, 9000 };
static const unsigned int stm32_adc_min_ts_h7[] = { 0, 0, 0, 4300, 9000 };
static_assert(ARRAY_SIZE(stm32_adc_min_ts_h7) == STM32_ADC_INT_CH_NB);
static const struct stm32_adc_cfg stm32h7_adc_cfg = {
@ -2607,7 +2607,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.ts_int_ch = stm32_adc_min_ts_h7,
};
const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 };
static const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 };
static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp1) == STM32_ADC_INT_CH_NB);
static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
@ -2627,7 +2627,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.ts_int_ch = stm32_adc_min_ts_mp1,
};
const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 };
static const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 };
static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp13) == STM32_ADC_INT_CH_NB);
static const struct stm32_adc_cfg stm32mp13_adc_cfg = {

View File

@ -0,0 +1,445 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* ADS1100 - Texas Instruments Analog-to-Digital Converter
*
* Copyright (c) 2023, Topic Embedded Products
*
* Datasheet: https://www.ti.com/lit/gpn/ads1100
* IIO driver for ADS1100 and ADS1000 ADC 16-bit I2C
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/units.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
/* The ADS1100 has a single byte config register */
/* Conversion in progress bit */
#define ADS1100_CFG_ST_BSY BIT(7)
/* Single conversion bit */
#define ADS1100_CFG_SC BIT(4)
/* Data rate */
#define ADS1100_DR_MASK GENMASK(3, 2)
/* Gain */
#define ADS1100_PGA_MASK GENMASK(1, 0)
#define ADS1100_CONTINUOUS 0
#define ADS1100_SINGLESHOT ADS1100_CFG_SC
#define ADS1100_SLEEP_DELAY_MS 2000
static const int ads1100_data_rate[] = { 128, 32, 16, 8 };
static const int ads1100_data_rate_bits[] = { 12, 14, 15, 16 };
struct ads1100_data {
struct i2c_client *client;
struct regulator *reg_vdd;
struct mutex lock;
int scale_avail[2 * 4]; /* 4 gain settings */
u8 config;
bool supports_data_rate; /* Only the ADS1100 can select the rate */
};
static const struct iio_chan_spec ads1100_channel = {
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_all =
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ),
.info_mask_shared_by_all_available =
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
.datasheet_name = "AIN",
};
static int ads1100_set_config_bits(struct ads1100_data *data, u8 mask, u8 value)
{
int ret;
u8 config = (data->config & ~mask) | (value & mask);
if (data->config == config)
return 0; /* Already done */
ret = i2c_master_send(data->client, &config, 1);
if (ret < 0)
return ret;
data->config = config;
return 0;
};
static int ads1100_data_bits(struct ads1100_data *data)
{
return ads1100_data_rate_bits[FIELD_GET(ADS1100_DR_MASK, data->config)];
}
static int ads1100_get_adc_result(struct ads1100_data *data, int chan, int *val)
{
int ret;
__be16 buffer;
s16 value;
if (chan != 0)
return -EINVAL;
ret = pm_runtime_resume_and_get(&data->client->dev);
if (ret < 0)
return ret;
ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer));
pm_runtime_mark_last_busy(&data->client->dev);
pm_runtime_put_autosuspend(&data->client->dev);
if (ret < 0) {
dev_err(&data->client->dev, "I2C read fail: %d\n", ret);
return ret;
}
/* Value is always 16-bit 2's complement */
value = be16_to_cpu(buffer);
/* Shift result to compensate for bit resolution vs. sample rate */
value <<= 16 - ads1100_data_bits(data);
*val = sign_extend32(value, 15);
return 0;
}
static int ads1100_set_scale(struct ads1100_data *data, int val, int val2)
{
int microvolts;
int gain;
/* With Vdd between 2.7 and 5V, the scale is always below 1 */
if (val)
return -EINVAL;
if (!val2)
return -EINVAL;
microvolts = regulator_get_voltage(data->reg_vdd);
/*
* val2 is in 'micro' units, n = val2 / 1000000
* result must be millivolts, d = microvolts / 1000
* the full-scale value is d/n, corresponds to 2^15,
* hence the gain = (d / n) >> 15, factoring out the 1000 and moving the
* bitshift so everything fits in 32-bits yields this formula.
*/
gain = DIV_ROUND_CLOSEST(microvolts, BIT(15)) * MILLI / val2;
if (gain < BIT(0) || gain > BIT(3))
return -EINVAL;
ads1100_set_config_bits(data, ADS1100_PGA_MASK, ffs(gain) - 1);
return 0;
}
static int ads1100_set_data_rate(struct ads1100_data *data, int chan, int rate)
{
unsigned int i;
unsigned int size;
size = data->supports_data_rate ? ARRAY_SIZE(ads1100_data_rate) : 1;
for (i = 0; i < size; i++) {
if (ads1100_data_rate[i] == rate)
return ads1100_set_config_bits(data, ADS1100_DR_MASK,
FIELD_PREP(ADS1100_DR_MASK, i));
}
return -EINVAL;
}
static int ads1100_get_vdd_millivolts(struct ads1100_data *data)
{
return regulator_get_voltage(data->reg_vdd) / (MICRO / MILLI);
}
static void ads1100_calc_scale_avail(struct ads1100_data *data)
{
int millivolts = ads1100_get_vdd_millivolts(data);
unsigned int i;
for (i = 0; i < ARRAY_SIZE(data->scale_avail) / 2; i++) {
data->scale_avail[i * 2 + 0] = millivolts;
data->scale_avail[i * 2 + 1] = 15 + i;
}
}
static int ads1100_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
struct ads1100_data *data = iio_priv(indio_dev);
if (chan->type != IIO_VOLTAGE)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
*type = IIO_VAL_INT;
*vals = ads1100_data_rate;
if (data->supports_data_rate)
*length = ARRAY_SIZE(ads1100_data_rate);
else
*length = 1;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_SCALE:
*type = IIO_VAL_FRACTIONAL_LOG2;
*vals = data->scale_avail;
*length = ARRAY_SIZE(data->scale_avail);
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
static int ads1100_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
int ret;
struct ads1100_data *data = iio_priv(indio_dev);
mutex_lock(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
break;
ret = ads1100_get_adc_result(data, chan->address, val);
if (ret >= 0)
ret = IIO_VAL_INT;
iio_device_release_direct_mode(indio_dev);
break;
case IIO_CHAN_INFO_SCALE:
/* full-scale is the supply voltage in millivolts */
*val = ads1100_get_vdd_millivolts(data);
*val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config);
ret = IIO_VAL_FRACTIONAL_LOG2;
break;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK,
data->config)];
ret = IIO_VAL_INT;
break;
default:
ret = -EINVAL;
break;
}
mutex_unlock(&data->lock);
return ret;
}
static int ads1100_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
{
struct ads1100_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
ret = ads1100_set_scale(data, val, val2);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = ads1100_set_data_rate(data, chan->address, val);
break;
default:
ret = -EINVAL;
break;
}
mutex_unlock(&data->lock);
return ret;
}
static const struct iio_info ads1100_info = {
.read_avail = ads1100_read_avail,
.read_raw = ads1100_read_raw,
.write_raw = ads1100_write_raw,
};
static int ads1100_setup(struct ads1100_data *data)
{
int ret;
u8 buffer[3];
/* Setup continuous sampling mode at 8sps */
buffer[0] = ADS1100_DR_MASK | ADS1100_CONTINUOUS;
ret = i2c_master_send(data->client, buffer, 1);
if (ret < 0)
return ret;
ret = i2c_master_recv(data->client, buffer, sizeof(buffer));
if (ret < 0)
return ret;
/* Config register returned in third byte, strip away the busy status */
data->config = buffer[2] & ~ADS1100_CFG_ST_BSY;
/* Detect the sample rate capability by checking the DR bits */
data->supports_data_rate = FIELD_GET(ADS1100_DR_MASK, buffer[2]) != 0;
return 0;
}
static void ads1100_reg_disable(void *reg)
{
regulator_disable(reg);
}
static void ads1100_disable_continuous(void *data)
{
ads1100_set_config_bits(data, ADS1100_CFG_SC, ADS1100_SINGLESHOT);
}
static int ads1100_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct ads1100_data *data;
struct device *dev = &client->dev;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
dev_set_drvdata(dev, data);
data->client = client;
mutex_init(&data->lock);
indio_dev->name = "ads1100";
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = &ads1100_channel;
indio_dev->num_channels = 1;
indio_dev->info = &ads1100_info;
data->reg_vdd = devm_regulator_get(dev, "vdd");
if (IS_ERR(data->reg_vdd))
return dev_err_probe(dev, PTR_ERR(data->reg_vdd),
"Failed to get vdd regulator\n");
ret = regulator_enable(data->reg_vdd);
if (ret < 0)
return dev_err_probe(dev, ret,
"Failed to enable vdd regulator\n");
ret = devm_add_action_or_reset(dev, ads1100_reg_disable, data->reg_vdd);
if (ret)
return ret;
ret = ads1100_setup(data);
if (ret)
return dev_err_probe(dev, ret,
"Failed to communicate with device\n");
ret = devm_add_action_or_reset(dev, ads1100_disable_continuous, data);
if (ret)
return ret;
ads1100_calc_scale_avail(data);
pm_runtime_set_autosuspend_delay(dev, ADS1100_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_active(dev);
ret = devm_pm_runtime_enable(dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to enable pm_runtime\n");
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
return dev_err_probe(dev, ret,
"Failed to register IIO device\n");
return 0;
}
static int ads1100_runtime_suspend(struct device *dev)
{
struct ads1100_data *data = dev_get_drvdata(dev);
ads1100_set_config_bits(data, ADS1100_CFG_SC, ADS1100_SINGLESHOT);
regulator_disable(data->reg_vdd);
return 0;
}
static int ads1100_runtime_resume(struct device *dev)
{
struct ads1100_data *data = dev_get_drvdata(dev);
int ret;
ret = regulator_enable(data->reg_vdd);
if (ret) {
dev_err(&data->client->dev, "Failed to enable Vdd\n");
return ret;
}
/*
* We'll always change the mode bit in the config register, so there is
* no need here to "force" a write to the config register. If the device
* has been power-cycled, we'll re-write its config register now.
*/
return ads1100_set_config_bits(data, ADS1100_CFG_SC,
ADS1100_CONTINUOUS);
}
static DEFINE_RUNTIME_DEV_PM_OPS(ads1100_pm_ops,
ads1100_runtime_suspend,
ads1100_runtime_resume,
NULL);
static const struct i2c_device_id ads1100_id[] = {
{ "ads1100" },
{ "ads1000" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ads1100_id);
static const struct of_device_id ads1100_of_match[] = {
{.compatible = "ti,ads1100" },
{.compatible = "ti,ads1000" },
{ }
};
MODULE_DEVICE_TABLE(of, ads1100_of_match);
static struct i2c_driver ads1100_driver = {
.driver = {
.name = "ads1100",
.of_match_table = ads1100_of_match,
.pm = pm_ptr(&ads1100_pm_ops),
},
.probe_new = ads1100_probe,
.id_table = ads1100_id,
};
module_i2c_driver(ads1100_driver);
MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
MODULE_DESCRIPTION("Texas Instruments ADS1100 ADC driver");
MODULE_LICENSE("GPL");

View File

@ -35,7 +35,9 @@ config STX104
tristate "Apex Embedded Systems STX104 driver"
depends on PC104 && X86
select ISA_BUS_API
select REGMAP_MMIO
select GPIOLIB
select GPIO_REGMAP
help
Say yes here to build support for the Apex Embedded Systems STX104
integrated analog PC/104 card.

View File

@ -39,6 +39,7 @@ struct ad74413r_chip_info {
struct ad74413r_channel_config {
u32 func;
u32 drive_strength;
bool gpo_comparator;
bool initialized;
};
@ -99,6 +100,7 @@ struct ad74413r_state {
#define AD74413R_REG_ADC_CONFIG_X(x) (0x05 + (x))
#define AD74413R_ADC_CONFIG_RANGE_MASK GENMASK(7, 5)
#define AD74413R_ADC_CONFIG_REJECTION_MASK GENMASK(4, 3)
#define AD74413R_ADC_CONFIG_CH_200K_TO_GND BIT(2)
#define AD74413R_ADC_RANGE_10V 0b000
#define AD74413R_ADC_RANGE_2P5V_EXT_POW 0b001
#define AD74413R_ADC_RANGE_2P5V_INT_POW 0b010
@ -111,6 +113,7 @@ struct ad74413r_state {
#define AD74413R_REG_DIN_CONFIG_X(x) (0x09 + (x))
#define AD74413R_DIN_DEBOUNCE_MASK GENMASK(4, 0)
#define AD74413R_DIN_DEBOUNCE_LEN BIT(5)
#define AD74413R_DIN_SINK_MASK GENMASK(9, 6)
#define AD74413R_REG_DAC_CODE_X(x) (0x16 + (x))
#define AD74413R_DAC_CODE_MAX GENMASK(12, 0)
@ -261,6 +264,18 @@ static int ad74413r_set_comp_debounce(struct ad74413r_state *st,
val);
}
static int ad74413r_set_comp_drive_strength(struct ad74413r_state *st,
unsigned int offset,
unsigned int strength)
{
strength = min(strength, 1800U);
return regmap_update_bits(st->regmap, AD74413R_REG_DIN_CONFIG_X(offset),
AD74413R_DIN_SINK_MASK,
FIELD_PREP(AD74413R_DIN_SINK_MASK, strength / 120));
}
static void ad74413r_gpio_set(struct gpio_chip *chip,
unsigned int offset, int val)
{
@ -424,9 +439,20 @@ static int ad74413r_set_channel_dac_code(struct ad74413r_state *st,
static int ad74413r_set_channel_function(struct ad74413r_state *st,
unsigned int channel, u8 func)
{
return regmap_update_bits(st->regmap,
int ret;
ret = regmap_update_bits(st->regmap,
AD74413R_REG_CH_FUNC_SETUP_X(channel),
AD74413R_CH_FUNC_SETUP_MASK, func);
if (ret)
return ret;
if (func == CH_FUNC_CURRENT_INPUT_LOOP_POWER)
ret = regmap_set_bits(st->regmap,
AD74413R_REG_ADC_CONFIG_X(channel),
AD74413R_ADC_CONFIG_CH_200K_TO_GND);
return ret;
}
static int ad74413r_set_adc_conv_seq(struct ad74413r_state *st,
@ -1112,6 +1138,11 @@ static struct iio_chan_spec ad74413r_current_input_channels[] = {
AD74413R_ADC_CURRENT_CHANNEL,
};
static struct iio_chan_spec ad74413r_current_input_loop_channels[] = {
AD74413R_DAC_CHANNEL(IIO_CURRENT, BIT(IIO_CHAN_INFO_SCALE)),
AD74413R_ADC_CURRENT_CHANNEL,
};
static struct iio_chan_spec ad74413r_resistance_input_channels[] = {
AD74413R_ADC_CHANNEL(IIO_RESISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)),
};
@ -1135,7 +1166,7 @@ static const struct ad74413r_channels ad74413r_channels_map[] = {
[CH_FUNC_CURRENT_OUTPUT] = AD74413R_CHANNELS(current_output),
[CH_FUNC_VOLTAGE_INPUT] = AD74413R_CHANNELS(voltage_input),
[CH_FUNC_CURRENT_INPUT_EXT_POWER] = AD74413R_CHANNELS(current_input),
[CH_FUNC_CURRENT_INPUT_LOOP_POWER] = AD74413R_CHANNELS(current_input),
[CH_FUNC_CURRENT_INPUT_LOOP_POWER] = AD74413R_CHANNELS(current_input_loop),
[CH_FUNC_RESISTANCE_INPUT] = AD74413R_CHANNELS(resistance_input),
[CH_FUNC_DIGITAL_INPUT_LOGIC] = AD74413R_CHANNELS(digital_input),
[CH_FUNC_DIGITAL_INPUT_LOOP_POWER] = AD74413R_CHANNELS(digital_input),
@ -1190,6 +1221,9 @@ static int ad74413r_parse_channel_config(struct iio_dev *indio_dev,
config->gpo_comparator = fwnode_property_read_bool(channel_node,
"adi,gpo-comparator");
fwnode_property_read_u32(channel_node, "drive-strength-microamp",
&config->drive_strength);
if (!config->gpo_comparator)
st->num_gpo_gpios++;
@ -1269,6 +1303,7 @@ static int ad74413r_setup_gpios(struct ad74413r_state *st)
unsigned int gpo_gpio_i = 0;
unsigned int i;
u8 gpo_config;
u32 strength;
int ret;
for (i = 0; i < AD74413R_CHANNEL_MAX; i++) {
@ -1285,6 +1320,11 @@ static int ad74413r_setup_gpios(struct ad74413r_state *st)
config->func == CH_FUNC_DIGITAL_INPUT_LOOP_POWER)
st->comp_gpio_offsets[comp_gpio_i++] = i;
strength = config->drive_strength;
ret = ad74413r_set_comp_drive_strength(st, i, strength);
if (ret)
return ret;
ret = ad74413r_set_gpo_config(st, i, gpo_config);
if (ret)
return ret;

View File

@ -3,19 +3,20 @@
* IIO driver for the Apex Embedded Systems STX104
* Copyright (C) 2016 William Breathitt Gray
*/
#include <linux/bitops.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/err.h>
#include <linux/gpio/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/isa.h>
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/types.h>
#define STX104_OUT_CHAN(chan) { \
@ -45,101 +46,211 @@ static unsigned int num_stx104;
module_param_hw_array(base, uint, ioport, &num_stx104, 0);
MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
/**
* struct stx104_reg - device register structure
* @ssr_ad: Software Strobe Register and ADC Data
* @achan: ADC Channel
* @dio: Digital I/O
* @dac: DAC Channels
* @cir_asr: Clear Interrupts and ADC Status
* @acr: ADC Control
* @pccr_fsh: Pacer Clock Control and FIFO Status MSB
* @acfg: ADC Configuration
*/
struct stx104_reg {
u16 ssr_ad;
u8 achan;
u8 dio;
u16 dac[2];
u8 cir_asr;
u8 acr;
u8 pccr_fsh;
u8 acfg;
};
#define STX104_AIO_BASE 0x0
#define STX104_SOFTWARE_STROBE STX104_AIO_BASE
#define STX104_ADC_DATA STX104_AIO_BASE
#define STX104_ADC_CHANNEL (STX104_AIO_BASE + 0x2)
#define STX104_DIO_REG (STX104_AIO_BASE + 0x3)
#define STX104_DAC_BASE (STX104_AIO_BASE + 0x4)
#define STX104_ADC_STATUS (STX104_AIO_BASE + 0x8)
#define STX104_ADC_CONTROL (STX104_AIO_BASE + 0x9)
#define STX104_ADC_CONFIGURATION (STX104_AIO_BASE + 0x11)
#define STX104_AIO_DATA_STRIDE 2
#define STX104_DAC_OFFSET(_channel) (STX104_DAC_BASE + STX104_AIO_DATA_STRIDE * (_channel))
/* ADC Channel */
#define STX104_FC GENMASK(3, 0)
#define STX104_LC GENMASK(7, 4)
#define STX104_SINGLE_CHANNEL(_channel) \
(u8_encode_bits(_channel, STX104_FC) | u8_encode_bits(_channel, STX104_LC))
/* ADC Status */
#define STX104_SD BIT(5)
#define STX104_CNV BIT(7)
#define STX104_DIFFERENTIAL 1
/* ADC Control */
#define STX104_ALSS GENMASK(1, 0)
#define STX104_SOFTWARE_TRIGGER u8_encode_bits(0x0, STX104_ALSS)
/* ADC Configuration */
#define STX104_GAIN GENMASK(1, 0)
#define STX104_ADBU BIT(2)
#define STX104_BIPOLAR 0
#define STX104_GAIN_X1 0
#define STX104_GAIN_X2 1
#define STX104_GAIN_X4 2
#define STX104_GAIN_X8 3
/**
* struct stx104_iio - IIO device private data structure
* @chan_out_states: channels' output states
* @reg: I/O address offset for the device registers
* @lock: synchronization lock to prevent I/O race conditions
* @aio_data_map: Regmap for analog I/O data
* @aio_ctl_map: Regmap for analog I/O control
*/
struct stx104_iio {
unsigned int chan_out_states[STX104_NUM_OUT_CHAN];
struct stx104_reg __iomem *reg;
struct mutex lock;
struct regmap *aio_data_map;
struct regmap *aio_ctl_map;
};
/**
* struct stx104_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @lock: synchronization lock to prevent I/O race conditions
* @base: base port address of the GPIO device
* @out_state: output bits state
*/
struct stx104_gpio {
struct gpio_chip chip;
spinlock_t lock;
u8 __iomem *base;
unsigned int out_state;
static const struct regmap_range aio_ctl_wr_ranges[] = {
regmap_reg_range(0x0, 0x0), regmap_reg_range(0x2, 0x2), regmap_reg_range(0x9, 0x9),
regmap_reg_range(0x11, 0x11),
};
static const struct regmap_range aio_ctl_rd_ranges[] = {
regmap_reg_range(0x2, 0x2), regmap_reg_range(0x8, 0x9), regmap_reg_range(0x11, 0x11),
};
static const struct regmap_range aio_ctl_volatile_ranges[] = {
regmap_reg_range(0x8, 0x8),
};
static const struct regmap_access_table aio_ctl_wr_table = {
.yes_ranges = aio_ctl_wr_ranges,
.n_yes_ranges = ARRAY_SIZE(aio_ctl_wr_ranges),
};
static const struct regmap_access_table aio_ctl_rd_table = {
.yes_ranges = aio_ctl_rd_ranges,
.n_yes_ranges = ARRAY_SIZE(aio_ctl_rd_ranges),
};
static const struct regmap_access_table aio_ctl_volatile_table = {
.yes_ranges = aio_ctl_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(aio_ctl_volatile_ranges),
};
static const struct regmap_config aio_ctl_regmap_config = {
.name = "aio_ctl",
.reg_bits = 8,
.reg_stride = 1,
.reg_base = STX104_AIO_BASE,
.val_bits = 8,
.io_port = true,
.wr_table = &aio_ctl_wr_table,
.rd_table = &aio_ctl_rd_table,
.volatile_table = &aio_ctl_volatile_table,
.cache_type = REGCACHE_FLAT,
};
static const struct regmap_range aio_data_wr_ranges[] = {
regmap_reg_range(0x4, 0x6),
};
static const struct regmap_range aio_data_rd_ranges[] = {
regmap_reg_range(0x0, 0x0),
};
static const struct regmap_access_table aio_data_wr_table = {
.yes_ranges = aio_data_wr_ranges,
.n_yes_ranges = ARRAY_SIZE(aio_data_wr_ranges),
};
static const struct regmap_access_table aio_data_rd_table = {
.yes_ranges = aio_data_rd_ranges,
.n_yes_ranges = ARRAY_SIZE(aio_data_rd_ranges),
};
static const struct regmap_config aio_data_regmap_config = {
.name = "aio_data",
.reg_bits = 16,
.reg_stride = STX104_AIO_DATA_STRIDE,
.reg_base = STX104_AIO_BASE,
.val_bits = 16,
.io_port = true,
.wr_table = &aio_data_wr_table,
.rd_table = &aio_data_rd_table,
.volatile_table = &aio_data_rd_table,
.cache_type = REGCACHE_FLAT,
};
static const struct regmap_config dio_regmap_config = {
.name = "dio",
.reg_bits = 8,
.reg_stride = 1,
.reg_base = STX104_DIO_REG,
.val_bits = 8,
.io_port = true,
};
static int stx104_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
struct stx104_iio *const priv = iio_priv(indio_dev);
struct stx104_reg __iomem *const reg = priv->reg;
int err;
unsigned int adc_config;
int adbu;
int gain;
unsigned int value;
unsigned int adc_status;
switch (mask) {
case IIO_CHAN_INFO_HARDWAREGAIN:
/* get gain configuration */
adc_config = ioread8(&reg->acfg);
gain = adc_config & 0x3;
err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config);
if (err)
return err;
*val = 1 << gain;
*val = BIT(u8_get_bits(adc_config, STX104_GAIN));
return IIO_VAL_INT;
case IIO_CHAN_INFO_RAW:
if (chan->output) {
*val = priv->chan_out_states[chan->channel];
err = regmap_read(priv->aio_data_map, STX104_DAC_OFFSET(chan->channel),
&value);
if (err)
return err;
*val = value;
return IIO_VAL_INT;
}
mutex_lock(&priv->lock);
/* select ADC channel */
iowrite8(chan->channel | (chan->channel << 4), &reg->achan);
err = regmap_write(priv->aio_ctl_map, STX104_ADC_CHANNEL,
STX104_SINGLE_CHANNEL(chan->channel));
if (err) {
mutex_unlock(&priv->lock);
return err;
}
/* trigger ADC sample capture by writing to the 8-bit
* Software Strobe Register and wait for completion
/*
* Trigger ADC sample capture by writing to the 8-bit Software Strobe Register and
* wait for completion; the conversion time range is 5 microseconds to 53.68 seconds
* in steps of 25 nanoseconds. The actual Analog Input Frame Timer time interval is
* calculated as:
* ai_time_frame_ns = ( AIFT + 1 ) * ( 25 nanoseconds ).
* Where 0 <= AIFT <= 2147483648.
*/
iowrite8(0, &reg->ssr_ad);
while (ioread8(&reg->cir_asr) & BIT(7));
err = regmap_write(priv->aio_ctl_map, STX104_SOFTWARE_STROBE, 0);
if (err) {
mutex_unlock(&priv->lock);
return err;
}
err = regmap_read_poll_timeout(priv->aio_ctl_map, STX104_ADC_STATUS, adc_status,
!u8_get_bits(adc_status, STX104_CNV), 0, 53687092);
if (err) {
mutex_unlock(&priv->lock);
return err;
}
*val = ioread16(&reg->ssr_ad);
err = regmap_read(priv->aio_data_map, STX104_ADC_DATA, &value);
if (err) {
mutex_unlock(&priv->lock);
return err;
}
*val = value;
mutex_unlock(&priv->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
/* get ADC bipolar/unipolar configuration */
adc_config = ioread8(&reg->acfg);
adbu = !(adc_config & BIT(2));
err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config);
if (err)
return err;
*val = -32768 * adbu;
*val = (u8_get_bits(adc_config, STX104_ADBU) == STX104_BIPOLAR) ? -32768 : 0;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/* get ADC bipolar/unipolar and gain configuration */
adc_config = ioread8(&reg->acfg);
adbu = !(adc_config & BIT(2));
gain = adc_config & 0x3;
err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config);
if (err)
return err;
*val = 5;
*val2 = 15 - adbu + gain;
*val2 = (u8_get_bits(adc_config, STX104_ADBU) == STX104_BIPOLAR) ? 14 : 15;
*val2 += u8_get_bits(adc_config, STX104_GAIN);
return IIO_VAL_FRACTIONAL_LOG2;
}
@ -150,40 +261,37 @@ static int stx104_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct stx104_iio *const priv = iio_priv(indio_dev);
u8 gain;
switch (mask) {
case IIO_CHAN_INFO_HARDWAREGAIN:
/* Only four gain states (x1, x2, x4, x8) */
switch (val) {
case 1:
iowrite8(0, &priv->reg->acfg);
gain = STX104_GAIN_X1;
break;
case 2:
iowrite8(1, &priv->reg->acfg);
gain = STX104_GAIN_X2;
break;
case 4:
iowrite8(2, &priv->reg->acfg);
gain = STX104_GAIN_X4;
break;
case 8:
iowrite8(3, &priv->reg->acfg);
gain = STX104_GAIN_X8;
break;
default:
return -EINVAL;
}
return 0;
return regmap_write(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, gain);
case IIO_CHAN_INFO_RAW:
if (chan->output) {
/* DAC can only accept up to a 16-bit value */
if ((unsigned int)val > 65535)
return -EINVAL;
if (!chan->output)
return -EINVAL;
priv->chan_out_states[chan->channel] = val;
iowrite16(val, &priv->reg->dac[chan->channel]);
if (val < 0 || val > U16_MAX)
return -EINVAL;
return 0;
}
return -EINVAL;
return regmap_write(priv->aio_data_map, STX104_DAC_OFFSET(chan->channel), val);
}
return -EINVAL;
@ -212,119 +320,66 @@ static const struct iio_chan_spec stx104_channels_diff[] = {
STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1)
};
static int stx104_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
/* GPIO 0-3 are input only, while the rest are output only */
if (offset < 4)
return 1;
return 0;
}
static int stx104_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,
unsigned int offset, unsigned int *const reg,
unsigned int *const mask)
{
/* Output lines are located at same register bit offsets as input lines */
if (offset >= 4)
return -EINVAL;
offset -= 4;
*reg = base;
*mask = BIT(offset);
return 0;
}
static int stx104_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
if (offset < 4)
return -EINVAL;
chip->set(chip, offset, value);
return 0;
}
static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
if (offset >= 4)
return -EINVAL;
return !!(ioread8(stx104gpio->base) & BIT(offset));
}
static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
*bits = ioread8(stx104gpio->base);
return 0;
}
static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
const unsigned int mask = BIT(offset) >> 4;
unsigned long flags;
if (offset < 4)
return;
spin_lock_irqsave(&stx104gpio->lock, flags);
if (value)
stx104gpio->out_state |= mask;
else
stx104gpio->out_state &= ~mask;
iowrite8(stx104gpio->out_state, stx104gpio->base);
spin_unlock_irqrestore(&stx104gpio->lock, flags);
}
#define STX104_NGPIO 8
static const char *stx104_names[STX104_NGPIO] = {
"DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3"
};
static void stx104_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
static int stx104_init_hw(struct stx104_iio *const priv)
{
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
unsigned long flags;
int err;
/* verify masked GPIO are output */
if (!(*mask & 0xF0))
return;
/* configure device for software trigger operation */
err = regmap_write(priv->aio_ctl_map, STX104_ADC_CONTROL, STX104_SOFTWARE_TRIGGER);
if (err)
return err;
*mask >>= 4;
*bits >>= 4;
/* initialize gain setting to x1 */
err = regmap_write(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, STX104_GAIN_X1);
if (err)
return err;
spin_lock_irqsave(&stx104gpio->lock, flags);
/* initialize DAC outputs to 0V */
err = regmap_write(priv->aio_data_map, STX104_DAC_BASE, 0);
if (err)
return err;
err = regmap_write(priv->aio_data_map, STX104_DAC_BASE + STX104_AIO_DATA_STRIDE, 0);
if (err)
return err;
stx104gpio->out_state &= ~*mask;
stx104gpio->out_state |= *mask & *bits;
iowrite8(stx104gpio->out_state, stx104gpio->base);
spin_unlock_irqrestore(&stx104gpio->lock, flags);
return 0;
}
static int stx104_probe(struct device *dev, unsigned int id)
{
struct iio_dev *indio_dev;
struct stx104_iio *priv;
struct stx104_gpio *stx104gpio;
struct gpio_regmap_config gpio_config;
void __iomem *stx104_base;
struct regmap *aio_ctl_map;
struct regmap *aio_data_map;
struct regmap *dio_map;
int err;
unsigned int adc_status;
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL);
if (!stx104gpio)
return -ENOMEM;
if (!devm_request_region(dev, base[id], STX104_EXTENT,
dev_name(dev))) {
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
@ -332,16 +387,37 @@ static int stx104_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
priv = iio_priv(indio_dev);
priv->reg = devm_ioport_map(dev, base[id], STX104_EXTENT);
if (!priv->reg)
stx104_base = devm_ioport_map(dev, base[id], STX104_EXTENT);
if (!stx104_base)
return -ENOMEM;
aio_ctl_map = devm_regmap_init_mmio(dev, stx104_base, &aio_ctl_regmap_config);
if (IS_ERR(aio_ctl_map))
return dev_err_probe(dev, PTR_ERR(aio_ctl_map),
"Unable to initialize aio_ctl register map\n");
aio_data_map = devm_regmap_init_mmio(dev, stx104_base, &aio_data_regmap_config);
if (IS_ERR(aio_data_map))
return dev_err_probe(dev, PTR_ERR(aio_data_map),
"Unable to initialize aio_data register map\n");
dio_map = devm_regmap_init_mmio(dev, stx104_base, &dio_regmap_config);
if (IS_ERR(dio_map))
return dev_err_probe(dev, PTR_ERR(dio_map),
"Unable to initialize dio register map\n");
priv = iio_priv(indio_dev);
priv->aio_ctl_map = aio_ctl_map;
priv->aio_data_map = aio_data_map;
indio_dev->info = &stx104_info;
indio_dev->modes = INDIO_DIRECT_MODE;
/* determine if differential inputs */
if (ioread8(&priv->reg->cir_asr) & BIT(5)) {
err = regmap_read(aio_ctl_map, STX104_ADC_STATUS, &adc_status);
if (err)
return err;
if (u8_get_bits(adc_status, STX104_SD) == STX104_DIFFERENTIAL) {
indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff);
indio_dev->channels = stx104_channels_diff;
} else {
@ -351,41 +427,29 @@ static int stx104_probe(struct device *dev, unsigned int id)
indio_dev->name = dev_name(dev);
/* configure device for software trigger operation */
iowrite8(0, &priv->reg->acr);
mutex_init(&priv->lock);
/* initialize gain setting to x1 */
iowrite8(0, &priv->reg->acfg);
/* initialize DAC output to 0V */
iowrite16(0, &priv->reg->dac[0]);
iowrite16(0, &priv->reg->dac[1]);
stx104gpio->chip.label = dev_name(dev);
stx104gpio->chip.parent = dev;
stx104gpio->chip.owner = THIS_MODULE;
stx104gpio->chip.base = -1;
stx104gpio->chip.ngpio = STX104_NGPIO;
stx104gpio->chip.names = stx104_names;
stx104gpio->chip.get_direction = stx104_gpio_get_direction;
stx104gpio->chip.direction_input = stx104_gpio_direction_input;
stx104gpio->chip.direction_output = stx104_gpio_direction_output;
stx104gpio->chip.get = stx104_gpio_get;
stx104gpio->chip.get_multiple = stx104_gpio_get_multiple;
stx104gpio->chip.set = stx104_gpio_set;
stx104gpio->chip.set_multiple = stx104_gpio_set_multiple;
stx104gpio->base = &priv->reg->dio;
stx104gpio->out_state = 0x0;
spin_lock_init(&stx104gpio->lock);
err = devm_gpiochip_add_data(dev, &stx104gpio->chip, stx104gpio);
if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err);
err = stx104_init_hw(priv);
if (err)
return err;
}
return devm_iio_device_register(dev, indio_dev);
err = devm_iio_device_register(dev, indio_dev);
if (err)
return err;
gpio_config = (struct gpio_regmap_config) {
.parent = dev,
.regmap = dio_map,
.ngpio = STX104_NGPIO,
.names = stx104_names,
.reg_dat_base = GPIO_REGMAP_ADDR(STX104_DIO_REG),
.reg_set_base = GPIO_REGMAP_ADDR(STX104_DIO_REG),
.ngpio_per_reg = STX104_NGPIO,
.reg_mask_xlate = stx104_reg_mask_xlate,
.drvdata = dio_map,
};
return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
}
static struct isa_driver stx104_driver = {

View File

@ -68,10 +68,10 @@ static int sps30_i2c_command(struct sps30_state *state, u16 cmd, void *arg, size
/*
* Internally sensor stores measurements in a following manner:
*
* PM1: upper two bytes, crc8, lower two bytes, crc8
* PM1: upper two bytes, crc8, lower two bytes, crc8
* PM2P5: upper two bytes, crc8, lower two bytes, crc8
* PM4: upper two bytes, crc8, lower two bytes, crc8
* PM10: upper two bytes, crc8, lower two bytes, crc8
* PM4: upper two bytes, crc8, lower two bytes, crc8
* PM10: upper two bytes, crc8, lower two bytes, crc8
*
* What follows next are number concentration measurements and
* typical particle size measurement which we omit.

View File

@ -85,7 +85,7 @@ static irqreturn_t st_sensors_irq_thread(int irq, void *p)
*/
if (sdata->hw_irq_trigger &&
st_sensors_new_samples_available(indio_dev, sdata)) {
iio_trigger_poll_chained(p);
iio_trigger_poll_nested(p);
} else {
dev_dbg(indio_dev->dev.parent, "spurious IRQ\n");
return IRQ_NONE;
@ -110,7 +110,7 @@ static irqreturn_t st_sensors_irq_thread(int irq, void *p)
dev_dbg(indio_dev->dev.parent,
"more samples came in during polling\n");
sdata->hw_timestamp = iio_get_time_ns(indio_dev);
iio_trigger_poll_chained(p);
iio_trigger_poll_nested(p);
}
return IRQ_HANDLED;

View File

@ -277,6 +277,7 @@ config CIO_DAC
tristate "Measurement Computing CIO-DAC IIO driver"
depends on X86 && (ISA_BUS || PC104)
select ISA_BUS_API
select REGMAP_MMIO
help
Say yes here to build support for the Measurement Computing CIO-DAC
analog output device family (CIO-DAC16, CIO-DAC08, PC104-DAC06). The

View File

@ -124,6 +124,10 @@ static int ad5592r_gpio_request(struct gpio_chip *chip, unsigned offset)
return 0;
}
static const char * const ad5592r_gpio_names[] = {
"GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", "GPIO6", "GPIO7",
};
static int ad5592r_gpio_init(struct ad5592r_state *st)
{
if (!st->gpio_map)
@ -140,6 +144,7 @@ static int ad5592r_gpio_init(struct ad5592r_state *st)
st->gpiochip.set = ad5592r_gpio_set;
st->gpiochip.request = ad5592r_gpio_request;
st->gpiochip.owner = THIS_MODULE;
st->gpiochip.names = ad5592r_gpio_names;
mutex_init(&st->gpio_lock);

View File

@ -4,18 +4,17 @@
* Copyright (C) 2016 William Breathitt Gray
*
* This driver supports the following Measurement Computing devices: CIO-DAC16,
* CIO-DAC06, and PC104-DAC06.
* CIO-DAC08, and PC104-DAC06.
*/
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/isa.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/regmap.h>
#include <linux/types.h>
#define CIO_DAC_NUM_CHAN 16
@ -35,25 +34,51 @@ static unsigned int num_cio_dac;
module_param_hw_array(base, uint, ioport, &num_cio_dac, 0);
MODULE_PARM_DESC(base, "Measurement Computing CIO-DAC base addresses");
#define CIO_DAC_BASE 0x00
#define CIO_DAC_CHANNEL_STRIDE 2
static bool cio_dac_precious_reg(struct device *dev, unsigned int reg)
{
/*
* All registers are considered precious; if the XFER jumper is set on
* the device, then no update occurs until a DAC register is read.
*/
return true;
}
static const struct regmap_config cio_dac_regmap_config = {
.reg_bits = 16,
.reg_stride = 2,
.val_bits = 16,
.io_port = true,
.max_register = 0x1F,
.precious_reg = cio_dac_precious_reg,
};
/**
* struct cio_dac_iio - IIO device private data structure
* @chan_out_states: channels' output states
* @base: base memory address of the DAC device
* @map: Regmap for the device
*/
struct cio_dac_iio {
int chan_out_states[CIO_DAC_NUM_CHAN];
u16 __iomem *base;
struct regmap *map;
};
static int cio_dac_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
struct cio_dac_iio *const priv = iio_priv(indio_dev);
const unsigned int offset = chan->channel * CIO_DAC_CHANNEL_STRIDE;
int err;
unsigned int dac_val;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
*val = priv->chan_out_states[chan->channel];
err = regmap_read(priv->map, CIO_DAC_BASE + offset, &dac_val);
if (err)
return err;
*val = dac_val;
return IIO_VAL_INT;
}
@ -62,6 +87,7 @@ static int cio_dac_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct cio_dac_iio *const priv = iio_priv(indio_dev);
const unsigned int offset = chan->channel * CIO_DAC_CHANNEL_STRIDE;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
@ -70,10 +96,7 @@ static int cio_dac_write_raw(struct iio_dev *indio_dev,
if ((unsigned int)val > 4095)
return -EINVAL;
priv->chan_out_states[chan->channel] = val;
iowrite16(val, priv->base + chan->channel);
return 0;
return regmap_write(priv->map, CIO_DAC_BASE + offset, val);
}
static const struct iio_info cio_dac_info = {
@ -92,7 +115,7 @@ static int cio_dac_probe(struct device *dev, unsigned int id)
{
struct iio_dev *indio_dev;
struct cio_dac_iio *priv;
unsigned int i;
void __iomem *regs;
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!indio_dev)
@ -105,21 +128,22 @@ static int cio_dac_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
priv = iio_priv(indio_dev);
priv->base = devm_ioport_map(dev, base[id], CIO_DAC_EXTENT);
if (!priv->base)
regs = devm_ioport_map(dev, base[id], CIO_DAC_EXTENT);
if (!regs)
return -ENOMEM;
priv = iio_priv(indio_dev);
priv->map = devm_regmap_init_mmio(dev, regs, &cio_dac_regmap_config);
if (IS_ERR(priv->map))
return dev_err_probe(dev, PTR_ERR(priv->map),
"Unable to initialize register map\n");
indio_dev->info = &cio_dac_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = cio_dac_channels;
indio_dev->num_channels = CIO_DAC_NUM_CHAN;
indio_dev->name = dev_name(dev);
/* initialize DAC outputs to 0V */
for (i = 0; i < CIO_DAC_NUM_CHAN; i++)
iowrite16(0, priv->base + i);
return devm_iio_device_register(dev, indio_dev);
}

View File

@ -52,7 +52,7 @@ struct max5522_state {
} \
}
const struct iio_chan_spec max5522_channels[] = {
static const struct iio_chan_spec max5522_channels[] = {
MAX5522_CHANNEL(0),
MAX5522_CHANNEL(1),
};

View File

@ -490,11 +490,6 @@ static int admv1013_init(struct admv1013_state *st)
st->input_mode);
}
static void admv1013_clk_disable(void *data)
{
clk_disable_unprepare(data);
}
static void admv1013_reg_disable(void *data)
{
regulator_disable(data);
@ -559,11 +554,6 @@ static int admv1013_properties_parse(struct admv1013_state *st)
return dev_err_probe(&spi->dev, PTR_ERR(st->reg),
"failed to get the common-mode voltage\n");
st->clkin = devm_clk_get(&spi->dev, "lo_in");
if (IS_ERR(st->clkin))
return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
"failed to get the LO input clock\n");
return 0;
}
@ -601,13 +591,10 @@ static int admv1013_probe(struct spi_device *spi)
if (ret)
return ret;
ret = clk_prepare_enable(st->clkin);
if (ret)
return ret;
ret = devm_add_action_or_reset(&spi->dev, admv1013_clk_disable, st->clkin);
if (ret)
return ret;
st->clkin = devm_clk_get_enabled(&spi->dev, "lo_in");
if (IS_ERR(st->clkin))
return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
"failed to get the LO input clock\n");
st->nb.notifier_call = admv1013_freq_change;
ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb);

View File

@ -813,7 +813,7 @@ static irqreturn_t fxas21002c_data_rdy_thread(int irq, void *private)
if (!data_ready)
return IRQ_NONE;
iio_trigger_poll_chained(data->dready_trig);
iio_trigger_poll_nested(data->dready_trig);
return IRQ_HANDLED;
}

View File

@ -939,7 +939,7 @@ static irqreturn_t mpu3050_irq_thread(int irq, void *p)
if (!(val & MPU3050_INT_STATUS_RAW_RDY))
return IRQ_NONE;
iio_trigger_poll_chained(p);
iio_trigger_poll_nested(p);
return IRQ_HANDLED;
}

View File

@ -68,7 +68,7 @@ static irqreturn_t hts221_trigger_handler_thread(int irq, void *private)
if (!(status & HTS221_RH_DRDY_MASK))
return IRQ_NONE;
iio_trigger_poll_chained(hw->trig);
iio_trigger_poll_nested(hw->trig);
return IRQ_HANDLED;
}

View File

@ -326,11 +326,11 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
/*
* This is not an hard requirement but it's not advised to run the IMU
* with a sample rate lower than 4000Hz due to possible undersampling
* with a sample rate lower than 1900Hz due to possible undersampling
* issues. However, there are users that might really want to take the risk.
* Hence, we provide a module parameter for them. If set, we allow sample
* rates lower than 4KHz. By default, we won't allow this and we just roundup
* the rate to the next multiple of the input clock bigger than 4KHz. This
* rates lower than 1.9KHz. By default, we won't allow this and we just roundup
* the rate to the next multiple of the input clock bigger than 1.9KHz. This
* is done like this as in some cases (when DEC_RATE is 0) might give
* us the closest value to the one desired by the user...
*/

View File

@ -14,8 +14,8 @@ config IIO_ST_LSM6DSX
sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
ism330dlc, lsm6dso, lsm6dsox, asm330lhh, asm330lhhx, lsm6dsr,
lsm6ds3tr-c, ism330dhcx, lsm6dsrx, lsm6ds0, lsm6dsop, lsm6dstx,
lsm6dsv, lsm6dsv16x, lsm6dso16is, ism330is, lsm6dst and the
accelerometer/gyroscope of lsm9ds1.
lsm6dsv, lsm6dsv16x, lsm6dso16is, ism330is, asm330lhb, lsm6dst
and the accelerometer/gyroscope of lsm9ds1.
To compile this driver as a module, choose M here: the module
will be called st_lsm6dsx.

View File

@ -37,6 +37,7 @@
#define ST_LSM6DSV16X_DEV_NAME "lsm6dsv16x"
#define ST_LSM6DSO16IS_DEV_NAME "lsm6dso16is"
#define ST_ISM330IS_DEV_NAME "ism330is"
#define ST_ASM330LHB_DEV_NAME "asm330lhb"
enum st_lsm6dsx_hw_id {
ST_LSM6DS3_ID,
@ -61,6 +62,7 @@ enum st_lsm6dsx_hw_id {
ST_LSM6DSV16X_ID,
ST_LSM6DSO16IS_ID,
ST_ISM330IS_ID,
ST_ASM330LHB_ID,
ST_LSM6DSX_MAX_ID,
};
@ -137,6 +139,13 @@ struct st_lsm6dsx_odr_table_entry {
int odr_len;
};
struct st_lsm6dsx_samples_to_discard {
struct {
u32 milli_hz;
u16 samples;
} val[ST_LSM6DSX_ODR_LIST_SIZE];
};
struct st_lsm6dsx_fs {
u32 gain;
u8 val;
@ -291,6 +300,7 @@ struct st_lsm6dsx_ext_dev_settings {
* @irq_config: interrupts related registers.
* @drdy_mask: register info for data-ready mask (addr + mask).
* @odr_table: Hw sensors odr table (Hz + val).
* @samples_to_discard: Number of samples to discard for filters settling time.
* @fs_table: Hw sensors gain table (gain + val).
* @decimator: List of decimator register info (addr + mask).
* @batch: List of FIFO batching register info (addr + mask).
@ -323,6 +333,7 @@ struct st_lsm6dsx_settings {
} irq_config;
struct st_lsm6dsx_reg drdy_mask;
struct st_lsm6dsx_odr_table_entry odr_table[2];
struct st_lsm6dsx_samples_to_discard samples_to_discard[2];
struct st_lsm6dsx_fs_table_entry fs_table[2];
struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
@ -353,6 +364,7 @@ enum st_lsm6dsx_fifo_mode {
* @hw: Pointer to instance of struct st_lsm6dsx_hw.
* @gain: Configured sensor sensitivity.
* @odr: Output data rate of the sensor [Hz].
* @samples_to_discard: Number of samples to discard for filters settling time.
* @watermark: Sensor watermark level.
* @decimator: Sensor decimation factor.
* @sip: Number of samples in a given pattern.
@ -367,6 +379,7 @@ struct st_lsm6dsx_sensor {
u32 gain;
u32 odr;
u16 samples_to_discard;
u16 watermark;
u8 decimator;
u8 sip;

View File

@ -15,7 +15,7 @@
* value of the decimation factor and ODR set for each FIFO data set.
*
* LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/LSM6DSRX/ISM330DHCX/
* LSM6DST/LSM6DSOP/LSM6DSTX/LSM6DSV:
* LSM6DST/LSM6DSOP/LSM6DSTX/LSM6DSV/ASM330LHB:
* The FIFO buffer can be configured to store data from gyroscope and
* accelerometer. Each sample is queued with a tag (1B) indicating data
* source (gyroscope, accelerometer, hw timer).
@ -457,17 +457,31 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
}
if (gyro_sip > 0 && !(sip % gyro_sensor->decimator)) {
iio_push_to_buffers_with_timestamp(
hw->iio_devs[ST_LSM6DSX_ID_GYRO],
&hw->scan[ST_LSM6DSX_ID_GYRO],
gyro_sensor->ts_ref + ts);
/*
* We need to discards gyro samples during
* filters settling time
*/
if (gyro_sensor->samples_to_discard > 0)
gyro_sensor->samples_to_discard--;
else
iio_push_to_buffers_with_timestamp(
hw->iio_devs[ST_LSM6DSX_ID_GYRO],
&hw->scan[ST_LSM6DSX_ID_GYRO],
gyro_sensor->ts_ref + ts);
gyro_sip--;
}
if (acc_sip > 0 && !(sip % acc_sensor->decimator)) {
iio_push_to_buffers_with_timestamp(
hw->iio_devs[ST_LSM6DSX_ID_ACC],
&hw->scan[ST_LSM6DSX_ID_ACC],
acc_sensor->ts_ref + ts);
/*
* We need to discards accel samples during
* filters settling time
*/
if (acc_sensor->samples_to_discard > 0)
acc_sensor->samples_to_discard--;
else
iio_push_to_buffers_with_timestamp(
hw->iio_devs[ST_LSM6DSX_ID_ACC],
&hw->scan[ST_LSM6DSX_ID_ACC],
acc_sensor->ts_ref + ts);
acc_sip--;
}
if (ext_sip > 0 && !(sip % ext_sensor->decimator)) {
@ -654,6 +668,30 @@ int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
return err;
}
static void
st_lsm6dsx_update_samples_to_discard(struct st_lsm6dsx_sensor *sensor)
{
const struct st_lsm6dsx_samples_to_discard *data;
struct st_lsm6dsx_hw *hw = sensor->hw;
int i;
if (sensor->id != ST_LSM6DSX_ID_GYRO &&
sensor->id != ST_LSM6DSX_ID_ACC)
return;
/* check if drdy mask is supported in hw */
if (hw->settings->drdy_mask.addr)
return;
data = &hw->settings->samples_to_discard[sensor->id];
for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) {
if (data->val[i].milli_hz == sensor->odr) {
sensor->samples_to_discard = data->val[i].samples;
return;
}
}
}
int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable)
{
struct st_lsm6dsx_hw *hw = sensor->hw;
@ -673,6 +711,9 @@ int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable)
goto out;
}
if (enable)
st_lsm6dsx_update_samples_to_discard(sensor);
err = st_lsm6dsx_device_set_enable(sensor, enable);
if (err < 0)
goto out;

View File

@ -634,6 +634,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.fs_len = 4,
},
},
.samples_to_discard = {
[ST_LSM6DSX_ID_ACC] = {
.val[0] = { 12500, 1 },
.val[1] = { 26000, 1 },
.val[2] = { 52000, 1 },
.val[3] = { 104000, 2 },
.val[4] = { 208000, 2 },
.val[5] = { 416000, 2 },
},
[ST_LSM6DSX_ID_GYRO] = {
.val[0] = { 12500, 2 },
.val[1] = { 26000, 5 },
.val[2] = { 52000, 7 },
.val[3] = { 104000, 12 },
.val[4] = { 208000, 20 },
.val[5] = { 416000, 36 },
},
},
.irq_config = {
.irq1 = {
.addr = 0x0d,
@ -1014,6 +1032,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.hw_id = ST_LSM6DSOP_ID,
.name = ST_LSM6DSOP_DEV_NAME,
.wai = 0x6c,
}, {
.hw_id = ST_ASM330LHB_ID,
.name = ST_ASM330LHB_DEV_NAME,
.wai = 0x6b,
},
},
.channels = {

View File

@ -125,6 +125,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
.compatible = "st,ism330is",
.data = (void *)ST_ISM330IS_ID,
},
{
.compatible = "st,asm330lhb",
.data = (void *)ST_ASM330LHB_ID,
},
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
@ -152,6 +156,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID },
{ ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID },
{ ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
{ ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID },
{},
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);

View File

@ -125,6 +125,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
.compatible = "st,ism330is",
.data = (void *)ST_ISM330IS_ID,
},
{
.compatible = "st,asm330lhb",
.data = (void *)ST_ASM330LHB_ID,
},
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@ -152,6 +156,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID },
{ ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID },
{ ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
{ ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID },
{},
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);

File diff suppressed because it is too large Load Diff

View File

@ -192,6 +192,12 @@ static void iio_trigger_notify_done_atomic(struct iio_trigger *trig)
schedule_work(&trig->reenable_work);
}
/**
* iio_trigger_poll() - Call the IRQ trigger handler of the consumers
* @trig: trigger which occurred
*
* This function should only be called from a hard IRQ context.
*/
void iio_trigger_poll(struct iio_trigger *trig)
{
int i;
@ -216,7 +222,14 @@ irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private)
}
EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll);
void iio_trigger_poll_chained(struct iio_trigger *trig)
/**
* iio_trigger_poll_nested() - Call the threaded trigger handler of the
* consumers
* @trig: trigger which occurred
*
* This function should only be called from a kernel thread context.
*/
void iio_trigger_poll_nested(struct iio_trigger *trig)
{
int i;
@ -231,7 +244,7 @@ void iio_trigger_poll_chained(struct iio_trigger *trig)
}
}
}
EXPORT_SYMBOL(iio_trigger_poll_chained);
EXPORT_SYMBOL(iio_trigger_poll_nested);
void iio_trigger_notify_done(struct iio_trigger *trig)
{

View File

@ -289,6 +289,20 @@ config JSA1212
To compile this driver as a module, choose M here:
the module will be called jsa1212.
config ROHM_BU27034
tristate "ROHM BU27034 ambient light sensor"
depends on I2C
select REGMAP_I2C
select IIO_GTS_HELPER
select IIO_BUFFER
select IIO_KFIFO_BUF
help
Enable support for the ROHM BU27034 ambient light sensor. ROHM BU27034
is an ambient light sesnor with 3 channels and 3 photo diodes capable
of detecting a very wide range of illuminance.
Typical application is adjusting LCD and backlight power of TVs and
mobile phones.
config RPR0521
tristate "ROHM RPR0521 ALS and proximity sensor driver"
depends on I2C

View File

@ -38,6 +38,7 @@ obj-$(CONFIG_MAX44009) += max44009.o
obj-$(CONFIG_NOA1305) += noa1305.o
obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_PA12203001) += pa12203001.o
obj-$(CONFIG_ROHM_BU27034) += rohm-bu27034.o
obj-$(CONFIG_RPR0521) += rpr0521.o
obj-$(CONFIG_SI1133) += si1133.o
obj-$(CONFIG_SI1145) += si1145.o

View File

@ -108,7 +108,7 @@ static void acpi_als_notify(struct acpi_device *device, u32 event)
if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev)) {
switch (event) {
case ACPI_ALS_NOTIFY_ILLUMINANCE:
iio_trigger_poll_chained(als->trig);
iio_trigger_poll_nested(als->trig);
break;
default:
/* Unhandled event */

View File

@ -527,6 +527,12 @@ static int max44009_probe(struct i2c_client *client)
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct of_device_id max44009_of_match[] = {
{ .compatible = "maxim,max44009" },
{ }
};
MODULE_DEVICE_TABLE(of, max44009_of_match);
static const struct i2c_device_id max44009_id[] = {
{ "max44009", 0 },
{ }
@ -536,18 +542,13 @@ MODULE_DEVICE_TABLE(i2c, max44009_id);
static struct i2c_driver max44009_driver = {
.driver = {
.name = MAX44009_DRV_NAME,
.of_match_table = max44009_of_match,
},
.probe_new = max44009_probe,
.id_table = max44009_id,
};
module_i2c_driver(max44009_driver);
static const struct of_device_id max44009_of_match[] = {
{ .compatible = "maxim,max44009" },
{ }
};
MODULE_DEVICE_TABLE(of, max44009_of_match);
MODULE_AUTHOR("Robert Eshleman <bobbyeshleman@gmail.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MAX44009 ambient light sensor driver");

File diff suppressed because it is too large Load Diff

View File

@ -431,7 +431,7 @@ static irqreturn_t rpr0521_drdy_irq_thread(int irq, void *private)
struct rpr0521_data *data = iio_priv(indio_dev);
if (rpr0521_is_triggered(data)) {
iio_trigger_poll_chained(data->drdy_trigger0);
iio_trigger_poll_nested(data->drdy_trigger0);
return IRQ_HANDLED;
}

View File

@ -161,7 +161,7 @@ static irqreturn_t st_uvis25_trigger_handler_thread(int irq, void *private)
if (!(status & ST_UVIS25_REG_UV_DA_MASK))
return IRQ_NONE;
iio_trigger_poll_chained(hw->trig);
iio_trigger_poll_nested(hw->trig);
return IRQ_HANDLED;
}

View File

@ -1077,7 +1077,7 @@ static irqreturn_t vcnl4010_irq_thread(int irq, void *p)
}
if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev))
iio_trigger_poll_chained(indio_dev->trig);
iio_trigger_poll_nested(indio_dev->trig);
end:
return IRQ_HANDLED;

View File

@ -89,7 +89,7 @@ static irqreturn_t vcnl4035_drdy_irq_thread(int irq, void *private)
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_EITHER),
iio_get_time_ns(indio_dev));
iio_trigger_poll_chained(data->drdy_trigger0);
iio_trigger_poll_nested(data->drdy_trigger0);
return IRQ_HANDLED;
}

View File

@ -118,7 +118,7 @@ static int lmp91000_read(struct lmp91000_data *data, int channel, int *val)
data->chan_select = channel != LMP91000_REG_MODECN_3LEAD;
iio_trigger_poll_chained(data->trig);
iio_trigger_poll_nested(data->trig);
ret = wait_for_completion_timeout(&data->completion, HZ);
reinit_completion(&data->completion);

View File

@ -17,14 +17,14 @@ config ABP060MG
will be called abp060mg.
config BMP280
tristate "Bosch Sensortec BMP180/BMP280/BMP380 pressure sensor I2C driver"
tristate "Bosch Sensortec BMP180/BMP280/BMP380/BMP580 pressure sensor driver"
depends on (I2C || SPI_MASTER)
select REGMAP
select BMP280_I2C if (I2C)
select BMP280_SPI if (SPI_MASTER)
help
Say yes here to build support for Bosch Sensortec BMP180, BMP280 and
BMP380 pressure and temperature sensors. Also supports the BME280 with
Say yes here to build support for Bosch Sensortec BMP180, BMP280, BMP380
and BMP580 pressure and temperature sensors. Also supports the BME280 with
an additional humidity sensor channel.
To compile this driver as a module, choose M here: the core module

View File

@ -13,6 +13,7 @@
* https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf
* https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf
* https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp388-ds001.pdf
* https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp581-ds004.pdf
*
* Notice:
* The link to the bmp180 datasheet points to an outdated version missing these changes:
@ -27,6 +28,7 @@
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
@ -49,65 +51,6 @@
*/
enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD };
struct bmp180_calib {
s16 AC1;
s16 AC2;
s16 AC3;
u16 AC4;
u16 AC5;
u16 AC6;
s16 B1;
s16 B2;
s16 MB;
s16 MC;
s16 MD;
};
/* See datasheet Section 4.2.2. */
struct bmp280_calib {
u16 T1;
s16 T2;
s16 T3;
u16 P1;
s16 P2;
s16 P3;
s16 P4;
s16 P5;
s16 P6;
s16 P7;
s16 P8;
s16 P9;
u8 H1;
s16 H2;
u8 H3;
s16 H4;
s16 H5;
s8 H6;
};
/* See datasheet Section 3.11.1. */
struct bmp380_calib {
u16 T1;
u16 T2;
s8 T3;
s16 P1;
s16 P2;
s8 P3;
s8 P4;
u16 P5;
u16 P6;
s8 P7;
s8 P8;
s16 P9;
s8 P10;
s8 P11;
};
static const char *const bmp280_supply_names[] = {
"vddd", "vdda"
};
#define BMP280_NUM_SUPPLIES ARRAY_SIZE(bmp280_supply_names)
enum bmp380_odr {
BMP380_ODR_200HZ,
@ -130,92 +73,39 @@ enum bmp380_odr {
BMP380_ODR_0_0015HZ,
};
struct bmp280_data {
struct device *dev;
struct mutex lock;
struct regmap *regmap;
struct completion done;
bool use_eoc;
const struct bmp280_chip_info *chip_info;
union {
struct bmp180_calib bmp180;
struct bmp280_calib bmp280;
struct bmp380_calib bmp380;
} calib;
struct regulator_bulk_data supplies[BMP280_NUM_SUPPLIES];
unsigned int start_up_time; /* in microseconds */
/* log of base 2 of oversampling rate */
u8 oversampling_press;
u8 oversampling_temp;
u8 oversampling_humid;
u8 iir_filter_coeff;
/*
* BMP380 devices introduce sampling frequency configuration. See
* datasheet sections 3.3.3. and 4.3.19 for more details.
*
* BMx280 devices allowed indirect configuration of sampling frequency
* changing the t_standby duration between measurements, as detailed on
* section 3.6.3 of the datasheet.
*/
int sampling_freq;
/*
* Carryover value from temperature conversion, used in pressure
* calculation.
*/
s32 t_fine;
/*
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
*/
union {
/* Sensor data buffer */
u8 buf[3];
/* Calibration data buffers */
__le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS / 2];
__be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT / 2];
u8 bmp380_cal_buf[BMP380_CALIB_REG_COUNT];
/* Miscellaneous, endianess-aware data buffers */
__le16 le16;
__be16 be16;
} __aligned(IIO_DMA_MINALIGN);
};
struct bmp280_chip_info {
unsigned int id_reg;
const struct iio_chan_spec *channels;
int num_channels;
unsigned int start_up_time;
const int *oversampling_temp_avail;
int num_oversampling_temp_avail;
int oversampling_temp_default;
const int *oversampling_press_avail;
int num_oversampling_press_avail;
int oversampling_press_default;
const int *oversampling_humid_avail;
int num_oversampling_humid_avail;
int oversampling_humid_default;
const int *iir_filter_coeffs_avail;
int num_iir_filter_coeffs_avail;
int iir_filter_coeff_default;
const int (*sampling_freq_avail)[2];
int num_sampling_freq_avail;
int sampling_freq_default;
int (*chip_config)(struct bmp280_data *);
int (*read_temp)(struct bmp280_data *, int *);
int (*read_press)(struct bmp280_data *, int *, int *);
int (*read_humid)(struct bmp280_data *, int *, int *);
int (*read_calib)(struct bmp280_data *);
enum bmp580_odr {
BMP580_ODR_240HZ,
BMP580_ODR_218HZ,
BMP580_ODR_199HZ,
BMP580_ODR_179HZ,
BMP580_ODR_160HZ,
BMP580_ODR_149HZ,
BMP580_ODR_140HZ,
BMP580_ODR_129HZ,
BMP580_ODR_120HZ,
BMP580_ODR_110HZ,
BMP580_ODR_100HZ,
BMP580_ODR_89HZ,
BMP580_ODR_80HZ,
BMP580_ODR_70HZ,
BMP580_ODR_60HZ,
BMP580_ODR_50HZ,
BMP580_ODR_45HZ,
BMP580_ODR_40HZ,
BMP580_ODR_35HZ,
BMP580_ODR_30HZ,
BMP580_ODR_25HZ,
BMP580_ODR_20HZ,
BMP580_ODR_15HZ,
BMP580_ODR_10HZ,
BMP580_ODR_5HZ,
BMP580_ODR_4HZ,
BMP580_ODR_3HZ,
BMP580_ODR_2HZ,
BMP580_ODR_1HZ,
BMP580_ODR_0_5HZ,
BMP580_ODR_0_25HZ,
BMP580_ODR_0_125HZ,
};
/*
@ -473,7 +363,7 @@ static u32 bmp280_compensate_press(struct bmp280_data *data,
}
static int bmp280_read_temp(struct bmp280_data *data,
int *val)
int *val, int *val2)
{
s32 adc_temp, comp_temp;
int ret;
@ -513,7 +403,7 @@ static int bmp280_read_press(struct bmp280_data *data,
int ret;
/* Read and compensate temperature so we get a reading of t_fine. */
ret = bmp280_read_temp(data, NULL);
ret = bmp280_read_temp(data, NULL, NULL);
if (ret < 0)
return ret;
@ -545,7 +435,7 @@ static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2)
int ret;
/* Read and compensate temperature so we get a reading of t_fine. */
ret = bmp280_read_temp(data, NULL);
ret = bmp280_read_temp(data, NULL, NULL);
if (ret < 0)
return ret;
@ -589,7 +479,7 @@ static int bmp280_read_raw(struct iio_dev *indio_dev,
ret = data->chip_info->read_press(data, val, val2);
break;
case IIO_TEMP:
ret = data->chip_info->read_temp(data, val);
ret = data->chip_info->read_temp(data, val, val2);
break;
default:
ret = -EINVAL;
@ -905,8 +795,10 @@ static int bmp280_chip_config(struct bmp280_data *data)
static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 };
static const struct bmp280_chip_info bmp280_chip_info = {
const struct bmp280_chip_info bmp280_chip_info = {
.id_reg = BMP280_REG_ID,
.chip_id = BMP280_CHIP_ID,
.regmap_config = &bmp280_regmap_config,
.start_up_time = 2000,
.channels = bmp280_channels,
.num_channels = 2,
@ -934,6 +826,7 @@ static const struct bmp280_chip_info bmp280_chip_info = {
.read_press = bmp280_read_press,
.read_calib = bmp280_read_calib,
};
EXPORT_SYMBOL_NS(bmp280_chip_info, IIO_BMP280);
static int bme280_chip_config(struct bmp280_data *data)
{
@ -953,8 +846,10 @@ static int bme280_chip_config(struct bmp280_data *data)
return bmp280_chip_config(data);
}
static const struct bmp280_chip_info bme280_chip_info = {
const struct bmp280_chip_info bme280_chip_info = {
.id_reg = BMP280_REG_ID,
.chip_id = BME280_CHIP_ID,
.regmap_config = &bmp280_regmap_config,
.start_up_time = 2000,
.channels = bmp280_channels,
.num_channels = 3,
@ -977,6 +872,7 @@ static const struct bmp280_chip_info bme280_chip_info = {
.read_humid = bmp280_read_humid,
.read_calib = bme280_read_calib,
};
EXPORT_SYMBOL_NS(bme280_chip_info, IIO_BMP280);
/*
* Helper function to send a command to BMP3XX sensors.
@ -1095,7 +991,7 @@ static u32 bmp380_compensate_press(struct bmp280_data *data, u32 adc_press)
return comp_press;
}
static int bmp380_read_temp(struct bmp280_data *data, int *val)
static int bmp380_read_temp(struct bmp280_data *data, int *val, int *val2)
{
s32 comp_temp;
u32 adc_temp;
@ -1135,7 +1031,7 @@ static int bmp380_read_press(struct bmp280_data *data, int *val, int *val2)
int ret;
/* Read and compensate for temperature so we get a reading of t_fine */
ret = bmp380_read_temp(data, NULL);
ret = bmp380_read_temp(data, NULL, NULL);
if (ret)
return ret;
@ -1217,6 +1113,12 @@ static const int bmp380_odr_table[][2] = {
[BMP380_ODR_0_0015HZ] = {0, 1526},
};
static int bmp380_preinit(struct bmp280_data *data)
{
/* BMP3xx requires soft-reset as part of initialization */
return bmp380_cmd(data, BMP380_CMD_SOFT_RESET);
}
static int bmp380_chip_config(struct bmp280_data *data)
{
bool change = false, aux;
@ -1319,8 +1221,10 @@ static int bmp380_chip_config(struct bmp280_data *data)
static const int bmp380_oversampling_avail[] = { 1, 2, 4, 8, 16, 32 };
static const int bmp380_iir_filter_coeffs_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128};
static const struct bmp280_chip_info bmp380_chip_info = {
const struct bmp280_chip_info bmp380_chip_info = {
.id_reg = BMP380_REG_ID,
.chip_id = BMP380_CHIP_ID,
.regmap_config = &bmp380_regmap_config,
.start_up_time = 2000,
.channels = bmp380_channels,
.num_channels = 2,
@ -1345,7 +1249,508 @@ static const struct bmp280_chip_info bmp380_chip_info = {
.read_temp = bmp380_read_temp,
.read_press = bmp380_read_press,
.read_calib = bmp380_read_calib,
.preinit = bmp380_preinit,
};
EXPORT_SYMBOL_NS(bmp380_chip_info, IIO_BMP280);
static int bmp580_soft_reset(struct bmp280_data *data)
{
unsigned int reg;
int ret;
ret = regmap_write(data->regmap, BMP580_REG_CMD, BMP580_CMD_SOFT_RESET);
if (ret) {
dev_err(data->dev, "failed to send reset command to device\n");
return ret;
}
usleep_range(2000, 2500);
/* Dummy read of chip_id */
ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, &reg);
if (ret) {
dev_err(data->dev, "failed to reestablish comms after reset\n");
return ret;
}
ret = regmap_read(data->regmap, BMP580_REG_INT_STATUS, &reg);
if (ret) {
dev_err(data->dev, "error reading interrupt status register\n");
return ret;
}
if (!(reg & BMP580_INT_STATUS_POR_MASK)) {
dev_err(data->dev, "error resetting sensor\n");
return -EINVAL;
}
return 0;
}
/**
* bmp580_nvm_operation() - Helper function to commit NVM memory operations
* @data: sensor data struct
* @is_write: flag to signal write operation
*/
static int bmp580_nvm_operation(struct bmp280_data *data, bool is_write)
{
unsigned long timeout, poll;
unsigned int reg;
int ret;
/* Check NVM ready flag */
ret = regmap_read(data->regmap, BMP580_REG_STATUS, &reg);
if (ret) {
dev_err(data->dev, "failed to check nvm status\n");
return ret;
}
if (!(reg & BMP580_STATUS_NVM_RDY_MASK)) {
dev_err(data->dev, "sensor's nvm is not ready\n");
return -EIO;
}
/* Start NVM operation sequence */
ret = regmap_write(data->regmap, BMP580_REG_CMD, BMP580_CMD_NVM_OP_SEQ_0);
if (ret) {
dev_err(data->dev, "failed to send nvm operation's first sequence\n");
return ret;
}
if (is_write) {
/* Send NVM write sequence */
ret = regmap_write(data->regmap, BMP580_REG_CMD,
BMP580_CMD_NVM_WRITE_SEQ_1);
if (ret) {
dev_err(data->dev, "failed to send nvm write sequence\n");
return ret;
}
/* Datasheet says on 4.8.1.2 it takes approximately 10ms */
poll = 2000;
timeout = 12000;
} else {
/* Send NVM read sequence */
ret = regmap_write(data->regmap, BMP580_REG_CMD,
BMP580_CMD_NVM_READ_SEQ_1);
if (ret) {
dev_err(data->dev, "failed to send nvm read sequence\n");
return ret;
}
/* Datasheet says on 4.8.1.1 it takes approximately 200us */
poll = 50;
timeout = 400;
}
if (ret) {
dev_err(data->dev, "failed to write command sequence\n");
return -EIO;
}
/* Wait until NVM is ready again */
ret = regmap_read_poll_timeout(data->regmap, BMP580_REG_STATUS, reg,
(reg & BMP580_STATUS_NVM_RDY_MASK),
poll, timeout);
if (ret) {
dev_err(data->dev, "error checking nvm operation status\n");
return ret;
}
/* Check NVM error flags */
if ((reg & BMP580_STATUS_NVM_ERR_MASK) || (reg & BMP580_STATUS_NVM_CMD_ERR_MASK)) {
dev_err(data->dev, "error processing nvm operation\n");
return -EIO;
}
return 0;
}
/*
* Contrary to previous sensors families, compensation algorithm is builtin.
* We are only required to read the register raw data and adapt the ranges
* for what is expected on IIO ABI.
*/
static int bmp580_read_temp(struct bmp280_data *data, int *val, int *val2)
{
s32 raw_temp;
int ret;
ret = regmap_bulk_read(data->regmap, BMP580_REG_TEMP_XLSB, data->buf,
sizeof(data->buf));
if (ret) {
dev_err(data->dev, "failed to read temperature\n");
return ret;
}
raw_temp = get_unaligned_le24(data->buf);
if (raw_temp == BMP580_TEMP_SKIPPED) {
dev_err(data->dev, "reading temperature skipped\n");
return -EIO;
}
/*
* Temperature is returned in Celsius degrees in fractional
* form down 2^16. We reescale by x1000 to return milli Celsius
* to respect IIO ABI.
*/
*val = raw_temp * 1000;
*val2 = 16;
return IIO_VAL_FRACTIONAL_LOG2;
}
static int bmp580_read_press(struct bmp280_data *data, int *val, int *val2)
{
u32 raw_press;
int ret;
ret = regmap_bulk_read(data->regmap, BMP580_REG_PRESS_XLSB, data->buf,
sizeof(data->buf));
if (ret) {
dev_err(data->dev, "failed to read pressure\n");
return ret;
}
raw_press = get_unaligned_le24(data->buf);
if (raw_press == BMP580_PRESS_SKIPPED) {
dev_err(data->dev, "reading pressure skipped\n");
return -EIO;
}
/*
* Pressure is returned in Pascals in fractional form down 2^16.
* We reescale /1000 to convert to kilopascal to respect IIO ABI.
*/
*val = raw_press;
*val2 = 64000; /* 2^6 * 1000 */
return IIO_VAL_FRACTIONAL;
}
static const int bmp580_odr_table[][2] = {
[BMP580_ODR_240HZ] = {240, 0},
[BMP580_ODR_218HZ] = {218, 0},
[BMP580_ODR_199HZ] = {199, 0},
[BMP580_ODR_179HZ] = {179, 0},
[BMP580_ODR_160HZ] = {160, 0},
[BMP580_ODR_149HZ] = {149, 0},
[BMP580_ODR_140HZ] = {140, 0},
[BMP580_ODR_129HZ] = {129, 0},
[BMP580_ODR_120HZ] = {120, 0},
[BMP580_ODR_110HZ] = {110, 0},
[BMP580_ODR_100HZ] = {100, 0},
[BMP580_ODR_89HZ] = {89, 0},
[BMP580_ODR_80HZ] = {80, 0},
[BMP580_ODR_70HZ] = {70, 0},
[BMP580_ODR_60HZ] = {60, 0},
[BMP580_ODR_50HZ] = {50, 0},
[BMP580_ODR_45HZ] = {45, 0},
[BMP580_ODR_40HZ] = {40, 0},
[BMP580_ODR_35HZ] = {35, 0},
[BMP580_ODR_30HZ] = {30, 0},
[BMP580_ODR_25HZ] = {25, 0},
[BMP580_ODR_20HZ] = {20, 0},
[BMP580_ODR_15HZ] = {15, 0},
[BMP580_ODR_10HZ] = {10, 0},
[BMP580_ODR_5HZ] = {5, 0},
[BMP580_ODR_4HZ] = {4, 0},
[BMP580_ODR_3HZ] = {3, 0},
[BMP580_ODR_2HZ] = {2, 0},
[BMP580_ODR_1HZ] = {1, 0},
[BMP580_ODR_0_5HZ] = {0, 500000},
[BMP580_ODR_0_25HZ] = {0, 250000},
[BMP580_ODR_0_125HZ] = {0, 125000},
};
static const int bmp580_nvmem_addrs[] = { 0x20, 0x21, 0x22 };
static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
struct bmp280_data *data = priv;
u16 *dst = val;
int ret, addr;
pm_runtime_get_sync(data->dev);
mutex_lock(&data->lock);
/* Set sensor in standby mode */
ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG,
BMP580_MODE_MASK | BMP580_ODR_DEEPSLEEP_DIS,
BMP580_ODR_DEEPSLEEP_DIS |
FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_SLEEP));
if (ret) {
dev_err(data->dev, "failed to change sensor to standby mode\n");
goto exit;
}
/* Wait standby transition time */
usleep_range(2500, 3000);
while (bytes >= sizeof(*dst)) {
addr = bmp580_nvmem_addrs[offset / sizeof(*dst)];
ret = regmap_write(data->regmap, BMP580_REG_NVM_ADDR,
FIELD_PREP(BMP580_NVM_ROW_ADDR_MASK, addr));
if (ret) {
dev_err(data->dev, "error writing nvm address\n");
goto exit;
}
ret = bmp580_nvm_operation(data, false);
if (ret)
goto exit;
ret = regmap_bulk_read(data->regmap, BMP580_REG_NVM_DATA_LSB, &data->le16,
sizeof(data->le16));
if (ret) {
dev_err(data->dev, "error reading nvm data regs\n");
goto exit;
}
*dst++ = le16_to_cpu(data->le16);
bytes -= sizeof(*dst);
offset += sizeof(*dst);
}
exit:
/* Restore chip config */
data->chip_info->chip_config(data);
mutex_unlock(&data->lock);
pm_runtime_mark_last_busy(data->dev);
pm_runtime_put_autosuspend(data->dev);
return ret;
}
static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
struct bmp280_data *data = priv;
u16 *buf = val;
int ret, addr;
pm_runtime_get_sync(data->dev);
mutex_lock(&data->lock);
/* Set sensor in standby mode */
ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG,
BMP580_MODE_MASK | BMP580_ODR_DEEPSLEEP_DIS,
BMP580_ODR_DEEPSLEEP_DIS |
FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_SLEEP));
if (ret) {
dev_err(data->dev, "failed to change sensor to standby mode\n");
goto exit;
}
/* Wait standby transition time */
usleep_range(2500, 3000);
while (bytes >= sizeof(*buf)) {
addr = bmp580_nvmem_addrs[offset / sizeof(*buf)];
ret = regmap_write(data->regmap, BMP580_REG_NVM_ADDR, BMP580_NVM_PROG_EN |
FIELD_PREP(BMP580_NVM_ROW_ADDR_MASK, addr));
if (ret) {
dev_err(data->dev, "error writing nvm address\n");
goto exit;
}
data->le16 = cpu_to_le16(*buf++);
ret = regmap_bulk_write(data->regmap, BMP580_REG_NVM_DATA_LSB, &data->le16,
sizeof(data->le16));
if (ret) {
dev_err(data->dev, "error writing LSB NVM data regs\n");
goto exit;
}
ret = bmp580_nvm_operation(data, true);
if (ret)
goto exit;
/* Disable programming mode bit */
ret = regmap_update_bits(data->regmap, BMP580_REG_NVM_ADDR,
BMP580_NVM_PROG_EN, 0);
if (ret) {
dev_err(data->dev, "error resetting nvm write\n");
goto exit;
}
bytes -= sizeof(*buf);
offset += sizeof(*buf);
}
exit:
/* Restore chip config */
data->chip_info->chip_config(data);
mutex_unlock(&data->lock);
pm_runtime_mark_last_busy(data->dev);
pm_runtime_put_autosuspend(data->dev);
return ret;
}
static int bmp580_preinit(struct bmp280_data *data)
{
struct nvmem_config config = {
.dev = data->dev,
.priv = data,
.name = "bmp580_nvmem",
.word_size = sizeof(u16),
.stride = sizeof(u16),
.size = 3 * sizeof(u16),
.reg_read = bmp580_nvmem_read,
.reg_write = bmp580_nvmem_write,
};
unsigned int reg;
int ret;
/* Issue soft-reset command */
ret = bmp580_soft_reset(data);
if (ret)
return ret;
/* Post powerup sequence */
ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, &reg);
if (ret)
return ret;
/* Print warn message if we don't know the chip id */
if (reg != BMP580_CHIP_ID && reg != BMP580_CHIP_ID_ALT)
dev_warn(data->dev, "preinit: unexpected chip_id\n");
ret = regmap_read(data->regmap, BMP580_REG_STATUS, &reg);
if (ret)
return ret;
/* Check nvm status */
if (!(reg & BMP580_STATUS_NVM_RDY_MASK) || (reg & BMP580_STATUS_NVM_ERR_MASK)) {
dev_err(data->dev, "preinit: nvm error on powerup sequence\n");
return -EIO;
}
/* Register nvmem device */
return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config));
}
static int bmp580_chip_config(struct bmp280_data *data)
{
bool change = false, aux;
unsigned int tmp;
u8 reg_val;
int ret;
/* Sets sensor in standby mode */
ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG,
BMP580_MODE_MASK | BMP580_ODR_DEEPSLEEP_DIS,
BMP580_ODR_DEEPSLEEP_DIS |
FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_SLEEP));
if (ret) {
dev_err(data->dev, "failed to change sensor to standby mode\n");
return ret;
}
/* From datasheet's table 4: electrical characteristics */
usleep_range(2500, 3000);
/* Set default DSP mode settings */
reg_val = FIELD_PREP(BMP580_DSP_COMP_MASK, BMP580_DSP_PRESS_TEMP_COMP_EN) |
BMP580_DSP_SHDW_IIR_TEMP_EN | BMP580_DSP_SHDW_IIR_PRESS_EN;
ret = regmap_update_bits(data->regmap, BMP580_REG_DSP_CONFIG,
BMP580_DSP_COMP_MASK |
BMP580_DSP_SHDW_IIR_TEMP_EN |
BMP580_DSP_SHDW_IIR_PRESS_EN, reg_val);
/* Configure oversampling */
reg_val = FIELD_PREP(BMP580_OSR_TEMP_MASK, data->oversampling_temp) |
FIELD_PREP(BMP580_OSR_PRESS_MASK, data->oversampling_press) |
BMP580_OSR_PRESS_EN;
ret = regmap_update_bits_check(data->regmap, BMP580_REG_OSR_CONFIG,
BMP580_OSR_TEMP_MASK | BMP580_OSR_PRESS_MASK |
BMP580_OSR_PRESS_EN,
reg_val, &aux);
if (ret) {
dev_err(data->dev, "failed to write oversampling register\n");
return ret;
}
change = change || aux;
/* Configure output data rate */
ret = regmap_update_bits_check(data->regmap, BMP580_REG_ODR_CONFIG, BMP580_ODR_MASK,
FIELD_PREP(BMP580_ODR_MASK, data->sampling_freq),
&aux);
if (ret) {
dev_err(data->dev, "failed to write ODR configuration register\n");
return ret;
}
change = change || aux;
/* Set filter data */
reg_val = FIELD_PREP(BMP580_DSP_IIR_PRESS_MASK, data->iir_filter_coeff) |
FIELD_PREP(BMP580_DSP_IIR_TEMP_MASK, data->iir_filter_coeff);
ret = regmap_update_bits_check(data->regmap, BMP580_REG_DSP_IIR,
BMP580_DSP_IIR_PRESS_MASK |
BMP580_DSP_IIR_TEMP_MASK,
reg_val, &aux);
if (ret) {
dev_err(data->dev, "failed to write config register\n");
return ret;
}
change = change || aux;
/* Restore sensor to normal operation mode */
ret = regmap_write_bits(data->regmap, BMP580_REG_ODR_CONFIG,
BMP580_MODE_MASK,
FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_NORMAL));
if (ret) {
dev_err(data->dev, "failed to set normal mode\n");
return ret;
}
/* From datasheet's table 4: electrical characteristics */
usleep_range(3000, 3500);
if (change) {
/*
* Check if ODR and OSR settings are valid or we are
* operating in a degraded mode.
*/
ret = regmap_read(data->regmap, BMP580_REG_EFF_OSR, &tmp);
if (ret) {
dev_err(data->dev, "error reading effective OSR register\n");
return ret;
}
if (!(tmp & BMP580_EFF_OSR_VALID_ODR)) {
dev_warn(data->dev, "OSR and ODR incompatible settings detected\n");
/* Set current OSR settings from data on effective OSR */
data->oversampling_temp = FIELD_GET(BMP580_EFF_OSR_TEMP_MASK, tmp);
data->oversampling_press = FIELD_GET(BMP580_EFF_OSR_PRESS_MASK, tmp);
return -EINVAL;
}
}
return 0;
}
static const int bmp580_oversampling_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
const struct bmp280_chip_info bmp580_chip_info = {
.id_reg = BMP580_REG_CHIP_ID,
.chip_id = BMP580_CHIP_ID,
.regmap_config = &bmp580_regmap_config,
.start_up_time = 2000,
.channels = bmp380_channels,
.num_channels = 2,
.oversampling_temp_avail = bmp580_oversampling_avail,
.num_oversampling_temp_avail = ARRAY_SIZE(bmp580_oversampling_avail),
.oversampling_temp_default = ilog2(1),
.oversampling_press_avail = bmp580_oversampling_avail,
.num_oversampling_press_avail = ARRAY_SIZE(bmp580_oversampling_avail),
.oversampling_press_default = ilog2(4),
.sampling_freq_avail = bmp580_odr_table,
.num_sampling_freq_avail = ARRAY_SIZE(bmp580_odr_table) * 2,
.sampling_freq_default = BMP580_ODR_50HZ,
.iir_filter_coeffs_avail = bmp380_iir_filter_coeffs_avail,
.num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp380_iir_filter_coeffs_avail),
.iir_filter_coeff_default = 2,
.chip_config = bmp580_chip_config,
.read_temp = bmp580_read_temp,
.read_press = bmp580_read_press,
.preinit = bmp580_preinit,
};
EXPORT_SYMBOL_NS(bmp580_chip_info, IIO_BMP280);
static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas)
{
@ -1467,7 +1872,7 @@ static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp)
return (data->t_fine + 8) >> 4;
}
static int bmp180_read_temp(struct bmp280_data *data, int *val)
static int bmp180_read_temp(struct bmp280_data *data, int *val, int *val2)
{
s32 adc_temp, comp_temp;
int ret;
@ -1555,7 +1960,7 @@ static int bmp180_read_press(struct bmp280_data *data,
int ret;
/* Read and compensate temperature so we get a reading of t_fine. */
ret = bmp180_read_temp(data, NULL);
ret = bmp180_read_temp(data, NULL, NULL);
if (ret)
return ret;
@ -1579,8 +1984,10 @@ static int bmp180_chip_config(struct bmp280_data *data)
static const int bmp180_oversampling_temp_avail[] = { 1 };
static const int bmp180_oversampling_press_avail[] = { 1, 2, 4, 8 };
static const struct bmp280_chip_info bmp180_chip_info = {
const struct bmp280_chip_info bmp180_chip_info = {
.id_reg = BMP280_REG_ID,
.chip_id = BMP180_CHIP_ID,
.regmap_config = &bmp180_regmap_config,
.start_up_time = 2000,
.channels = bmp280_channels,
.num_channels = 2,
@ -1600,6 +2007,7 @@ static const struct bmp280_chip_info bmp180_chip_info = {
.read_press = bmp180_read_press,
.read_calib = bmp180_read_calib,
};
EXPORT_SYMBOL_NS(bmp180_chip_info, IIO_BMP280);
static irqreturn_t bmp085_eoc_irq(int irq, void *d)
{
@ -1661,11 +2069,10 @@ static void bmp280_regulators_disable(void *data)
int bmp280_common_probe(struct device *dev,
struct regmap *regmap,
unsigned int chip,
const struct bmp280_chip_info *chip_info,
const char *name,
int irq)
{
const struct bmp280_chip_info *chip_info;
struct iio_dev *indio_dev;
struct bmp280_data *data;
struct gpio_desc *gpiod;
@ -1684,22 +2091,6 @@ int bmp280_common_probe(struct device *dev,
indio_dev->info = &bmp280_info;
indio_dev->modes = INDIO_DIRECT_MODE;
switch (chip) {
case BMP180_CHIP_ID:
chip_info = &bmp180_chip_info;
break;
case BMP280_CHIP_ID:
chip_info = &bmp280_chip_info;
break;
case BME280_CHIP_ID:
chip_info = &bme280_chip_info;
break;
case BMP380_CHIP_ID:
chip_info = &bmp380_chip_info;
break;
default:
return -EINVAL;
}
data->chip_info = chip_info;
/* Apply initial values from chip info structure */
@ -1751,17 +2142,17 @@ int bmp280_common_probe(struct device *dev,
ret = regmap_read(regmap, data->chip_info->id_reg, &chip_id);
if (ret < 0)
return ret;
if (chip_id != chip) {
if (chip_id != data->chip_info->chip_id) {
dev_err(dev, "bad chip id: expected %x got %x\n",
chip, chip_id);
data->chip_info->chip_id, chip_id);
return -EINVAL;
}
/* BMP3xx requires soft-reset as part of initialization */
if (chip_id == BMP380_CHIP_ID) {
ret = bmp380_cmd(data, BMP380_CMD_SOFT_RESET);
if (ret < 0)
return ret;
if (data->chip_info->preinit) {
ret = data->chip_info->preinit(data);
if (ret)
return dev_err_probe(data->dev, ret,
"error running preinit tasks\n");
}
ret = data->chip_info->chip_config(data);
@ -1776,10 +2167,12 @@ int bmp280_common_probe(struct device *dev,
* time once. They will not change.
*/
ret = data->chip_info->read_calib(data);
if (ret < 0)
return dev_err_probe(data->dev, ret,
"failed to read calibration coefficients\n");
if (data->chip_info->read_calib) {
ret = data->chip_info->read_calib(data);
if (ret < 0)
return dev_err_probe(data->dev, ret,
"failed to read calibration coefficients\n");
}
/*
* Attempt to grab an optional EOC IRQ - only the BMP085 has this

View File

@ -8,25 +8,14 @@
static int bmp280_i2c_probe(struct i2c_client *client)
{
struct regmap *regmap;
const struct regmap_config *regmap_config;
const struct bmp280_chip_info *chip_info;
const struct i2c_device_id *id = i2c_client_get_device_id(client);
switch (id->driver_data) {
case BMP180_CHIP_ID:
regmap_config = &bmp180_regmap_config;
break;
case BMP280_CHIP_ID:
case BME280_CHIP_ID:
regmap_config = &bmp280_regmap_config;
break;
case BMP380_CHIP_ID:
regmap_config = &bmp380_regmap_config;
break;
default:
return -EINVAL;
}
chip_info = device_get_match_data(&client->dev);
if (!chip_info)
chip_info = (const struct bmp280_chip_info *) id->driver_data;
regmap = devm_regmap_init_i2c(client, regmap_config);
regmap = devm_regmap_init_i2c(client, chip_info->regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "failed to allocate register map\n");
return PTR_ERR(regmap);
@ -34,27 +23,29 @@ static int bmp280_i2c_probe(struct i2c_client *client)
return bmp280_common_probe(&client->dev,
regmap,
id->driver_data,
chip_info,
id->name,
client->irq);
}
static const struct of_device_id bmp280_of_i2c_match[] = {
{ .compatible = "bosch,bmp085", .data = (void *)BMP180_CHIP_ID },
{ .compatible = "bosch,bmp180", .data = (void *)BMP180_CHIP_ID },
{ .compatible = "bosch,bmp280", .data = (void *)BMP280_CHIP_ID },
{ .compatible = "bosch,bme280", .data = (void *)BME280_CHIP_ID },
{ .compatible = "bosch,bmp380", .data = (void *)BMP380_CHIP_ID },
{ .compatible = "bosch,bmp085", .data = &bmp180_chip_info },
{ .compatible = "bosch,bmp180", .data = &bmp180_chip_info },
{ .compatible = "bosch,bmp280", .data = &bmp280_chip_info },
{ .compatible = "bosch,bme280", .data = &bme280_chip_info },
{ .compatible = "bosch,bmp380", .data = &bmp380_chip_info },
{ .compatible = "bosch,bmp580", .data = &bmp580_chip_info },
{ },
};
MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match);
static const struct i2c_device_id bmp280_i2c_id[] = {
{"bmp085", BMP180_CHIP_ID },
{"bmp180", BMP180_CHIP_ID },
{"bmp280", BMP280_CHIP_ID },
{"bme280", BME280_CHIP_ID },
{"bmp380", BMP380_CHIP_ID },
{"bmp085", (kernel_ulong_t)&bmp180_chip_info },
{"bmp180", (kernel_ulong_t)&bmp180_chip_info },
{"bmp280", (kernel_ulong_t)&bmp280_chip_info },
{"bme280", (kernel_ulong_t)&bme280_chip_info },
{"bmp380", (kernel_ulong_t)&bmp380_chip_info },
{"bmp580", (kernel_ulong_t)&bmp580_chip_info },
{ },
};
MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id);

View File

@ -115,6 +115,54 @@ static bool bmp380_is_volatile_reg(struct device *dev, unsigned int reg)
}
}
static bool bmp580_is_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMP580_REG_NVM_DATA_MSB:
case BMP580_REG_NVM_DATA_LSB:
case BMP580_REG_NVM_ADDR:
case BMP580_REG_ODR_CONFIG:
case BMP580_REG_OSR_CONFIG:
case BMP580_REG_INT_SOURCE:
case BMP580_REG_INT_CONFIG:
case BMP580_REG_OOR_THR_MSB:
case BMP580_REG_OOR_THR_LSB:
case BMP580_REG_OOR_CONFIG:
case BMP580_REG_OOR_RANGE:
case BMP580_REG_IF_CONFIG:
case BMP580_REG_FIFO_CONFIG:
case BMP580_REG_FIFO_SEL:
case BMP580_REG_DSP_CONFIG:
case BMP580_REG_DSP_IIR:
case BMP580_REG_CMD:
return true;
default:
return false;
}
}
static bool bmp580_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMP580_REG_NVM_DATA_MSB:
case BMP580_REG_NVM_DATA_LSB:
case BMP580_REG_FIFO_COUNT:
case BMP580_REG_INT_STATUS:
case BMP580_REG_PRESS_XLSB:
case BMP580_REG_PRESS_LSB:
case BMP580_REG_PRESS_MSB:
case BMP580_REG_FIFO_DATA:
case BMP580_REG_TEMP_XLSB:
case BMP580_REG_TEMP_LSB:
case BMP580_REG_TEMP_MSB:
case BMP580_REG_EFF_OSR:
case BMP580_REG_STATUS:
return true;
default:
return false;
}
}
const struct regmap_config bmp280_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@ -138,3 +186,15 @@ const struct regmap_config bmp380_regmap_config = {
.volatile_reg = bmp380_is_volatile_reg,
};
EXPORT_SYMBOL_NS(bmp380_regmap_config, IIO_BMP280);
const struct regmap_config bmp580_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = BMP580_REG_CMD,
.cache_type = REGCACHE_RBTREE,
.writeable_reg = bmp580_is_writeable_reg,
.volatile_reg = bmp580_is_volatile_reg,
};
EXPORT_SYMBOL_NS(bmp580_regmap_config, IIO_BMP280);

View File

@ -47,8 +47,8 @@ static struct regmap_bus bmp280_regmap_bus = {
static int bmp280_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
const struct bmp280_chip_info *chip_info;
struct regmap *regmap;
const struct regmap_config *regmap_config;
int ret;
spi->bits_per_word = 8;
@ -58,25 +58,14 @@ static int bmp280_spi_probe(struct spi_device *spi)
return ret;
}
switch (id->driver_data) {
case BMP180_CHIP_ID:
regmap_config = &bmp180_regmap_config;
break;
case BMP280_CHIP_ID:
case BME280_CHIP_ID:
regmap_config = &bmp280_regmap_config;
break;
case BMP380_CHIP_ID:
regmap_config = &bmp380_regmap_config;
break;
default:
return -EINVAL;
}
chip_info = device_get_match_data(&spi->dev);
if (!chip_info)
chip_info = (const struct bmp280_chip_info *) id->driver_data;
regmap = devm_regmap_init(&spi->dev,
&bmp280_regmap_bus,
&spi->dev,
regmap_config);
chip_info->regmap_config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "failed to allocate register map\n");
return PTR_ERR(regmap);
@ -84,28 +73,30 @@ static int bmp280_spi_probe(struct spi_device *spi)
return bmp280_common_probe(&spi->dev,
regmap,
id->driver_data,
chip_info,
id->name,
spi->irq);
}
static const struct of_device_id bmp280_of_spi_match[] = {
{ .compatible = "bosch,bmp085", },
{ .compatible = "bosch,bmp180", },
{ .compatible = "bosch,bmp181", },
{ .compatible = "bosch,bmp280", },
{ .compatible = "bosch,bme280", },
{ .compatible = "bosch,bmp380", },
{ .compatible = "bosch,bmp085", .data = &bmp180_chip_info },
{ .compatible = "bosch,bmp180", .data = &bmp180_chip_info },
{ .compatible = "bosch,bmp181", .data = &bmp180_chip_info },
{ .compatible = "bosch,bmp280", .data = &bmp280_chip_info },
{ .compatible = "bosch,bme280", .data = &bmp280_chip_info },
{ .compatible = "bosch,bmp380", .data = &bmp380_chip_info },
{ .compatible = "bosch,bmp580", .data = &bmp580_chip_info },
{ },
};
MODULE_DEVICE_TABLE(of, bmp280_of_spi_match);
static const struct spi_device_id bmp280_spi_id[] = {
{ "bmp180", BMP180_CHIP_ID },
{ "bmp181", BMP180_CHIP_ID },
{ "bmp280", BMP280_CHIP_ID },
{ "bme280", BME280_CHIP_ID },
{ "bmp380", BMP380_CHIP_ID },
{ "bmp180", (kernel_ulong_t)&bmp180_chip_info },
{ "bmp181", (kernel_ulong_t)&bmp180_chip_info },
{ "bmp280", (kernel_ulong_t)&bmp280_chip_info },
{ "bme280", (kernel_ulong_t)&bmp280_chip_info },
{ "bmp380", (kernel_ulong_t)&bmp380_chip_info },
{ "bmp580", (kernel_ulong_t)&bmp580_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, bmp280_spi_id);

View File

@ -1,7 +1,114 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/iio/iio.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
/* BMP580 specific registers */
#define BMP580_REG_CMD 0x7E
#define BMP580_REG_EFF_OSR 0x38
#define BMP580_REG_ODR_CONFIG 0x37
#define BMP580_REG_OSR_CONFIG 0x36
#define BMP580_REG_IF_CONFIG 0x13
#define BMP580_REG_REV_ID 0x02
#define BMP580_REG_CHIP_ID 0x01
/* OOR allows to configure a pressure alarm */
#define BMP580_REG_OOR_CONFIG 0x35
#define BMP580_REG_OOR_RANGE 0x34
#define BMP580_REG_OOR_THR_MSB 0x33
#define BMP580_REG_OOR_THR_LSB 0x32
/* DSP registers (IIR filters) */
#define BMP580_REG_DSP_IIR 0x31
#define BMP580_REG_DSP_CONFIG 0x30
/* NVM access registers */
#define BMP580_REG_NVM_DATA_MSB 0x2D
#define BMP580_REG_NVM_DATA_LSB 0x2C
#define BMP580_REG_NVM_ADDR 0x2B
/* Status registers */
#define BMP580_REG_STATUS 0x28
#define BMP580_REG_INT_STATUS 0x27
#define BMP580_REG_CHIP_STATUS 0x11
/* Data registers */
#define BMP580_REG_FIFO_DATA 0x29
#define BMP580_REG_PRESS_MSB 0x22
#define BMP580_REG_PRESS_LSB 0x21
#define BMP580_REG_PRESS_XLSB 0x20
#define BMP580_REG_TEMP_MSB 0x1F
#define BMP580_REG_TEMP_LSB 0x1E
#define BMP580_REG_TEMP_XLSB 0x1D
/* FIFO config registers */
#define BMP580_REG_FIFO_SEL 0x18
#define BMP580_REG_FIFO_COUNT 0x17
#define BMP580_REG_FIFO_CONFIG 0x16
/* Interruptions config registers */
#define BMP580_REG_INT_SOURCE 0x15
#define BMP580_REG_INT_CONFIG 0x14
#define BMP580_CMD_NOOP 0x00
#define BMP580_CMD_EXTMODE_SEQ_0 0x73
#define BMP580_CMD_EXTMODE_SEQ_1 0xB4
#define BMP580_CMD_EXTMODE_SEQ_2 0x69
#define BMP580_CMD_NVM_OP_SEQ_0 0x5D
#define BMP580_CMD_NVM_READ_SEQ_1 0xA5
#define BMP580_CMD_NVM_WRITE_SEQ_1 0xA0
#define BMP580_CMD_SOFT_RESET 0xB6
#define BMP580_INT_STATUS_POR_MASK BIT(4)
#define BMP580_STATUS_CORE_RDY_MASK BIT(0)
#define BMP580_STATUS_NVM_RDY_MASK BIT(1)
#define BMP580_STATUS_NVM_ERR_MASK BIT(2)
#define BMP580_STATUS_NVM_CMD_ERR_MASK BIT(3)
#define BMP580_OSR_PRESS_MASK GENMASK(5, 3)
#define BMP580_OSR_TEMP_MASK GENMASK(2, 0)
#define BMP580_OSR_PRESS_EN BIT(6)
#define BMP580_EFF_OSR_PRESS_MASK GENMASK(5, 3)
#define BMP580_EFF_OSR_TEMP_MASK GENMASK(2, 0)
#define BMP580_EFF_OSR_VALID_ODR BIT(7)
#define BMP580_ODR_MASK GENMASK(6, 2)
#define BMP580_MODE_MASK GENMASK(1, 0)
#define BMP580_MODE_SLEEP 0
#define BMP580_MODE_NORMAL 1
#define BMP580_MODE_FORCED 2
#define BMP580_MODE_CONTINOUS 3
#define BMP580_ODR_DEEPSLEEP_DIS BIT(7)
#define BMP580_DSP_COMP_MASK GENMASK(1, 0)
#define BMP580_DSP_COMP_DIS 0
#define BMP580_DSP_TEMP_COMP_EN 1
/*
* In section 7.27 of datasheet, modes 2 and 3 are technically the same.
* Pressure compensation means also enabling temperature compensation
*/
#define BMP580_DSP_PRESS_COMP_EN 2
#define BMP580_DSP_PRESS_TEMP_COMP_EN 3
#define BMP580_DSP_IIR_FORCED_FLUSH BIT(2)
#define BMP580_DSP_SHDW_IIR_TEMP_EN BIT(3)
#define BMP580_DSP_FIFO_IIR_TEMP_EN BIT(4)
#define BMP580_DSP_SHDW_IIR_PRESS_EN BIT(5)
#define BMP580_DSP_FIFO_IIR_PRESS_EN BIT(6)
#define BMP580_DSP_OOR_IIR_PRESS_EN BIT(7)
#define BMP580_DSP_IIR_PRESS_MASK GENMASK(5, 3)
#define BMP580_DSP_IIR_TEMP_MASK GENMASK(2, 0)
#define BMP580_FILTER_OFF 0
#define BMP580_FILTER_1X 1
#define BMP580_FILTER_3X 2
#define BMP580_FILTER_7X 3
#define BMP580_FILTER_15X 4
#define BMP580_FILTER_31X 5
#define BMP580_FILTER_63X 6
#define BMP580_FILTER_127X 7
#define BMP580_NVM_ROW_ADDR_MASK GENMASK(5, 0)
#define BMP580_NVM_PROG_EN BIT(6)
#define BMP580_TEMP_SKIPPED 0x7f7f7f
#define BMP580_PRESS_SKIPPED 0x7f7f7f
/* BMP380 specific registers */
#define BMP380_REG_CMD 0x7E
@ -181,6 +288,8 @@
#define BMP280_REG_ID 0xD0
#define BMP380_CHIP_ID 0x50
#define BMP580_CHIP_ID 0x50
#define BMP580_CHIP_ID_ALT 0x51
#define BMP180_CHIP_ID 0x55
#define BMP280_CHIP_ID 0x58
#define BME280_CHIP_ID 0x60
@ -191,15 +300,177 @@
#define BMP280_PRESS_SKIPPED 0x80000
#define BMP280_HUMIDITY_SKIPPED 0x8000
/* Core exported structs */
static const char *const bmp280_supply_names[] = {
"vddd", "vdda"
};
#define BMP280_NUM_SUPPLIES ARRAY_SIZE(bmp280_supply_names)
struct bmp180_calib {
s16 AC1;
s16 AC2;
s16 AC3;
u16 AC4;
u16 AC5;
u16 AC6;
s16 B1;
s16 B2;
s16 MB;
s16 MC;
s16 MD;
};
/* See datasheet Section 4.2.2. */
struct bmp280_calib {
u16 T1;
s16 T2;
s16 T3;
u16 P1;
s16 P2;
s16 P3;
s16 P4;
s16 P5;
s16 P6;
s16 P7;
s16 P8;
s16 P9;
u8 H1;
s16 H2;
u8 H3;
s16 H4;
s16 H5;
s8 H6;
};
/* See datasheet Section 3.11.1. */
struct bmp380_calib {
u16 T1;
u16 T2;
s8 T3;
s16 P1;
s16 P2;
s8 P3;
s8 P4;
u16 P5;
u16 P6;
s8 P7;
s8 P8;
s16 P9;
s8 P10;
s8 P11;
};
struct bmp280_data {
struct device *dev;
struct mutex lock;
struct regmap *regmap;
struct completion done;
bool use_eoc;
const struct bmp280_chip_info *chip_info;
union {
struct bmp180_calib bmp180;
struct bmp280_calib bmp280;
struct bmp380_calib bmp380;
} calib;
struct regulator_bulk_data supplies[BMP280_NUM_SUPPLIES];
unsigned int start_up_time; /* in microseconds */
/* log of base 2 of oversampling rate */
u8 oversampling_press;
u8 oversampling_temp;
u8 oversampling_humid;
u8 iir_filter_coeff;
/*
* BMP380 devices introduce sampling frequency configuration. See
* datasheet sections 3.3.3. and 4.3.19 for more details.
*
* BMx280 devices allowed indirect configuration of sampling frequency
* changing the t_standby duration between measurements, as detailed on
* section 3.6.3 of the datasheet.
*/
int sampling_freq;
/*
* Carryover value from temperature conversion, used in pressure
* calculation.
*/
s32 t_fine;
/*
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
*/
union {
/* Sensor data buffer */
u8 buf[3];
/* Calibration data buffers */
__le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS / 2];
__be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT / 2];
u8 bmp380_cal_buf[BMP380_CALIB_REG_COUNT];
/* Miscellaneous, endianess-aware data buffers */
__le16 le16;
__be16 be16;
} __aligned(IIO_DMA_MINALIGN);
};
struct bmp280_chip_info {
unsigned int id_reg;
const unsigned int chip_id;
const struct regmap_config *regmap_config;
const struct iio_chan_spec *channels;
int num_channels;
unsigned int start_up_time;
const int *oversampling_temp_avail;
int num_oversampling_temp_avail;
int oversampling_temp_default;
const int *oversampling_press_avail;
int num_oversampling_press_avail;
int oversampling_press_default;
const int *oversampling_humid_avail;
int num_oversampling_humid_avail;
int oversampling_humid_default;
const int *iir_filter_coeffs_avail;
int num_iir_filter_coeffs_avail;
int iir_filter_coeff_default;
const int (*sampling_freq_avail)[2];
int num_sampling_freq_avail;
int sampling_freq_default;
int (*chip_config)(struct bmp280_data *);
int (*read_temp)(struct bmp280_data *, int *, int *);
int (*read_press)(struct bmp280_data *, int *, int *);
int (*read_humid)(struct bmp280_data *, int *, int *);
int (*read_calib)(struct bmp280_data *);
int (*preinit)(struct bmp280_data *);
};
/* Chip infos for each variant */
extern const struct bmp280_chip_info bmp180_chip_info;
extern const struct bmp280_chip_info bmp280_chip_info;
extern const struct bmp280_chip_info bme280_chip_info;
extern const struct bmp280_chip_info bmp380_chip_info;
extern const struct bmp280_chip_info bmp580_chip_info;
/* Regmap configurations */
extern const struct regmap_config bmp180_regmap_config;
extern const struct regmap_config bmp280_regmap_config;
extern const struct regmap_config bmp380_regmap_config;
extern const struct regmap_config bmp580_regmap_config;
/* Probe called from different transports */
int bmp280_common_probe(struct device *dev,
struct regmap *regmap,
unsigned int chip,
const struct bmp280_chip_info *,
const char *name,
int irq);

View File

@ -829,7 +829,7 @@ static irqreturn_t zpa2326_handle_threaded_irq(int irq, void *data)
}
/* New sample available: dispatch internal trigger consumers. */
iio_trigger_poll_chained(priv->trigger);
iio_trigger_poll_nested(priv->trigger);
if (cont)
/*

View File

@ -257,7 +257,7 @@ static void as3935_event_work(struct work_struct *work)
switch (val) {
case AS3935_EVENT_INT:
iio_trigger_poll_chained(st->trig);
iio_trigger_poll_nested(st->trig);
break;
case AS3935_DISTURB_INT:
case AS3935_NOISE_INT:

View File

@ -783,73 +783,75 @@ static int sx9324_write_raw(struct iio_dev *indio_dev,
static const struct sx_common_reg_default sx9324_default_regs[] = {
{ SX9324_REG_IRQ_MSK, 0x00 },
{ SX9324_REG_IRQ_CFG0, 0x00 },
{ SX9324_REG_IRQ_CFG1, SX9324_REG_IRQ_CFG1_FAILCOND },
{ SX9324_REG_IRQ_CFG2, 0x00 },
{ SX9324_REG_GNRL_CTRL0, SX9324_REG_GNRL_CTRL0_SCANPERIOD_100MS },
{ SX9324_REG_IRQ_CFG0, 0x00, "irq_cfg0" },
{ SX9324_REG_IRQ_CFG1, SX9324_REG_IRQ_CFG1_FAILCOND, "irq_cfg1" },
{ SX9324_REG_IRQ_CFG2, 0x00, "irq_cfg2" },
{ SX9324_REG_GNRL_CTRL0, SX9324_REG_GNRL_CTRL0_SCANPERIOD_100MS, "gnrl_ctrl0" },
/*
* The lower 4 bits should not be set as it enable sensors measurements.
* Turning the detection on before the configuration values are set to
* good values can cause the device to return erroneous readings.
*/
{ SX9324_REG_GNRL_CTRL1, SX9324_REG_GNRL_CTRL1_PAUSECTRL },
{ SX9324_REG_GNRL_CTRL1, SX9324_REG_GNRL_CTRL1_PAUSECTRL, "gnrl_ctrl1" },
{ SX9324_REG_AFE_CTRL0, SX9324_REG_AFE_CTRL0_RINT_LOWEST },
{ SX9324_REG_AFE_CTRL3, 0x00 },
{ SX9324_REG_AFE_CTRL0, SX9324_REG_AFE_CTRL0_RINT_LOWEST, "afe_ctrl0" },
{ SX9324_REG_AFE_CTRL3, 0x00, "afe_ctrl3" },
{ SX9324_REG_AFE_CTRL4, SX9324_REG_AFE_CTRL4_FREQ_83_33HZ |
SX9324_REG_AFE_CTRL4_RES_100 },
{ SX9324_REG_AFE_CTRL6, 0x00 },
SX9324_REG_AFE_CTRL4_RES_100, "afe_ctrl4" },
{ SX9324_REG_AFE_CTRL6, 0x00, "afe_ctrl6" },
{ SX9324_REG_AFE_CTRL7, SX9324_REG_AFE_CTRL4_FREQ_83_33HZ |
SX9324_REG_AFE_CTRL4_RES_100 },
SX9324_REG_AFE_CTRL4_RES_100, "afe_ctrl7" },
/* TODO(gwendal): PHx use chip default or all grounded? */
{ SX9324_REG_AFE_PH0, 0x29 },
{ SX9324_REG_AFE_PH1, 0x26 },
{ SX9324_REG_AFE_PH2, 0x1a },
{ SX9324_REG_AFE_PH3, 0x16 },
{ SX9324_REG_AFE_PH0, 0x29, "afe_ph0" },
{ SX9324_REG_AFE_PH1, 0x26, "afe_ph1" },
{ SX9324_REG_AFE_PH2, 0x1a, "afe_ph2" },
{ SX9324_REG_AFE_PH3, 0x16, "afe_ph3" },
{ SX9324_REG_AFE_CTRL8, SX9324_REG_AFE_CTRL8_RESERVED |
SX9324_REG_AFE_CTRL8_RESFILTIN_4KOHM },
{ SX9324_REG_AFE_CTRL9, SX9324_REG_AFE_CTRL9_AGAIN_1 },
SX9324_REG_AFE_CTRL8_RESFILTIN_4KOHM, "afe_ctrl8" },
{ SX9324_REG_AFE_CTRL9, SX9324_REG_AFE_CTRL9_AGAIN_1, "afe_ctrl9" },
{ SX9324_REG_PROX_CTRL0,
SX9324_REG_PROX_CTRL0_GAIN_1 << SX9324_REG_PROX_CTRL0_GAIN_SHIFT |
SX9324_REG_PROX_CTRL0_RAWFILT_1P50 },
SX9324_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl0" },
{ SX9324_REG_PROX_CTRL1,
SX9324_REG_PROX_CTRL0_GAIN_1 << SX9324_REG_PROX_CTRL0_GAIN_SHIFT |
SX9324_REG_PROX_CTRL0_RAWFILT_1P50 },
{ SX9324_REG_PROX_CTRL2, SX9324_REG_PROX_CTRL2_AVGNEG_THRESH_16K },
SX9324_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl1" },
{ SX9324_REG_PROX_CTRL2, SX9324_REG_PROX_CTRL2_AVGNEG_THRESH_16K, "prox_ctrl2" },
{ SX9324_REG_PROX_CTRL3, SX9324_REG_PROX_CTRL3_AVGDEB_2SAMPLES |
SX9324_REG_PROX_CTRL3_AVGPOS_THRESH_16K },
SX9324_REG_PROX_CTRL3_AVGPOS_THRESH_16K, "prox_ctrl3" },
{ SX9324_REG_PROX_CTRL4, SX9324_REG_PROX_CTRL4_AVGNEG_FILT_2 |
SX9324_REG_PROX_CTRL4_AVGPOS_FILT_256 },
{ SX9324_REG_PROX_CTRL5, 0x00 },
{ SX9324_REG_PROX_CTRL6, SX9324_REG_PROX_CTRL6_PROXTHRESH_32 },
{ SX9324_REG_PROX_CTRL7, SX9324_REG_PROX_CTRL6_PROXTHRESH_32 },
{ SX9324_REG_ADV_CTRL0, 0x00 },
{ SX9324_REG_ADV_CTRL1, 0x00 },
{ SX9324_REG_ADV_CTRL2, 0x00 },
{ SX9324_REG_ADV_CTRL3, 0x00 },
{ SX9324_REG_ADV_CTRL4, 0x00 },
SX9324_REG_PROX_CTRL4_AVGPOS_FILT_256, "prox_ctrl4" },
{ SX9324_REG_PROX_CTRL5, 0x00, "prox_ctrl5" },
{ SX9324_REG_PROX_CTRL6, SX9324_REG_PROX_CTRL6_PROXTHRESH_32, "prox_ctrl6" },
{ SX9324_REG_PROX_CTRL7, SX9324_REG_PROX_CTRL6_PROXTHRESH_32, "prox_ctrl7" },
{ SX9324_REG_ADV_CTRL0, 0x00, "adv_ctrl0" },
{ SX9324_REG_ADV_CTRL1, 0x00, "adv_ctrl1" },
{ SX9324_REG_ADV_CTRL2, 0x00, "adv_ctrl2" },
{ SX9324_REG_ADV_CTRL3, 0x00, "adv_ctrl3" },
{ SX9324_REG_ADV_CTRL4, 0x00, "adv_ctrl4" },
{ SX9324_REG_ADV_CTRL5, SX9324_REG_ADV_CTRL5_STARTUP_SENSOR_1 |
SX9324_REG_ADV_CTRL5_STARTUP_METHOD_1 },
{ SX9324_REG_ADV_CTRL6, 0x00 },
{ SX9324_REG_ADV_CTRL7, 0x00 },
{ SX9324_REG_ADV_CTRL8, 0x00 },
{ SX9324_REG_ADV_CTRL9, 0x00 },
SX9324_REG_ADV_CTRL5_STARTUP_METHOD_1, "adv_ctrl5" },
{ SX9324_REG_ADV_CTRL6, 0x00, "adv_ctrl6" },
{ SX9324_REG_ADV_CTRL7, 0x00, "adv_ctrl7" },
{ SX9324_REG_ADV_CTRL8, 0x00, "adv_ctrl8" },
{ SX9324_REG_ADV_CTRL9, 0x00, "adv_ctrl9" },
/* Body/Table threshold */
{ SX9324_REG_ADV_CTRL10, 0x00 },
{ SX9324_REG_ADV_CTRL11, 0x00 },
{ SX9324_REG_ADV_CTRL12, 0x00 },
{ SX9324_REG_ADV_CTRL10, 0x00, "adv_ctrl10" },
{ SX9324_REG_ADV_CTRL11, 0x00, "adv_ctrl11" },
{ SX9324_REG_ADV_CTRL12, 0x00, "adv_ctrl12" },
/* TODO(gwendal): SAR currenly disabled */
{ SX9324_REG_ADV_CTRL13, 0x00 },
{ SX9324_REG_ADV_CTRL14, 0x00 },
{ SX9324_REG_ADV_CTRL15, 0x00 },
{ SX9324_REG_ADV_CTRL16, 0x00 },
{ SX9324_REG_ADV_CTRL17, 0x00 },
{ SX9324_REG_ADV_CTRL18, 0x00 },
{ SX9324_REG_ADV_CTRL19, SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION },
{ SX9324_REG_ADV_CTRL20, SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION },
{ SX9324_REG_ADV_CTRL13, 0x00, "adv_ctrl13" },
{ SX9324_REG_ADV_CTRL14, 0x00, "adv_ctrl14" },
{ SX9324_REG_ADV_CTRL15, 0x00, "adv_ctrl15" },
{ SX9324_REG_ADV_CTRL16, 0x00, "adv_ctrl16" },
{ SX9324_REG_ADV_CTRL17, 0x00, "adv_ctrl17" },
{ SX9324_REG_ADV_CTRL18, 0x00, "adv_ctrl18" },
{ SX9324_REG_ADV_CTRL19,
SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION, "adv_ctrl19" },
{ SX9324_REG_ADV_CTRL20,
SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION, "adv_ctrl20" },
};
/* Activate all channels and perform an initial compensation. */
@ -889,13 +891,15 @@ sx9324_get_default_reg(struct device *dev, int idx,
const char *res;
memcpy(reg_def, &sx9324_default_regs[idx], sizeof(*reg_def));
sx_common_get_raw_register_config(dev, reg_def);
switch (reg_def->reg) {
case SX9324_REG_AFE_PH0:
case SX9324_REG_AFE_PH1:
case SX9324_REG_AFE_PH2:
case SX9324_REG_AFE_PH3:
ph = reg_def->reg - SX9324_REG_AFE_PH0;
scnprintf(prop, ARRAY_SIZE(prop), "semtech,ph%d-pin", ph);
snprintf(prop, ARRAY_SIZE(prop), "semtech,ph%d-pin", ph);
count = device_property_count_u32(dev, prop);
if (count != ARRAY_SIZE(pin_defs))

View File

@ -663,37 +663,37 @@ static int sx9360_write_raw(struct iio_dev *indio_dev,
static const struct sx_common_reg_default sx9360_default_regs[] = {
{ SX9360_REG_IRQ_MSK, 0x00 },
{ SX9360_REG_IRQ_CFG, 0x00 },
{ SX9360_REG_IRQ_CFG, 0x00, "irq_cfg" },
/*
* The lower 2 bits should not be set as it enable sensors measurements.
* Turning the detection on before the configuration values are set to
* good values can cause the device to return erroneous readings.
*/
{ SX9360_REG_GNRL_CTRL0, 0x00 },
{ SX9360_REG_GNRL_CTRL1, 0x00 },
{ SX9360_REG_GNRL_CTRL2, SX9360_REG_GNRL_CTRL2_PERIOD_102MS },
{ SX9360_REG_GNRL_CTRL0, 0x00, "gnrl_ctrl0" },
{ SX9360_REG_GNRL_CTRL1, 0x00, "gnrl_ctrl1" },
{ SX9360_REG_GNRL_CTRL2, SX9360_REG_GNRL_CTRL2_PERIOD_102MS, "gnrl_ctrl2" },
{ SX9360_REG_AFE_CTRL1, SX9360_REG_AFE_CTRL1_RESFILTIN_0OHMS },
{ SX9360_REG_AFE_CTRL1, SX9360_REG_AFE_CTRL1_RESFILTIN_0OHMS, "afe_ctrl0" },
{ SX9360_REG_AFE_PARAM0_PHR, SX9360_REG_AFE_PARAM0_RSVD |
SX9360_REG_AFE_PARAM0_RESOLUTION_128 },
SX9360_REG_AFE_PARAM0_RESOLUTION_128, "afe_param0_phr" },
{ SX9360_REG_AFE_PARAM1_PHR, SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF |
SX9360_REG_AFE_PARAM1_FREQ_83_33HZ },
SX9360_REG_AFE_PARAM1_FREQ_83_33HZ, "afe_param1_phr" },
{ SX9360_REG_AFE_PARAM0_PHM, SX9360_REG_AFE_PARAM0_RSVD |
SX9360_REG_AFE_PARAM0_RESOLUTION_128 },
SX9360_REG_AFE_PARAM0_RESOLUTION_128, "afe_param0_phm" },
{ SX9360_REG_AFE_PARAM1_PHM, SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF |
SX9360_REG_AFE_PARAM1_FREQ_83_33HZ },
SX9360_REG_AFE_PARAM1_FREQ_83_33HZ, "afe_param1_phm" },
{ SX9360_REG_PROX_CTRL0_PHR, SX9360_REG_PROX_CTRL0_GAIN_1 |
SX9360_REG_PROX_CTRL0_RAWFILT_1P50 },
SX9360_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl0_phr" },
{ SX9360_REG_PROX_CTRL0_PHM, SX9360_REG_PROX_CTRL0_GAIN_1 |
SX9360_REG_PROX_CTRL0_RAWFILT_1P50 },
{ SX9360_REG_PROX_CTRL1, SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_16K },
SX9360_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl0_phm" },
{ SX9360_REG_PROX_CTRL1, SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_16K, "prox_ctrl1" },
{ SX9360_REG_PROX_CTRL2, SX9360_REG_PROX_CTRL2_AVGDEB_2SAMPLES |
SX9360_REG_PROX_CTRL2_AVGPOS_THRESH_16K },
SX9360_REG_PROX_CTRL2_AVGPOS_THRESH_16K, "prox_ctrl2" },
{ SX9360_REG_PROX_CTRL3, SX9360_REG_PROX_CTRL3_AVGNEG_FILT_2 |
SX9360_REG_PROX_CTRL3_AVGPOS_FILT_256 },
{ SX9360_REG_PROX_CTRL4, 0x00 },
{ SX9360_REG_PROX_CTRL5, SX9360_REG_PROX_CTRL5_PROXTHRESH_32 },
SX9360_REG_PROX_CTRL3_AVGPOS_FILT_256, "prox_ctrl3" },
{ SX9360_REG_PROX_CTRL4, 0x00, "prox_ctrl4" },
{ SX9360_REG_PROX_CTRL5, SX9360_REG_PROX_CTRL5_PROXTHRESH_32, "prox_ctrl5" },
};
/* Activate all channels and perform an initial compensation. */

View File

@ -1051,8 +1051,8 @@ MODULE_DEVICE_TABLE(i2c, sx9500_id);
static struct i2c_driver sx9500_driver = {
.driver = {
.name = SX9500_DRIVER_NAME,
.acpi_match_table = ACPI_PTR(sx9500_acpi_match),
.of_match_table = of_match_ptr(sx9500_of_match),
.acpi_match_table = sx9500_acpi_match,
.of_match_table = sx9500_of_match,
.pm = pm_sleep_ptr(&sx9500_pm_ops),
},
.probe_new = sx9500_probe,

View File

@ -424,6 +424,27 @@ static const struct iio_buffer_setup_ops sx_common_buffer_setup_ops = {
.postdisable = sx_common_buffer_postdisable,
};
void sx_common_get_raw_register_config(struct device *dev,
struct sx_common_reg_default *reg_def)
{
#ifdef CONFIG_ACPI
struct acpi_device *adev = ACPI_COMPANION(dev);
u32 raw = 0, ret;
char prop[80];
if (!reg_def->property || !adev)
return;
snprintf(prop, ARRAY_SIZE(prop), "%s,reg_%s", acpi_device_hid(adev), reg_def->property);
ret = device_property_read_u32(dev, prop, &raw);
if (ret)
return;
reg_def->def = raw;
#endif
}
EXPORT_SYMBOL_NS_GPL(sx_common_get_raw_register_config, SEMTECH_PROX);
#define SX_COMMON_SOFT_RESET 0xde
static int sx_common_init_device(struct device *dev, struct iio_dev *indio_dev)

View File

@ -8,6 +8,7 @@
#ifndef IIO_SX_COMMON_H
#define IIO_SX_COMMON_H
#include <linux/acpi.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/regulator/consumer.h>
@ -26,6 +27,7 @@ static_assert(SX_COMMON_MAX_NUM_CHANNELS < BITS_PER_LONG);
struct sx_common_reg_default {
u8 reg;
u8 def;
const char *property;
};
/**
@ -101,7 +103,6 @@ struct sx_common_chip_info {
* @client: I2C client structure.
* @trig: IIO trigger object.
* @regmap: Register map.
* @num_default_regs: Number of default registers to set at init.
* @chan_prox_stat: Last reading of the proximity status for each channel.
* We only send an event to user space when this changes.
* @trigger_enabled: True when the device trigger is enabled.
@ -149,6 +150,9 @@ int sx_common_probe(struct i2c_client *client,
const struct sx_common_chip_info *chip_info,
const struct regmap_config *regmap_config);
void sx_common_get_raw_register_config(struct device *dev,
struct sx_common_reg_default *reg_def);
/* 3 is the number of events defined by a single phase. */
extern const struct iio_event_spec sx_common_events[3];

View File

@ -16,6 +16,7 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/property.h>
#include <linux/iio/iio.h>
@ -31,17 +32,19 @@
#define TMP117_REG_DEVICE_ID 0xF
#define TMP117_RESOLUTION_10UC 78125
#define TMP117_DEVICE_ID 0x0117
#define MICRODEGREE_PER_10MILLIDEGREE 10000
#define TMP116_DEVICE_ID 0x1116
#define TMP117_DEVICE_ID 0x0117
struct tmp117_data {
struct i2c_client *client;
s16 calibbias;
};
static int tmp117_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
struct tmp117_data *data = iio_priv(indio_dev);
s32 ret;
@ -49,7 +52,7 @@ static int tmp117_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = i2c_smbus_read_word_swapped(data->client,
TMP117_REG_TEMP);
TMP117_REG_TEMP);
if (ret < 0)
return ret;
*val = sign_extend32(ret, 15);
@ -57,7 +60,7 @@ static int tmp117_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS:
ret = i2c_smbus_read_word_swapped(data->client,
TMP117_REG_TEMP_OFFSET);
TMP117_REG_TEMP_OFFSET);
if (ret < 0)
return ret;
*val = sign_extend32(ret, 15);
@ -79,9 +82,8 @@ static int tmp117_read_raw(struct iio_dev *indio_dev,
}
}
static int tmp117_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int val,
int val2, long mask)
static int tmp117_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec
const *channel, int val, int val2, long mask)
{
struct tmp117_data *data = iio_priv(indio_dev);
s16 off;
@ -104,7 +106,16 @@ static const struct iio_chan_spec tmp117_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE),
BIT(IIO_CHAN_INFO_CALIBBIAS) |
BIT(IIO_CHAN_INFO_SCALE),
},
};
static const struct iio_chan_spec tmp116_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
},
};
@ -115,23 +126,41 @@ static const struct iio_info tmp117_info = {
static int tmp117_identify(struct i2c_client *client)
{
const struct i2c_device_id *id;
unsigned long match_data;
int dev_id;
dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID);
if (dev_id < 0)
return dev_id;
if (dev_id != TMP117_DEVICE_ID) {
dev_err(&client->dev, "TMP117 not found\n");
return -ENODEV;
switch (dev_id) {
case TMP116_DEVICE_ID:
case TMP117_DEVICE_ID:
return dev_id;
}
return 0;
dev_info(&client->dev, "Unknown device id (0x%x), use fallback compatible\n",
dev_id);
match_data = (uintptr_t)device_get_match_data(&client->dev);
if (match_data)
return match_data;
id = i2c_client_get_device_id(client);
if (id)
return id->driver_data;
dev_err(&client->dev, "Failed to identify unsupported device\n");
return -ENODEV;
}
static int tmp117_probe(struct i2c_client *client)
{
struct tmp117_data *data;
struct iio_dev *indio_dev;
int ret;
int ret, dev_id;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
@ -140,6 +169,8 @@ static int tmp117_probe(struct i2c_client *client)
if (ret < 0)
return ret;
dev_id = ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
@ -148,24 +179,35 @@ static int tmp117_probe(struct i2c_client *client)
data->client = client;
data->calibbias = 0;
indio_dev->name = "tmp117";
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &tmp117_info;
indio_dev->channels = tmp117_channels;
indio_dev->num_channels = ARRAY_SIZE(tmp117_channels);
switch (dev_id) {
case TMP116_DEVICE_ID:
indio_dev->channels = tmp116_channels;
indio_dev->num_channels = ARRAY_SIZE(tmp116_channels);
indio_dev->name = "tmp116";
break;
case TMP117_DEVICE_ID:
indio_dev->channels = tmp117_channels;
indio_dev->num_channels = ARRAY_SIZE(tmp117_channels);
indio_dev->name = "tmp117";
break;
}
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct of_device_id tmp117_of_match[] = {
{ .compatible = "ti,tmp117", },
{ .compatible = "ti,tmp116", .data = (void *)TMP116_DEVICE_ID },
{ .compatible = "ti,tmp117", .data = (void *)TMP117_DEVICE_ID },
{ }
};
MODULE_DEVICE_TABLE(of, tmp117_of_match);
static const struct i2c_device_id tmp117_id[] = {
{ "tmp117", 0 },
{ "tmp116", TMP116_DEVICE_ID },
{ "tmp117", TMP117_DEVICE_ID },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp117_id);

View File

@ -46,7 +46,7 @@ static int iio_loop_thread(void *data)
set_freezable();
do {
iio_trigger_poll_chained(trig);
iio_trigger_poll_nested(trig);
} while (likely(!kthread_freezable_should_stop(NULL)));
return 0;

View File

@ -10,7 +10,6 @@ source "drivers/staging/iio/adc/Kconfig"
source "drivers/staging/iio/addac/Kconfig"
source "drivers/staging/iio/frequency/Kconfig"
source "drivers/staging/iio/impedance-analyzer/Kconfig"
source "drivers/staging/iio/meter/Kconfig"
source "drivers/staging/iio/resolver/Kconfig"
endmenu

View File

@ -8,5 +8,4 @@ obj-y += adc/
obj-y += addac/
obj-y += frequency/
obj-y += impedance-analyzer/
obj-y += meter/
obj-y += resolver/

View File

@ -1,37 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
#
# IIO meter drivers configuration
#
menu "Active energy metering IC"
config ADE7854
tristate "Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver"
depends on SPI || I2C
help
Say yes here to build support for Analog Devices ADE7854/58/68/78 Polyphase
Multifunction Energy Metering IC Driver.
To compile this driver as a module, choose M here: the
module will be called ade7854.
config ADE7854_I2C
tristate "support I2C bus connection"
depends on ADE7854 && I2C
default y
help
Say Y here if you have ADE7854/58/68/78 hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called ade7854-i2c.
config ADE7854_SPI
tristate "support SPI bus connection"
depends on ADE7854 && SPI
default y
help
Say Y here if you have ADE7854/58/68/78 hooked to a SPI bus.
To compile this driver as a module, choose M here: the
module will be called ade7854-spi.
endmenu

View File

@ -1,8 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for metering ic drivers
#
obj-$(CONFIG_ADE7854) += ade7854.o
obj-$(CONFIG_ADE7854_I2C) += ade7854-i2c.o
obj-$(CONFIG_ADE7854_SPI) += ade7854-spi.o

View File

@ -1,153 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (I2C Bus)
*
* Copyright 2010 Analog Devices Inc.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include "ade7854.h"
static int ade7854_i2c_write_reg(struct device *dev,
u16 reg_address,
u32 val,
int bits)
{
int ret;
int count;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = (reg_address >> 8) & 0xFF;
st->tx[1] = reg_address & 0xFF;
switch (bits) {
case 8:
st->tx[2] = val & 0xFF;
count = 3;
break;
case 16:
st->tx[2] = (val >> 8) & 0xFF;
st->tx[3] = val & 0xFF;
count = 4;
break;
case 24:
st->tx[2] = (val >> 16) & 0xFF;
st->tx[3] = (val >> 8) & 0xFF;
st->tx[4] = val & 0xFF;
count = 5;
break;
case 32:
st->tx[2] = (val >> 24) & 0xFF;
st->tx[3] = (val >> 16) & 0xFF;
st->tx[4] = (val >> 8) & 0xFF;
st->tx[5] = val & 0xFF;
count = 6;
break;
default:
ret = -EINVAL;
goto unlock;
}
ret = i2c_master_send(st->i2c, st->tx, count);
unlock:
mutex_unlock(&st->buf_lock);
if (ret < 0)
return ret;
return 0;
}
static int ade7854_i2c_read_reg(struct device *dev,
u16 reg_address,
u32 *val,
int bits)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&st->buf_lock);
st->tx[0] = (reg_address >> 8) & 0xFF;
st->tx[1] = reg_address & 0xFF;
ret = i2c_master_send(st->i2c, st->tx, 2);
if (ret < 0)
goto unlock;
ret = i2c_master_recv(st->i2c, st->rx, bits);
if (ret < 0)
goto unlock;
switch (bits) {
case 8:
*val = st->rx[0];
break;
case 16:
*val = (st->rx[0] << 8) | st->rx[1];
break;
case 24:
*val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
break;
case 32:
*val = (st->rx[0] << 24) | (st->rx[1] << 16) |
(st->rx[2] << 8) | st->rx[3];
break;
default:
ret = -EINVAL;
goto unlock;
}
unlock:
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7854_i2c_probe(struct i2c_client *client)
{
struct ade7854_state *st;
struct iio_dev *indio_dev;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
st->read_reg = ade7854_i2c_read_reg;
st->write_reg = ade7854_i2c_write_reg;
st->i2c = client;
st->irq = client->irq;
return ade7854_probe(indio_dev, &client->dev);
}
static const struct i2c_device_id ade7854_id[] = {
{ "ade7854", 0 },
{ "ade7858", 0 },
{ "ade7868", 0 },
{ "ade7878", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ade7854_id);
static struct i2c_driver ade7854_i2c_driver = {
.driver = {
.name = "ade7854",
},
.probe_new = ade7854_i2c_probe,
.id_table = ade7854_id,
};
module_i2c_driver(ade7854_i2c_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC I2C Driver");
MODULE_LICENSE("GPL v2");

View File

@ -1,160 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (SPI Bus)
*
* Copyright 2010 Analog Devices Inc.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include "ade7854.h"
static int ade7854_spi_write_reg(struct device *dev,
u16 reg_address,
u32 val,
int bits)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct spi_transfer xfer = {
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 4,
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7854_WRITE_REG;
st->tx[1] = (reg_address >> 8) & 0xFF;
st->tx[2] = reg_address & 0xFF;
switch (bits) {
case 8:
st->tx[3] = val & 0xFF;
break;
case 16:
xfer.len = 5;
st->tx[3] = (val >> 8) & 0xFF;
st->tx[4] = val & 0xFF;
break;
case 24:
xfer.len = 6;
st->tx[3] = (val >> 16) & 0xFF;
st->tx[4] = (val >> 8) & 0xFF;
st->tx[5] = val & 0xFF;
break;
case 32:
xfer.len = 7;
st->tx[3] = (val >> 24) & 0xFF;
st->tx[4] = (val >> 16) & 0xFF;
st->tx[5] = (val >> 8) & 0xFF;
st->tx[6] = val & 0xFF;
break;
default:
ret = -EINVAL;
goto unlock;
}
ret = spi_sync_transfer(st->spi, &xfer, 1);
unlock:
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7854_spi_read_reg(struct device *dev,
u16 reg_address,
u32 *val,
int bits)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 3,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = bits,
}
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7854_READ_REG;
st->tx[1] = (reg_address >> 8) & 0xFF;
st->tx[2] = reg_address & 0xFF;
ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
if (ret < 0) {
dev_err(&st->spi->dev, "problem when reading register 0x%02X",
reg_address);
goto unlock;
}
switch (bits) {
case 8:
*val = st->rx[0];
break;
case 16:
*val = be16_to_cpup((const __be16 *)st->rx);
break;
case 24:
*val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
break;
case 32:
*val = be32_to_cpup((const __be32 *)st->rx);
break;
}
unlock:
mutex_unlock(&st->buf_lock);
return ret;
}
static int ade7854_spi_probe(struct spi_device *spi)
{
struct ade7854_state *st;
struct iio_dev *indio_dev;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->read_reg = ade7854_spi_read_reg;
st->write_reg = ade7854_spi_write_reg;
st->irq = spi->irq;
st->spi = spi;
return ade7854_probe(indio_dev, &spi->dev);
}
static const struct spi_device_id ade7854_id[] = {
{ "ade7854", 0 },
{ "ade7858", 0 },
{ "ade7868", 0 },
{ "ade7878", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, ade7854_id);
static struct spi_driver ade7854_driver = {
.driver = {
.name = "ade7854",
},
.probe = ade7854_spi_probe,
.id_table = ade7854_id,
};
module_spi_driver(ade7854_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 SPI Driver");
MODULE_LICENSE("GPL v2");

View File

@ -1,556 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver
*
* Copyright 2010 Analog Devices Inc.
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include "meter.h"
#include "ade7854.h"
static ssize_t ade7854_read_8bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u32 val = 0;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = st->read_reg(dev, this_attr->address, &val, 8);
if (ret < 0)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7854_read_16bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u32 val = 0;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = st->read_reg(dev, this_attr->address, &val, 16);
if (ret < 0)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7854_read_24bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u32 val;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = st->read_reg(dev, this_attr->address, &val, 24);
if (ret < 0)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7854_read_32bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
u32 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
ret = st->read_reg(dev, this_attr->address, &val, 32);
if (ret < 0)
return ret;
return sprintf(buf, "%u\n", val);
}
static ssize_t ade7854_write_8bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
u8 val;
ret = kstrtou8(buf, 10, &val);
if (ret)
goto error_ret;
ret = st->write_reg(dev, this_attr->address, val, 8);
error_ret:
return ret ? ret : len;
}
static ssize_t ade7854_write_16bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
u16 val;
ret = kstrtou16(buf, 10, &val);
if (ret)
goto error_ret;
ret = st->write_reg(dev, this_attr->address, val, 16);
error_ret:
return ret ? ret : len;
}
static ssize_t ade7854_write_24bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
u32 val;
ret = kstrtou32(buf, 10, &val);
if (ret)
goto error_ret;
ret = st->write_reg(dev, this_attr->address, val, 24);
error_ret:
return ret ? ret : len;
}
static ssize_t ade7854_write_32bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
u32 val;
ret = kstrtou32(buf, 10, &val);
if (ret)
goto error_ret;
ret = st->write_reg(dev, this_attr->address, val, 32);
error_ret:
return ret ? ret : len;
}
static int ade7854_reset(struct device *dev)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
u32 val;
st->read_reg(dev, ADE7854_CONFIG, &val, 16);
val |= BIT(7); /* Software Chip Reset */
return st->write_reg(dev, ADE7854_CONFIG, val, 16);
}
static IIO_DEV_ATTR_AIGAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_AIGAIN);
static IIO_DEV_ATTR_BIGAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_BIGAIN);
static IIO_DEV_ATTR_CIGAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_CIGAIN);
static IIO_DEV_ATTR_NIGAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_NIGAIN);
static IIO_DEV_ATTR_AVGAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_AVGAIN);
static IIO_DEV_ATTR_BVGAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_BVGAIN);
static IIO_DEV_ATTR_CVGAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_CVGAIN);
static IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_AVAGAIN);
static IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_BVAGAIN);
static IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_CVAGAIN);
static IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_AWATTOS);
static IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_BWATTOS);
static IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_CWATTOS);
static IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_AVARGAIN);
static IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_BVARGAIN);
static IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_CVARGAIN);
static IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_AVAROS);
static IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_BVAROS);
static IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(0644,
ade7854_read_24bit,
ade7854_write_24bit,
ADE7854_CVAROS);
static IIO_DEV_ATTR_VPEAK(0644,
ade7854_read_32bit,
ade7854_write_32bit,
ADE7854_VPEAK);
static IIO_DEV_ATTR_IPEAK(0644,
ade7854_read_32bit,
ade7854_write_32bit,
ADE7854_IPEAK);
static IIO_DEV_ATTR_APHCAL(0644,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_APHCAL);
static IIO_DEV_ATTR_BPHCAL(0644,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_BPHCAL);
static IIO_DEV_ATTR_CPHCAL(0644,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_CPHCAL);
static IIO_DEV_ATTR_CF1DEN(0644,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_CF1DEN);
static IIO_DEV_ATTR_CF2DEN(0644,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_CF2DEN);
static IIO_DEV_ATTR_CF3DEN(0644,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_CF3DEN);
static IIO_DEV_ATTR_LINECYC(0644,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_LINECYC);
static IIO_DEV_ATTR_SAGCYC(0644,
ade7854_read_8bit,
ade7854_write_8bit,
ADE7854_SAGCYC);
static IIO_DEV_ATTR_CFCYC(0644,
ade7854_read_8bit,
ade7854_write_8bit,
ADE7854_CFCYC);
static IIO_DEV_ATTR_PEAKCYC(0644,
ade7854_read_8bit,
ade7854_write_8bit,
ADE7854_PEAKCYC);
static IIO_DEV_ATTR_CHKSUM(ade7854_read_24bit,
ADE7854_CHECKSUM);
static IIO_DEV_ATTR_ANGLE0(ade7854_read_24bit,
ADE7854_ANGLE0);
static IIO_DEV_ATTR_ANGLE1(ade7854_read_24bit,
ADE7854_ANGLE1);
static IIO_DEV_ATTR_ANGLE2(ade7854_read_24bit,
ADE7854_ANGLE2);
static IIO_DEV_ATTR_AIRMS(0444,
ade7854_read_24bit,
NULL,
ADE7854_AIRMS);
static IIO_DEV_ATTR_BIRMS(0444,
ade7854_read_24bit,
NULL,
ADE7854_BIRMS);
static IIO_DEV_ATTR_CIRMS(0444,
ade7854_read_24bit,
NULL,
ADE7854_CIRMS);
static IIO_DEV_ATTR_NIRMS(0444,
ade7854_read_24bit,
NULL,
ADE7854_NIRMS);
static IIO_DEV_ATTR_AVRMS(0444,
ade7854_read_24bit,
NULL,
ADE7854_AVRMS);
static IIO_DEV_ATTR_BVRMS(0444,
ade7854_read_24bit,
NULL,
ADE7854_BVRMS);
static IIO_DEV_ATTR_CVRMS(0444,
ade7854_read_24bit,
NULL,
ADE7854_CVRMS);
static IIO_DEV_ATTR_AIRMSOS(0444,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_AIRMSOS);
static IIO_DEV_ATTR_BIRMSOS(0444,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_BIRMSOS);
static IIO_DEV_ATTR_CIRMSOS(0444,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_CIRMSOS);
static IIO_DEV_ATTR_AVRMSOS(0444,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_AVRMSOS);
static IIO_DEV_ATTR_BVRMSOS(0444,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_BVRMSOS);
static IIO_DEV_ATTR_CVRMSOS(0444,
ade7854_read_16bit,
ade7854_write_16bit,
ADE7854_CVRMSOS);
static IIO_DEV_ATTR_VOLT_A(ade7854_read_24bit,
ADE7854_VAWV);
static IIO_DEV_ATTR_VOLT_B(ade7854_read_24bit,
ADE7854_VBWV);
static IIO_DEV_ATTR_VOLT_C(ade7854_read_24bit,
ADE7854_VCWV);
static IIO_DEV_ATTR_CURRENT_A(ade7854_read_24bit,
ADE7854_IAWV);
static IIO_DEV_ATTR_CURRENT_B(ade7854_read_24bit,
ADE7854_IBWV);
static IIO_DEV_ATTR_CURRENT_C(ade7854_read_24bit,
ADE7854_ICWV);
static IIO_DEV_ATTR_AWATTHR(ade7854_read_32bit,
ADE7854_AWATTHR);
static IIO_DEV_ATTR_BWATTHR(ade7854_read_32bit,
ADE7854_BWATTHR);
static IIO_DEV_ATTR_CWATTHR(ade7854_read_32bit,
ADE7854_CWATTHR);
static IIO_DEV_ATTR_AFWATTHR(ade7854_read_32bit,
ADE7854_AFWATTHR);
static IIO_DEV_ATTR_BFWATTHR(ade7854_read_32bit,
ADE7854_BFWATTHR);
static IIO_DEV_ATTR_CFWATTHR(ade7854_read_32bit,
ADE7854_CFWATTHR);
static IIO_DEV_ATTR_AVARHR(ade7854_read_32bit,
ADE7854_AVARHR);
static IIO_DEV_ATTR_BVARHR(ade7854_read_32bit,
ADE7854_BVARHR);
static IIO_DEV_ATTR_CVARHR(ade7854_read_32bit,
ADE7854_CVARHR);
static IIO_DEV_ATTR_AVAHR(ade7854_read_32bit,
ADE7854_AVAHR);
static IIO_DEV_ATTR_BVAHR(ade7854_read_32bit,
ADE7854_BVAHR);
static IIO_DEV_ATTR_CVAHR(ade7854_read_32bit,
ADE7854_CVAHR);
static int ade7854_set_irq(struct device *dev, bool enable)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
u32 irqen;
ret = st->read_reg(dev, ADE7854_MASK0, &irqen, 32);
if (ret < 0)
return ret;
if (enable)
irqen |= BIT(17); /* 1: interrupt enabled when all periodical
* (at 8 kHz rate) DSP computations finish.
*/
else
irqen &= ~BIT(17);
return st->write_reg(dev, ADE7854_MASK0, irqen, 32);
}
static int ade7854_initial_setup(struct iio_dev *indio_dev)
{
int ret;
struct device *dev = &indio_dev->dev;
/* Disable IRQ */
ret = ade7854_set_irq(dev, false);
if (ret) {
dev_err(dev, "disable irq failed");
goto err_ret;
}
ade7854_reset(dev);
usleep_range(ADE7854_STARTUP_DELAY, ADE7854_STARTUP_DELAY + 100);
err_ret:
return ret;
}
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("8000");
static IIO_CONST_ATTR(name, "ade7854");
static struct attribute *ade7854_attributes[] = {
&iio_dev_attr_aigain.dev_attr.attr,
&iio_dev_attr_bigain.dev_attr.attr,
&iio_dev_attr_cigain.dev_attr.attr,
&iio_dev_attr_nigain.dev_attr.attr,
&iio_dev_attr_avgain.dev_attr.attr,
&iio_dev_attr_bvgain.dev_attr.attr,
&iio_dev_attr_cvgain.dev_attr.attr,
&iio_dev_attr_linecyc.dev_attr.attr,
&iio_dev_attr_sagcyc.dev_attr.attr,
&iio_dev_attr_cfcyc.dev_attr.attr,
&iio_dev_attr_peakcyc.dev_attr.attr,
&iio_dev_attr_chksum.dev_attr.attr,
&iio_dev_attr_apparent_power_a_gain.dev_attr.attr,
&iio_dev_attr_apparent_power_b_gain.dev_attr.attr,
&iio_dev_attr_apparent_power_c_gain.dev_attr.attr,
&iio_dev_attr_active_power_a_offset.dev_attr.attr,
&iio_dev_attr_active_power_b_offset.dev_attr.attr,
&iio_dev_attr_active_power_c_offset.dev_attr.attr,
&iio_dev_attr_reactive_power_a_gain.dev_attr.attr,
&iio_dev_attr_reactive_power_b_gain.dev_attr.attr,
&iio_dev_attr_reactive_power_c_gain.dev_attr.attr,
&iio_dev_attr_reactive_power_a_offset.dev_attr.attr,
&iio_dev_attr_reactive_power_b_offset.dev_attr.attr,
&iio_dev_attr_reactive_power_c_offset.dev_attr.attr,
&iio_dev_attr_awatthr.dev_attr.attr,
&iio_dev_attr_bwatthr.dev_attr.attr,
&iio_dev_attr_cwatthr.dev_attr.attr,
&iio_dev_attr_afwatthr.dev_attr.attr,
&iio_dev_attr_bfwatthr.dev_attr.attr,
&iio_dev_attr_cfwatthr.dev_attr.attr,
&iio_dev_attr_avarhr.dev_attr.attr,
&iio_dev_attr_bvarhr.dev_attr.attr,
&iio_dev_attr_cvarhr.dev_attr.attr,
&iio_dev_attr_angle0.dev_attr.attr,
&iio_dev_attr_angle1.dev_attr.attr,
&iio_dev_attr_angle2.dev_attr.attr,
&iio_dev_attr_avahr.dev_attr.attr,
&iio_dev_attr_bvahr.dev_attr.attr,
&iio_dev_attr_cvahr.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_const_attr_name.dev_attr.attr,
&iio_dev_attr_vpeak.dev_attr.attr,
&iio_dev_attr_ipeak.dev_attr.attr,
&iio_dev_attr_aphcal.dev_attr.attr,
&iio_dev_attr_bphcal.dev_attr.attr,
&iio_dev_attr_cphcal.dev_attr.attr,
&iio_dev_attr_cf1den.dev_attr.attr,
&iio_dev_attr_cf2den.dev_attr.attr,
&iio_dev_attr_cf3den.dev_attr.attr,
&iio_dev_attr_airms.dev_attr.attr,
&iio_dev_attr_birms.dev_attr.attr,
&iio_dev_attr_cirms.dev_attr.attr,
&iio_dev_attr_nirms.dev_attr.attr,
&iio_dev_attr_avrms.dev_attr.attr,
&iio_dev_attr_bvrms.dev_attr.attr,
&iio_dev_attr_cvrms.dev_attr.attr,
&iio_dev_attr_airmsos.dev_attr.attr,
&iio_dev_attr_birmsos.dev_attr.attr,
&iio_dev_attr_cirmsos.dev_attr.attr,
&iio_dev_attr_avrmsos.dev_attr.attr,
&iio_dev_attr_bvrmsos.dev_attr.attr,
&iio_dev_attr_cvrmsos.dev_attr.attr,
&iio_dev_attr_volt_a.dev_attr.attr,
&iio_dev_attr_volt_b.dev_attr.attr,
&iio_dev_attr_volt_c.dev_attr.attr,
&iio_dev_attr_current_a.dev_attr.attr,
&iio_dev_attr_current_b.dev_attr.attr,
&iio_dev_attr_current_c.dev_attr.attr,
NULL,
};
static const struct attribute_group ade7854_attribute_group = {
.attrs = ade7854_attributes,
};
static const struct iio_info ade7854_info = {
.attrs = &ade7854_attribute_group,
};
int ade7854_probe(struct iio_dev *indio_dev, struct device *dev)
{
int ret;
struct ade7854_state *st = iio_priv(indio_dev);
/* setup the industrialio driver allocated elements */
mutex_init(&st->buf_lock);
indio_dev->dev.parent = dev;
indio_dev->info = &ade7854_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
return ret;
/* Get the device into a sane initial state */
return ade7854_initial_setup(indio_dev);
}
EXPORT_SYMBOL(ade7854_probe);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Energy Meter");
MODULE_LICENSE("GPL v2");

View File

@ -1,173 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ADE7854_H
#define _ADE7854_H
#define ADE7854_AIGAIN 0x4380
#define ADE7854_AVGAIN 0x4381
#define ADE7854_BIGAIN 0x4382
#define ADE7854_BVGAIN 0x4383
#define ADE7854_CIGAIN 0x4384
#define ADE7854_CVGAIN 0x4385
#define ADE7854_NIGAIN 0x4386
#define ADE7854_AIRMSOS 0x4387
#define ADE7854_AVRMSOS 0x4388
#define ADE7854_BIRMSOS 0x4389
#define ADE7854_BVRMSOS 0x438A
#define ADE7854_CIRMSOS 0x438B
#define ADE7854_CVRMSOS 0x438C
#define ADE7854_NIRMSOS 0x438D
#define ADE7854_AVAGAIN 0x438E
#define ADE7854_BVAGAIN 0x438F
#define ADE7854_CVAGAIN 0x4390
#define ADE7854_AWGAIN 0x4391
#define ADE7854_AWATTOS 0x4392
#define ADE7854_BWGAIN 0x4393
#define ADE7854_BWATTOS 0x4394
#define ADE7854_CWGAIN 0x4395
#define ADE7854_CWATTOS 0x4396
#define ADE7854_AVARGAIN 0x4397
#define ADE7854_AVAROS 0x4398
#define ADE7854_BVARGAIN 0x4399
#define ADE7854_BVAROS 0x439A
#define ADE7854_CVARGAIN 0x439B
#define ADE7854_CVAROS 0x439C
#define ADE7854_AFWGAIN 0x439D
#define ADE7854_AFWATTOS 0x439E
#define ADE7854_BFWGAIN 0x439F
#define ADE7854_BFWATTOS 0x43A0
#define ADE7854_CFWGAIN 0x43A1
#define ADE7854_CFWATTOS 0x43A2
#define ADE7854_AFVARGAIN 0x43A3
#define ADE7854_AFVAROS 0x43A4
#define ADE7854_BFVARGAIN 0x43A5
#define ADE7854_BFVAROS 0x43A6
#define ADE7854_CFVARGAIN 0x43A7
#define ADE7854_CFVAROS 0x43A8
#define ADE7854_VATHR1 0x43A9
#define ADE7854_VATHR0 0x43AA
#define ADE7854_WTHR1 0x43AB
#define ADE7854_WTHR0 0x43AC
#define ADE7854_VARTHR1 0x43AD
#define ADE7854_VARTHR0 0x43AE
#define ADE7854_RSV 0x43AF
#define ADE7854_VANOLOAD 0x43B0
#define ADE7854_APNOLOAD 0x43B1
#define ADE7854_VARNOLOAD 0x43B2
#define ADE7854_VLEVEL 0x43B3
#define ADE7854_DICOEFF 0x43B5
#define ADE7854_HPFDIS 0x43B6
#define ADE7854_ISUMLVL 0x43B8
#define ADE7854_ISUM 0x43BF
#define ADE7854_AIRMS 0x43C0
#define ADE7854_AVRMS 0x43C1
#define ADE7854_BIRMS 0x43C2
#define ADE7854_BVRMS 0x43C3
#define ADE7854_CIRMS 0x43C4
#define ADE7854_CVRMS 0x43C5
#define ADE7854_NIRMS 0x43C6
#define ADE7854_RUN 0xE228
#define ADE7854_AWATTHR 0xE400
#define ADE7854_BWATTHR 0xE401
#define ADE7854_CWATTHR 0xE402
#define ADE7854_AFWATTHR 0xE403
#define ADE7854_BFWATTHR 0xE404
#define ADE7854_CFWATTHR 0xE405
#define ADE7854_AVARHR 0xE406
#define ADE7854_BVARHR 0xE407
#define ADE7854_CVARHR 0xE408
#define ADE7854_AFVARHR 0xE409
#define ADE7854_BFVARHR 0xE40A
#define ADE7854_CFVARHR 0xE40B
#define ADE7854_AVAHR 0xE40C
#define ADE7854_BVAHR 0xE40D
#define ADE7854_CVAHR 0xE40E
#define ADE7854_IPEAK 0xE500
#define ADE7854_VPEAK 0xE501
#define ADE7854_STATUS0 0xE502
#define ADE7854_STATUS1 0xE503
#define ADE7854_OILVL 0xE507
#define ADE7854_OVLVL 0xE508
#define ADE7854_SAGLVL 0xE509
#define ADE7854_MASK0 0xE50A
#define ADE7854_MASK1 0xE50B
#define ADE7854_IAWV 0xE50C
#define ADE7854_IBWV 0xE50D
#define ADE7854_ICWV 0xE50E
#define ADE7854_VAWV 0xE510
#define ADE7854_VBWV 0xE511
#define ADE7854_VCWV 0xE512
#define ADE7854_AWATT 0xE513
#define ADE7854_BWATT 0xE514
#define ADE7854_CWATT 0xE515
#define ADE7854_AVA 0xE519
#define ADE7854_BVA 0xE51A
#define ADE7854_CVA 0xE51B
#define ADE7854_CHECKSUM 0xE51F
#define ADE7854_VNOM 0xE520
#define ADE7854_PHSTATUS 0xE600
#define ADE7854_ANGLE0 0xE601
#define ADE7854_ANGLE1 0xE602
#define ADE7854_ANGLE2 0xE603
#define ADE7854_PERIOD 0xE607
#define ADE7854_PHNOLOAD 0xE608
#define ADE7854_LINECYC 0xE60C
#define ADE7854_ZXTOUT 0xE60D
#define ADE7854_COMPMODE 0xE60E
#define ADE7854_GAIN 0xE60F
#define ADE7854_CFMODE 0xE610
#define ADE7854_CF1DEN 0xE611
#define ADE7854_CF2DEN 0xE612
#define ADE7854_CF3DEN 0xE613
#define ADE7854_APHCAL 0xE614
#define ADE7854_BPHCAL 0xE615
#define ADE7854_CPHCAL 0xE616
#define ADE7854_PHSIGN 0xE617
#define ADE7854_CONFIG 0xE618
#define ADE7854_MMODE 0xE700
#define ADE7854_ACCMODE 0xE701
#define ADE7854_LCYCMODE 0xE702
#define ADE7854_PEAKCYC 0xE703
#define ADE7854_SAGCYC 0xE704
#define ADE7854_CFCYC 0xE705
#define ADE7854_HSDC_CFG 0xE706
#define ADE7854_CONFIG2 0xEC01
#define ADE7854_READ_REG 0x1
#define ADE7854_WRITE_REG 0x0
#define ADE7854_MAX_TX 7
#define ADE7854_MAX_RX 7
#define ADE7854_STARTUP_DELAY 1000
#define ADE7854_SPI_SLOW (u32)(300 * 1000)
#define ADE7854_SPI_BURST (u32)(1000 * 1000)
#define ADE7854_SPI_FAST (u32)(2000 * 1000)
/**
* struct ade7854_state - device instance specific data
* @spi: actual spi_device
* @read_reg Wrapper function for I2C and SPI read
* @write_reg Wrapper function for I2C and SPI write
* @indio_dev: industrial I/O device structure
* @buf_lock: mutex to protect tx and rx
* @tx: transmit buffer
* @rx: receive buffer
**/
struct ade7854_state {
struct spi_device *spi;
struct i2c_client *i2c;
int (*read_reg)(struct device *dev, u16 reg_address, u32 *val,
int bits);
int (*write_reg)(struct device *dev, u16 reg_address, u32 val,
int bits);
int irq;
struct mutex buf_lock;
u8 tx[ADE7854_MAX_TX] __aligned(IIO_DMA_MINALIGN);
u8 rx[ADE7854_MAX_RX];
};
int ade7854_probe(struct iio_dev *indio_dev, struct device *dev);
int ade7854_remove(struct iio_dev *indio_dev);
#endif

View File

@ -1,398 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _METER_H
#define _METER_H
#include <linux/iio/sysfs.h>
/* metering ic types of attribute */
#define IIO_DEV_ATTR_CURRENT_A_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(current_a_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CURRENT_B_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(current_b_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CURRENT_C_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(current_c_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_VOLT_A_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(volt_a_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_VOLT_B_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(volt_b_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_VOLT_C_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(volt_c_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(reactive_power_a_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(reactive_power_b_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(reactive_power_c_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(active_power_a_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(active_power_b_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(active_power_c_offset, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CURRENT_A_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(current_a_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CURRENT_B_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(current_b_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CURRENT_C_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(current_c_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(apparent_power_a_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(apparent_power_b_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(apparent_power_c_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACTIVE_POWER_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(active_power_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(active_power_a_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(active_power_b_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(active_power_c_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(reactive_power_a_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(reactive_power_b_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(reactive_power_c_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CURRENT_A(_show, _addr) \
IIO_DEVICE_ATTR(current_a, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_CURRENT_B(_show, _addr) \
IIO_DEVICE_ATTR(current_b, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_CURRENT_C(_show, _addr) \
IIO_DEVICE_ATTR(current_c, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_VOLT_A(_show, _addr) \
IIO_DEVICE_ATTR(volt_a, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_VOLT_B(_show, _addr) \
IIO_DEVICE_ATTR(volt_b, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_VOLT_C(_show, _addr) \
IIO_DEVICE_ATTR(volt_c, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_AENERGY(_show, _addr) \
IIO_DEVICE_ATTR(aenergy, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_LENERGY(_show, _addr) \
IIO_DEVICE_ATTR(lenergy, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_RAENERGY(_show, _addr) \
IIO_DEVICE_ATTR(raenergy, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_LAENERGY(_show, _addr) \
IIO_DEVICE_ATTR(laenergy, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_VAENERGY(_show, _addr) \
IIO_DEVICE_ATTR(vaenergy, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_LVAENERGY(_show, _addr) \
IIO_DEVICE_ATTR(lvaenergy, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_RVAENERGY(_show, _addr) \
IIO_DEVICE_ATTR(rvaenergy, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_LVARENERGY(_show, _addr) \
IIO_DEVICE_ATTR(lvarenergy, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_CHKSUM(_show, _addr) \
IIO_DEVICE_ATTR(chksum, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_ANGLE0(_show, _addr) \
IIO_DEVICE_ATTR(angle0, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_ANGLE1(_show, _addr) \
IIO_DEVICE_ATTR(angle1, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_ANGLE2(_show, _addr) \
IIO_DEVICE_ATTR(angle2, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_AWATTHR(_show, _addr) \
IIO_DEVICE_ATTR(awatthr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_BWATTHR(_show, _addr) \
IIO_DEVICE_ATTR(bwatthr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_CWATTHR(_show, _addr) \
IIO_DEVICE_ATTR(cwatthr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_AFWATTHR(_show, _addr) \
IIO_DEVICE_ATTR(afwatthr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_BFWATTHR(_show, _addr) \
IIO_DEVICE_ATTR(bfwatthr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_CFWATTHR(_show, _addr) \
IIO_DEVICE_ATTR(cfwatthr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_AVARHR(_show, _addr) \
IIO_DEVICE_ATTR(avarhr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_BVARHR(_show, _addr) \
IIO_DEVICE_ATTR(bvarhr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_CVARHR(_show, _addr) \
IIO_DEVICE_ATTR(cvarhr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_AVAHR(_show, _addr) \
IIO_DEVICE_ATTR(avahr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_BVAHR(_show, _addr) \
IIO_DEVICE_ATTR(bvahr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_CVAHR(_show, _addr) \
IIO_DEVICE_ATTR(cvahr, 0444, _show, NULL, _addr)
#define IIO_DEV_ATTR_IOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(ios, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_VOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(vos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_PHCAL(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(phcal, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_APHCAL(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(aphcal, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_BPHCAL(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(bphcal, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CPHCAL(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cphcal, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_APOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(apos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_AAPOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(aapos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_BAPOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(bapos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CAPOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(capos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_AVRMSGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(avrmsgain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_BVRMSGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(bvrmsgain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CVRMSGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cvrmsgain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_AIGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(aigain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_BIGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(bigain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CIGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cigain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_NIGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(nigain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_AVGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(avgain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_BVGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(bvgain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CVGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cvgain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_WGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(wgain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_WDIV(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(wdiv, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CFNUM(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cfnum, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CFDEN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cfden, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CF1DEN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cf1den, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CF2DEN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cf2den, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CF3DEN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cf3den, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_IRMS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(irms, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_VRMS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(vrms, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_AIRMS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(airms, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_BIRMS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(birms, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CIRMS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cirms, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_NIRMS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(nirms, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_AVRMS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(avrms, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_BVRMS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(bvrms, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CVRMS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cvrms, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_IRMSOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(irmsos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_VRMSOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(vrmsos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_AIRMSOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(airmsos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_BIRMSOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(birmsos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CIRMSOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cirmsos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_AVRMSOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(avrmsos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_BVRMSOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(bvrmsos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CVRMSOS(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cvrmsos, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_VAGAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(vagain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_PGA_GAIN(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(pga_gain, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_VADIV(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(vadiv, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_LINECYC(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(linecyc, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_SAGCYC(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(sagcyc, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_CFCYC(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(cfcyc, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_PEAKCYC(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(peakcyc, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_SAGLVL(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(saglvl, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_IPKLVL(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(ipklvl, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_VPKLVL(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(vpklvl, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_IPEAK(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(ipeak, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_RIPEAK(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(ripeak, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_VPEAK(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(vpeak, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_RVPEAK(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(rvpeak, _mode, _show, _store, _addr)
#define IIO_DEV_ATTR_VPERIOD(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(vperiod, _mode, _show, _store, _addr)
/* active energy register, AENERGY, is more than half full */
#define IIO_EVENT_ATTR_AENERGY_HALF_FULL(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(aenergy_half_full, _evlist, _show, _store, _mask)
/* a SAG on the line voltage */
#define IIO_EVENT_ATTR_LINE_VOLT_SAG(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(line_volt_sag, _evlist, _show, _store, _mask)
/*
* Indicates the end of energy accumulation over an integer number
* of half line cycles
*/
#define IIO_EVENT_ATTR_CYCEND(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(cycend, _evlist, _show, _store, _mask)
/* on the rising and falling edge of the voltage waveform */
#define IIO_EVENT_ATTR_ZERO_CROSS(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(zero_cross, _evlist, _show, _store, _mask)
/* the active energy register has overflowed */
#define IIO_EVENT_ATTR_AENERGY_OVERFLOW(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(aenergy_overflow, _evlist, _show, _store, _mask)
/* the apparent energy register has overflowed */
#define IIO_EVENT_ATTR_VAENERGY_OVERFLOW(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(vaenergy_overflow, _evlist, _show, _store, _mask)
/* the active energy register, VAENERGY, is more than half full */
#define IIO_EVENT_ATTR_VAENERGY_HALF_FULL(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(vaenergy_half_full, _evlist, _show, _store, _mask)
/* the power has gone from negative to positive */
#define IIO_EVENT_ATTR_PPOS(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(ppos, _evlist, _show, _store, _mask)
/* the power has gone from positive to negative */
#define IIO_EVENT_ATTR_PNEG(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(pneg, _evlist, _show, _store, _mask)
/* waveform sample from Channel 1 has exceeded the IPKLVL value */
#define IIO_EVENT_ATTR_IPKLVL_EXC(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(ipklvl_exc, _evlist, _show, _store, _mask)
/* waveform sample from Channel 2 has exceeded the VPKLVL value */
#define IIO_EVENT_ATTR_VPKLVL_EXC(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(vpklvl_exc, _evlist, _show, _store, _mask)
#endif /* _METER_H */

View File

@ -101,7 +101,7 @@ struct ad2s1210_state {
static const int ad2s1210_mode_vals[4][2] = {
[MOD_POS] = { 0, 0 },
[MOD_VEL] = { 0, 1 },
[MOD_CONFIG] = { 1, 0 },
[MOD_CONFIG] = { 1, 1 },
};
static inline void ad2s1210_set_mode(enum ad2s1210_mode mode,

View File

@ -0,0 +1,206 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* gain-time-scale conversion helpers for IIO light sensors
*
* Copyright (c) 2023 Matti Vaittinen <mazziesaccount@gmail.com>
*/
#ifndef __IIO_GTS_HELPER__
#define __IIO_GTS_HELPER__
#include <linux/types.h>
struct device;
/**
* struct iio_gain_sel_pair - gain - selector values
*
* In many cases devices like light sensors allow setting signal amplification
* (gain) using a register interface. This structure describes amplification
* and corresponding selector (register value)
*
* @gain: Gain (multiplication) value. Gain must be positive, negative
* values are reserved for error handling.
* @sel: Selector (usually register value) used to indicate this gain.
* NOTE: Only selectors >= 0 supported.
*/
struct iio_gain_sel_pair {
int gain;
int sel;
};
/**
* struct iio_itime_sel_mul - integration time description
*
* In many cases devices like light sensors allow setting the duration of
* collecting data. Typically this duration has also an impact to the magnitude
* of measured values (gain). This structure describes the relation of
* integration time and amplification as well as corresponding selector
* (register value).
*
* An example could be a sensor allowing 50, 100, 200 and 400 mS times. The
* respective multiplication values could be 50 mS => 1, 100 mS => 2,
* 200 mS => 4 and 400 mS => 8 assuming the impact of integration time would be
* linear in a way that when collecting data for 50 mS caused value X, doubling
* the data collection time caused value 2X etc.
*
* @time_us: Integration time in microseconds. Time values must be positive,
* negative values are reserved for error handling.
* @sel: Selector (usually register value) used to indicate this time
* NOTE: Only selectors >= 0 supported.
* @mul: Multiplication to the values caused by this time.
* NOTE: Only multipliers > 0 supported.
*/
struct iio_itime_sel_mul {
int time_us;
int sel;
int mul;
};
struct iio_gts {
u64 max_scale;
const struct iio_gain_sel_pair *hwgain_table;
int num_hwgain;
const struct iio_itime_sel_mul *itime_table;
int num_itime;
int **per_time_avail_scale_tables;
int *avail_all_scales_table;
int num_avail_all_scales;
int *avail_time_tables;
int num_avail_time_tables;
};
#define GAIN_SCALE_GAIN(_gain, _sel) \
{ \
.gain = (_gain), \
.sel = (_sel), \
}
#define GAIN_SCALE_ITIME_US(_itime, _sel, _mul) \
{ \
.time_us = (_itime), \
.sel = (_sel), \
.mul = (_mul), \
}
static inline const struct iio_itime_sel_mul *
iio_gts_find_itime_by_time(struct iio_gts *gts, int time)
{
int i;
if (!gts->num_itime)
return NULL;
for (i = 0; i < gts->num_itime; i++)
if (gts->itime_table[i].time_us == time)
return &gts->itime_table[i];
return NULL;
}
static inline const struct iio_itime_sel_mul *
iio_gts_find_itime_by_sel(struct iio_gts *gts, int sel)
{
int i;
for (i = 0; i < gts->num_itime; i++)
if (gts->itime_table[i].sel == sel)
return &gts->itime_table[i];
return NULL;
}
int devm_iio_init_iio_gts(struct device *dev, int max_scale_int, int max_scale_nano,
const struct iio_gain_sel_pair *gain_tbl, int num_gain,
const struct iio_itime_sel_mul *tim_tbl, int num_times,
struct iio_gts *gts);
/**
* iio_gts_find_int_time_by_sel - find integration time matching a selector
* @gts: Gain time scale descriptor
* @sel: selector for which matching integration time is searched for
*
* Return: integration time matching given selector or -EINVAL if
* integration time was not found.
*/
static inline int iio_gts_find_int_time_by_sel(struct iio_gts *gts, int sel)
{
const struct iio_itime_sel_mul *itime;
itime = iio_gts_find_itime_by_sel(gts, sel);
if (!itime)
return -EINVAL;
return itime->time_us;
}
/**
* iio_gts_find_sel_by_int_time - find selector matching integration time
* @gts: Gain time scale descriptor
* @gain: HW-gain for which matching selector is searched for
*
* Return: a selector matching given integration time or -EINVAL if
* selector was not found.
*/
static inline int iio_gts_find_sel_by_int_time(struct iio_gts *gts, int time)
{
const struct iio_itime_sel_mul *itime;
itime = iio_gts_find_itime_by_time(gts, time);
if (!itime)
return -EINVAL;
return itime->sel;
}
/**
* iio_gts_valid_time - check if given integration time is valid
* @gts: Gain time scale descriptor
* @time_us: Integration time to check
*
* Return: True if given time is supported by device. False if not.
*/
static inline bool iio_gts_valid_time(struct iio_gts *gts, int time_us)
{
return iio_gts_find_itime_by_time(gts, time_us) != NULL;
}
int iio_gts_find_sel_by_gain(struct iio_gts *gts, int gain);
/**
* iio_gts_valid_gain - check if given HW-gain is valid
* @gts: Gain time scale descriptor
* @gain: HW-gain to check
*
* Return: True if given time is supported by device. False if not.
*/
static inline bool iio_gts_valid_gain(struct iio_gts *gts, int gain)
{
return iio_gts_find_sel_by_gain(gts, gain) >= 0;
}
int iio_find_closest_gain_low(struct iio_gts *gts, int gain, bool *in_range);
int iio_gts_find_gain_by_sel(struct iio_gts *gts, int sel);
int iio_gts_get_min_gain(struct iio_gts *gts);
int iio_gts_find_int_time_by_sel(struct iio_gts *gts, int sel);
int iio_gts_find_sel_by_int_time(struct iio_gts *gts, int time);
int iio_gts_total_gain_to_scale(struct iio_gts *gts, int total_gain,
int *scale_int, int *scale_nano);
int iio_gts_find_gain_sel_for_scale_using_time(struct iio_gts *gts, int time_sel,
int scale_int, int scale_nano,
int *gain_sel);
int iio_gts_get_scale(struct iio_gts *gts, int gain, int time, int *scale_int,
int *scale_nano);
int iio_gts_find_new_gain_sel_by_old_gain_time(struct iio_gts *gts,
int old_gain, int old_time_sel,
int new_time_sel, int *new_gain);
int iio_gts_find_new_gain_by_old_gain_time(struct iio_gts *gts, int old_gain,
int old_time, int new_time,
int *new_gain);
int iio_gts_avail_times(struct iio_gts *gts, const int **vals, int *type,
int *length);
int iio_gts_all_avail_scales(struct iio_gts *gts, const int **vals, int *type,
int *length);
int iio_gts_avail_scales_for_time(struct iio_gts *gts, int time,
const int **vals, int *type, int *length);
#endif

View File

@ -151,14 +151,8 @@ void iio_trigger_unregister(struct iio_trigger *trig_info);
**/
int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *trig);
/**
* iio_trigger_poll() - called on a trigger occurring
* @trig: trigger which occurred
*
* Typically called in relevant hardware interrupt handler.
**/
void iio_trigger_poll(struct iio_trigger *trig);
void iio_trigger_poll_chained(struct iio_trigger *trig);
void iio_trigger_poll_nested(struct iio_trigger *trig);
irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private);