mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
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:
commit
fba51482b6
@ -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
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
46
Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml
Normal file
46
Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
...
|
@ -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
|
||||
|
||||
|
@ -46,6 +46,9 @@ properties:
|
||||
- items:
|
||||
- const: st,ism330is
|
||||
- const: st,lsm6dso16is
|
||||
- items:
|
||||
- const: st,asm330lhb
|
||||
- const: st,asm330lhh
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
13
MAINTAINERS
13
MAINTAINERS
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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, ®val);
|
||||
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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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 = {
|
||||
|
445
drivers/iio/adc/ti-ads1100.c
Normal file
445
drivers/iio/adc/ti-ads1100.c
Normal 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");
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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(®->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), ®->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, ®->ssr_ad);
|
||||
while (ioread8(®->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(®->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(®->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(®->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 = {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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...
|
||||
*/
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
1077
drivers/iio/industrialio-gts-helper.c
Normal file
1077
drivers/iio/industrialio-gts-helper.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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");
|
||||
|
1497
drivers/iio/light/rohm-bu27034.c
Normal file
1497
drivers/iio/light/rohm-bu27034.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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, ®);
|
||||
if (ret) {
|
||||
dev_err(data->dev, "failed to reestablish comms after reset\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(data->regmap, BMP580_REG_INT_STATUS, ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
/*
|
||||
|
@ -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:
|
||||
|
@ -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))
|
||||
|
@ -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. */
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -8,5 +8,4 @@ obj-y += adc/
|
||||
obj-y += addac/
|
||||
obj-y += frequency/
|
||||
obj-y += impedance-analyzer/
|
||||
obj-y += meter/
|
||||
obj-y += resolver/
|
||||
|
@ -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
|
@ -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
|
@ -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");
|
@ -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");
|
@ -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");
|
@ -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
|
@ -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 */
|
@ -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,
|
||||
|
206
include/linux/iio/iio-gts-helper.h
Normal file
206
include/linux/iio/iio-gts-helper.h
Normal 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 >s->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 >s->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
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user