IIO / Staging driver update for 5.15-rc1
Here is the big set of staging and IIO driver updates for 5.15-rc1. Also included in here are the counter driver subsystem updates as the IIO drivers needed them. Lots of churn in some staging drivers, we dropped the "old" rtl8188eu driver and replaced it with a newer version of the driver that had been maintained out-of-tree by Larry with the end goal of actually being able to get this driver out of staging eventually. Despite that driver being "newer" the line count of this pull request is going up. Some drivers moved out of staging as well, which is always nice to see, that is why there are additions to the mfc and misc driver subsystems. All of these were acked by the various subsystem maintainers involved. But by far, as normal, it's coding style cleanups all over the drivers/staging/ tree in here. Full details of these changes are in the shortlog. All of these have been in linux-next for a while with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYS+BKg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yku5gCgyMykJ2mwtEiQxfAWu13e2iZX29AAnjk38ANp Un2sQXYnL9RVlcnjLg+X =jMWL -----END PGP SIGNATURE----- Merge tag 'staging-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging Pull IIO and staging driver updates from Greg KH: "Here is the big set of staging and IIO driver updates for 5.15-rc1. Also included in here are the counter driver subsystem updates as the IIO drivers needed them. Lots of churn in some staging drivers, we dropped the "old" rtl8188eu driver and replaced it with a newer version of the driver that had been maintained out-of-tree by Larry with the end goal of actually being able to get this driver out of staging eventually. Despite that driver being "newer" the line count of this pull request is going up. Some drivers moved out of staging as well, which is always nice to see, that is why there are additions to the mfc and misc driver subsystems. All of these were acked by the various subsystem maintainers involved. But by far, as normal, it's coding style cleanups all over the drivers/staging/ tree in here. Full details of these changes are in the shortlog. All of these have been in linux-next for a while with no reported problems" [ Note: the r8188eu merge clashed with commit89939e8906
("staging: rtlwifi: use siocdevprivate") from the networking tree. When resolving the issue, I noted that the whole r8188eu rtw_android code is dead since commitae7471cae0
("staging: r8188eu: remove rtw_ioctl function"). End result: the merge resolution was to throw all of that away, rather than do the mindless fixup to code that isn't actually reachable - Linus ] * tag 'staging-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (551 commits) staging: vt6655: Remove filenames in files staging: r8188eu: add extra TODO entries staging: vt6656: Remove filenames in files staging: wlan-ng: fix invalid assignment warning staging: r8188eu: rename fields of struct rtl_ps staging: r8188eu: remove ODM_DynamicPrimaryCCA_DupRTS() staging: r8188eu: rename fields of struct dyn_primary_cca staging: r8188eu: rename struct field Wifi_Error_Status staging: r8188eu: Provide a TODO file for this driver staging: r8188eu: remove unneeded variable staging: r8188eu: remove unneeded conversions to bool staging: r8188eu: remove {read,write}_macreg staging: r8188eu: core: remove condition with no effect staging: r8188eu: remove ethernet.h header file staging: r8188eu: remove ip.h header file staging: r8188eu: remove if_ether.h header file staging: r8188eu: make rtw_deinit_intf_priv return void staging: r8188eu: use is_multicast_ether_addr in os_dep/recv_linux.c staging: r8188eu: use is_multicast_ether_addr in hal/rtl8188eu_xmit.c staging: r8188eu: use is_multicast_ether_addr in core/rtw_xmit.c ...
This commit is contained in:
Коммит
ebf435d3b5
|
@ -0,0 +1,31 @@
|
|||
What: /sys/bus/iio/devices/iio:deviceX/out_temp_raw
|
||||
Date: August 2021
|
||||
KernelVersion: 5.15
|
||||
Contact: Andreas Klinger <ak@it-klinger.de>
|
||||
Description:
|
||||
Set the temperature. This value is sent to the sensor for
|
||||
temperature compensation.
|
||||
Default value: 25000 (25 °C)
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_humidityrelative_raw
|
||||
Date: August 2021
|
||||
KernelVersion: 5.15
|
||||
Contact: Andreas Klinger <ak@it-klinger.de>
|
||||
Description:
|
||||
Set the relative humidity. This value is sent to the sensor for
|
||||
humidity compensation.
|
||||
Default value: 50000 (50 % relative humidity)
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_resistance_calibbias
|
||||
Date: August 2021
|
||||
KernelVersion: 5.15
|
||||
Contact: Andreas Klinger <ak@it-klinger.de>
|
||||
Description:
|
||||
Set the bias value for the resistance which is used for
|
||||
calculation of in_concentration_input as follows:
|
||||
|
||||
x = (in_resistance_raw - in_resistance_calibbias) * 0.65
|
||||
|
||||
in_concentration_input = 500 / (1 + e^x)
|
||||
|
||||
Default value: 30000
|
|
@ -1,61 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/accel/bosch,bma180.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Bosch BMA023 / BMA150/ BMA180 / BMA250 / SMB380 triaxial accelerometers
|
||||
|
||||
maintainers:
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
description: |
|
||||
https://media.digikey.com/pdf/Data%20Sheets/Bosch/BMA150.pdf
|
||||
http://omapworld.com/BMA180_111_1002839.pdf
|
||||
http://ae-bst.resource.bosch.com/media/products/dokumente/bma250/bst-bma250-ds002-05.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- bosch,bma023
|
||||
- bosch,bma150
|
||||
- bosch,bma180
|
||||
- bosch,bma250
|
||||
- bosch,smb380
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
vddio-supply: true
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description: |
|
||||
Type should be either IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_EDGE_RISING.
|
||||
For the bma250 the first interrupt listed must be the one
|
||||
connected to the INT1 pin, the second (optional) interrupt
|
||||
listed must be the one connected to the INT2 pin.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
accel@40 {
|
||||
compatible = "bosch,bma180";
|
||||
reg = <0x40>;
|
||||
interrupt-parent = <&gpio6>;
|
||||
interrupts = <18 (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -8,6 +8,7 @@ title: Bosch BMA255 and Similar Accelerometers
|
|||
|
||||
maintainers:
|
||||
- Linus Walleij <linus.walleij@linaro.org>
|
||||
- Stephan Gerhold <stephan@gerhold.net>
|
||||
|
||||
description:
|
||||
3 axis accelerometers with varying range and I2C or SPI
|
||||
|
@ -16,15 +17,24 @@ description:
|
|||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- bosch,bmc150_accel
|
||||
- bosch,bmi055_accel
|
||||
# bmc150-accel driver in Linux
|
||||
- bosch,bma222
|
||||
- bosch,bma222e
|
||||
- bosch,bma250e
|
||||
- bosch,bma253
|
||||
- bosch,bma254
|
||||
- bosch,bma255
|
||||
- bosch,bma250e
|
||||
- bosch,bma222
|
||||
- bosch,bma222e
|
||||
- bosch,bma280
|
||||
- bosch,bmc150_accel
|
||||
- bosch,bmc156_accel
|
||||
- bosch,bmi055_accel
|
||||
|
||||
# bma180 driver in Linux
|
||||
- bosch,bma023
|
||||
- bosch,bma150
|
||||
- bosch,bma180
|
||||
- bosch,bma250
|
||||
- bosch,smb380
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -36,9 +46,21 @@ properties:
|
|||
minItems: 1
|
||||
maxItems: 2
|
||||
description: |
|
||||
The first interrupt listed must be the one connected to the INT1 pin,
|
||||
the second (optional) interrupt listed must be the one connected to the
|
||||
INT2 pin (if available).
|
||||
Without interrupt-names, the first interrupt listed must be the one
|
||||
connected to the INT1 pin, the second (optional) interrupt listed must be
|
||||
the one connected to the INT2 pin (if available). The type should be
|
||||
IRQ_TYPE_EDGE_RISING.
|
||||
|
||||
BMC156 does not have an INT1 pin, therefore the first interrupt pin is
|
||||
always treated as INT2.
|
||||
|
||||
interrupt-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
enum:
|
||||
- INT1
|
||||
- INT2
|
||||
|
||||
mount-matrix:
|
||||
description: an optional 3x3 mounting rotation matrix.
|
||||
|
@ -63,7 +85,22 @@ examples:
|
|||
reg = <0x08>;
|
||||
vddio-supply = <&vddio>;
|
||||
vdd-supply = <&vdd>;
|
||||
interrupts = <57 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupts = <57 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "INT1";
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
accelerometer@10 {
|
||||
compatible = "bosch,bmc156_accel";
|
||||
reg = <0x10>;
|
||||
vddio-supply = <&vddio>;
|
||||
vdd-supply = <&vdd>;
|
||||
interrupts = <116 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "INT2";
|
||||
};
|
||||
};
|
||||
- |
|
||||
|
|
|
@ -23,6 +23,8 @@ properties:
|
|||
enum:
|
||||
- ingenic,jz4725b-adc
|
||||
- ingenic,jz4740-adc
|
||||
- ingenic,jz4760-adc
|
||||
- ingenic,jz4760b-adc
|
||||
- ingenic,jz4770-adc
|
||||
|
||||
'#io-channel-cells':
|
||||
|
@ -43,6 +45,23 @@ properties:
|
|||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
ingenic,use-internal-divider:
|
||||
description:
|
||||
If present, battery voltage is read from the VBAT_IR pin, which has an
|
||||
internal 1/4 divider. If absent, it is read through the VBAT_ER pin,
|
||||
which does not have such a divider.
|
||||
type: boolean
|
||||
|
||||
if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ingenic,jz4760b-adc
|
||||
then:
|
||||
properties:
|
||||
ingenic,use-internal-divider: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- '#io-channel-cells'
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/renesas,rzg2l-adc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas RZ/G2L ADC
|
||||
|
||||
maintainers:
|
||||
- Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
|
||||
|
||||
description: |
|
||||
A/D Converter block is a successive approximation analog-to-digital converter
|
||||
with a 12-bit accuracy. Up to eight analog input channels can be selected.
|
||||
Conversions can be performed in single or repeat mode. Result of the ADC is
|
||||
stored in a 32-bit data register corresponding to each channel.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r9a07g044-adc # RZ/G2{L,LC}
|
||||
- const: renesas,rzg2l-adc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: converter clock
|
||||
- description: peripheral clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: adclk
|
||||
- const: pclk
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: presetn
|
||||
- const: adrst-n
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- power-domains
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-7]$":
|
||||
$ref: "adc.yaml"
|
||||
type: object
|
||||
description: |
|
||||
Represents the external channels which are connected to the ADC.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: |
|
||||
The channel number. It can have up to 8 channels numbered from 0 to 7.
|
||||
items:
|
||||
- minimum: 0
|
||||
maximum: 7
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r9a07g044-cpg.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
adc: adc@10059000 {
|
||||
compatible = "renesas,r9a07g044-adc", "renesas,rzg2l-adc";
|
||||
reg = <0x10059000 0x400>;
|
||||
interrupts = <GIC_SPI 347 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&cpg CPG_MOD R9A07G044_ADC_ADCLK>,
|
||||
<&cpg CPG_MOD R9A07G044_ADC_PCLK>;
|
||||
clock-names = "adclk", "pclk";
|
||||
power-domains = <&cpg>;
|
||||
resets = <&cpg R9A07G044_ADC_PRESETN>,
|
||||
<&cpg R9A07G044_ADC_ADRST_N>;
|
||||
reset-names = "presetn", "adrst-n";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
channel@2 {
|
||||
reg = <2>;
|
||||
};
|
||||
channel@3 {
|
||||
reg = <3>;
|
||||
};
|
||||
channel@4 {
|
||||
reg = <4>;
|
||||
};
|
||||
channel@5 {
|
||||
reg = <5>;
|
||||
};
|
||||
channel@6 {
|
||||
reg = <6>;
|
||||
};
|
||||
channel@7 {
|
||||
reg = <7>;
|
||||
};
|
||||
};
|
|
@ -20,6 +20,7 @@ properties:
|
|||
- rockchip,px30-saradc
|
||||
- rockchip,rk3308-saradc
|
||||
- rockchip,rk3328-saradc
|
||||
- rockchip,rk3568-saradc
|
||||
- rockchip,rv1108-saradc
|
||||
- const: rockchip,rk3399-saradc
|
||||
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5064.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5064 and similar DACs
|
||||
|
||||
maintainers:
|
||||
- Lars-Peter Clausen <lars@metafoo.de>
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
description: |
|
||||
A range of similar DAC devices with between 1 and 12 channels. Some parts
|
||||
have internal references, others require a single shared external reference
|
||||
and the remainder have a separate reference pin for each DAC.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- description: I2C devics
|
||||
enum:
|
||||
- adi,ad5024
|
||||
- adi,ad5025
|
||||
- adi,ad5044
|
||||
- adi,ad5045
|
||||
- adi,ad5064
|
||||
- adi,ad5064-1
|
||||
- adi,ad5065
|
||||
- adi,ad5628-1
|
||||
- adi,ad5628-2
|
||||
- adi,ad5648-1
|
||||
- adi,ad5648-2
|
||||
- adi,ad5666-1
|
||||
- adi,ad5666-2
|
||||
- adi,ad5668-1
|
||||
- adi,ad5668-2
|
||||
- adi,ad5668-3
|
||||
- description: SPI devices
|
||||
enum:
|
||||
- adi,ad5625
|
||||
- adi,ad5625r-1v25
|
||||
- adi,ad5625r-2v5
|
||||
- adi,ad5627
|
||||
- adi,ad5627r-1v25
|
||||
- adi,ad5627r-2v5
|
||||
- adi,ad5629-1
|
||||
- adi,ad5629-2
|
||||
- adi,ad5629-3
|
||||
- adi,ad5645r-1v25
|
||||
- adi,ad5645r-2v5
|
||||
- adi,ad5665
|
||||
- adi,ad5665r-1v25
|
||||
- adi,ad5665r-2v5
|
||||
- adi,ad5667
|
||||
- adi,ad5667r-1v25
|
||||
- adi,ad5667r-2v5
|
||||
- adi,ad5669-1
|
||||
- adi,ad5669-2
|
||||
- adi,ad5669-3
|
||||
- lltc,ltc2606
|
||||
- lltc,ltc2607
|
||||
- lltc,ltc2609
|
||||
- lltc,ltc2616
|
||||
- lltc,ltc2617
|
||||
- lltc,ltc2619
|
||||
- lltc,ltc2626
|
||||
- lltc,ltc2627
|
||||
- lltc,ltc2629
|
||||
- lltc,ltc2631-l12
|
||||
- lltc,ltc2631-h12
|
||||
- lltc,ltc2631-l10
|
||||
- lltc,ltc2631-h10
|
||||
- lltc,ltc2631-l8
|
||||
- lltc,ltc2631-h8
|
||||
- lltc,ltc2633-l12
|
||||
- lltc,ltc2633-h12
|
||||
- lltc,ltc2633-l10
|
||||
- lltc,ltc2633-h10
|
||||
- lltc,ltc2633-l8
|
||||
- lltc,ltc2633-h8
|
||||
- lltc,ltc2635-l12
|
||||
- lltc,ltc2635-h12
|
||||
- lltc,ltc2635-l10
|
||||
- lltc,ltc2635-h10
|
||||
- lltc,ltc2635-l8
|
||||
- lltc,ltc2635-h8
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vrefA-supply: true
|
||||
vrefB-supply: true
|
||||
vrefC-supply: true
|
||||
vrefD-supply: true
|
||||
vref-supply: true
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- # Shared external vref, no internal reference
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad5064-1
|
||||
- adi,ad5625
|
||||
- adi,ad5627
|
||||
- adi,ad5665
|
||||
- adi,ad5667
|
||||
- lltc,ltc2606
|
||||
- lltc,ltc2607
|
||||
- lltc,ltc2616
|
||||
- lltc,ltc2617
|
||||
- lltc,ltc2626
|
||||
- lltc,ltc2627
|
||||
then:
|
||||
properties:
|
||||
vref-supply: true
|
||||
vrefA-supply: false
|
||||
vrefB-supply: false
|
||||
vrefC-supply: false
|
||||
vrefD-supply: false
|
||||
required:
|
||||
- vref-supply
|
||||
- # Shared external vref, internal reference available
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad5625r-1v25
|
||||
- adi,ad5625r-2v5
|
||||
- adi,ad5627r-1v25
|
||||
- adi,ad5627r-2v5
|
||||
- adi,ad5628-1
|
||||
- adi,ad5628-2
|
||||
- adi,ad5629-1
|
||||
- adi,ad5629-2
|
||||
- adi,ad5629-3
|
||||
- adi,ad5645r-1v25
|
||||
- adi,ad5645r-2v5
|
||||
- adi,ad5647r-1v25
|
||||
- adi,ad5647r-2v5
|
||||
- adi,ad5648-1
|
||||
- adi,ad5648-2
|
||||
- adi,ad5665r-1v25
|
||||
- adi,ad5665r-2v5
|
||||
- adi,ad5666-1
|
||||
- adi,ad5666-2
|
||||
- adi,ad5667r-1v25
|
||||
- adi,ad5667r-2v5
|
||||
- adi,ad5668-1
|
||||
- adi,ad5668-2
|
||||
- adi,ad5668-3
|
||||
- adi,ad5669-1
|
||||
- adi,ad5669-2
|
||||
- adi,ad5669-3
|
||||
- lltc,ltc2631-l12
|
||||
- lltc,ltc2631-h12
|
||||
- lltc,ltc2631-l10
|
||||
- lltc,ltc2631-h10
|
||||
- lltc,ltc2631-l8
|
||||
- lltc,ltc2631-h8
|
||||
- lltc,ltc2633-l12
|
||||
- lltc,ltc2633-h12
|
||||
- lltc,ltc2633-l10
|
||||
- lltc,ltc2633-h10
|
||||
- lltc,ltc2633-l8
|
||||
- lltc,ltc2633-h8
|
||||
- lltc,ltc2635-l12
|
||||
- lltc,ltc2635-h12
|
||||
- lltc,ltc2635-l10
|
||||
- lltc,ltc2635-h10
|
||||
- lltc,ltc2635-l8
|
||||
- lltc,ltc2635-h8
|
||||
then:
|
||||
properties:
|
||||
vref-supply: true
|
||||
vrefA-supply: false
|
||||
vrefB-supply: false
|
||||
vrefC-supply: false
|
||||
vrefD-supply: false
|
||||
- # 4 input devices, separate vrefs, no internal reference
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad5024
|
||||
- adi,ad5044
|
||||
- adi,ad5064
|
||||
- lltc,ltc2609
|
||||
- lltc,ltc2619
|
||||
- lltc,ltc2629
|
||||
then:
|
||||
properties:
|
||||
vrefA-supply: true
|
||||
vrefB-supply: true
|
||||
vrefC-supply: true
|
||||
vrefD-supply: true
|
||||
vref-supply: false
|
||||
required:
|
||||
- vrefA-supply
|
||||
- vrefB-supply
|
||||
- vrefC-supply
|
||||
- vrefD-supply
|
||||
- # 2 input devices, separate vrefs, no internal reference
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad5025
|
||||
- adi,ad5045
|
||||
- adi,ad5065
|
||||
then:
|
||||
properties:
|
||||
vrefA-supply: true
|
||||
vrefB-supply: true
|
||||
vrefC-supply: false
|
||||
vrefD-supply: false
|
||||
vref-supply: false
|
||||
required:
|
||||
- vrefA-supply
|
||||
- vrefB-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@0 {
|
||||
reg = <0>;
|
||||
compatible = "adi,ad5625";
|
||||
vref-supply = <&dac_vref>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@0 {
|
||||
reg = <0>;
|
||||
compatible = "adi,ad5625r-1v25";
|
||||
};
|
||||
};
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@42 {
|
||||
reg = <0x42>;
|
||||
compatible = "adi,ad5024";
|
||||
vrefA-supply = <&dac_vref>;
|
||||
vrefB-supply = <&dac_vref>;
|
||||
vrefC-supply = <&dac_vref2>;
|
||||
vrefD-supply = <&dac_vref2>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,79 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5360.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5360 and similar DACs
|
||||
|
||||
maintainers:
|
||||
- Lars-Peter Clausen <lars@metafoo.de>
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad5360
|
||||
- adi,ad5361
|
||||
- adi,ad5363
|
||||
- adi,ad5370
|
||||
- adi,ad5371
|
||||
- adi,ad5372
|
||||
- adi,ad5373
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vref0-supply: true
|
||||
vref1-supply: true
|
||||
vref2-supply: true
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vref0-supply
|
||||
- vref1-supply
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad5360
|
||||
- adi,ad5361
|
||||
- adi,ad5363
|
||||
- adi,ad5370
|
||||
- adi,ad5372
|
||||
- adi,ad5373
|
||||
then:
|
||||
properties:
|
||||
vref2-supply: false
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad5371
|
||||
then:
|
||||
required:
|
||||
- vref2-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@0 {
|
||||
reg = <0>;
|
||||
compatible = "adi,ad5371";
|
||||
vref0-supply = <&dac_vref0>;
|
||||
vref1-supply = <&dac_vref1>;
|
||||
vref2-supply = <&dac_vref2>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,70 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5380.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5380 and similar DACs
|
||||
|
||||
maintainers:
|
||||
- Lars-Peter Clausen <lars@metafoo.de>
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
description: |
|
||||
DAC devices supporting both SPI and I2C interfaces.
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad5380-3
|
||||
- adi,ad5380-5
|
||||
- adi,ad5381-3
|
||||
- adi,ad5381-5
|
||||
- adi,ad5382-3
|
||||
- adi,ad5382-5
|
||||
- adi,ad5383-3
|
||||
- adi,ad5383-5
|
||||
- adi,ad5384-3
|
||||
- adi,ad5384-5
|
||||
- adi,ad5390-3
|
||||
- adi,ad5390-5
|
||||
- adi,ad5391-3
|
||||
- adi,ad5391-5
|
||||
- adi,ad5392-3
|
||||
- adi,ad5392-5
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vref-supply:
|
||||
description:
|
||||
If not supplied devices will use internal regulators.
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@0 {
|
||||
reg = <0>;
|
||||
compatible = "adi,ad5390-5";
|
||||
vref-supply = <&dacvref>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@42 {
|
||||
reg = <0x42>;
|
||||
compatible = "adi,ad5380-3";
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,51 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5421.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5421 DAC
|
||||
|
||||
maintainers:
|
||||
- Lars-Peter Clausen <lars@metafoo.de>
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
description: |
|
||||
AD5421 is designed for us in loop-powered, 4 mA to 20 mA smart transmitter
|
||||
applications. It provides a 16-bit DAC, current amplifier, voltage regulator
|
||||
to drive the loop and a voltage reference.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: adi,ad5421
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description: Fault signal.
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
compatible = "adi,ad5421";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <30000000>;
|
||||
interrupts = <55 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,97 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5449.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5449 and similar DACs
|
||||
|
||||
maintainers:
|
||||
- Lars-Peter Clausen <lars@metafoo.de>
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
description:
|
||||
Family of multiplying DACs from Analog Devices
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad5415
|
||||
- adi,ad5426
|
||||
- adi,ad5429
|
||||
- adi,ad5432
|
||||
- adi,ad5439
|
||||
- adi,ad5443
|
||||
- adi,ad5449
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
VREF-supply: true
|
||||
VREFA-supply: true
|
||||
VREFB-supply: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad5415
|
||||
- adi,ad5426
|
||||
- adi,ad5432
|
||||
then:
|
||||
properties:
|
||||
VREF-supply: true
|
||||
VREFA-supply: false
|
||||
VREFB-supply: false
|
||||
required:
|
||||
- VREF-supply
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad5429
|
||||
- adi,ad5439
|
||||
- adi,ad5449
|
||||
then:
|
||||
properties:
|
||||
VREF-supply: false
|
||||
VREFA-supply: true
|
||||
VREFB-supply: true
|
||||
required:
|
||||
- VREFA-supply
|
||||
- VREFB-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@0 {
|
||||
reg = <0>;
|
||||
compatible = "adi,ad5415";
|
||||
VREF-supply = <&dac_ref>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@0 {
|
||||
reg = <0>;
|
||||
compatible = "adi,ad5429";
|
||||
VREFA-supply = <&dac_refA>;
|
||||
VREFB-supply = <&dac_refB>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,50 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5504.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5501 and AD5504 DACs
|
||||
|
||||
maintainers:
|
||||
- Lars-Peter Clausen <lars@metafoo.de>
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
description:
|
||||
High voltage (up to 60V) DACs with temperature sensor alarm function
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad5501
|
||||
- adi,ad5504
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description: Used for temperature alarm.
|
||||
maxItems: 1
|
||||
|
||||
vcc-supply: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@0 {
|
||||
reg = <0>;
|
||||
compatible = "adi,ad5504";
|
||||
vcc-supply = <&dac_vcc>;
|
||||
interrupts = <55 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,47 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5624r.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5624r and similar DACs
|
||||
|
||||
maintainers:
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad5624r3
|
||||
- adi,ad5644r3
|
||||
- adi,ad5664r3
|
||||
- adi,ad5624r5
|
||||
- adi,ad5644r5
|
||||
- adi,ad5664r5
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vref-supply:
|
||||
description: If not present, internal reference will be used.
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@0 {
|
||||
reg = <0>;
|
||||
compatible = "adi,ad5624r3";
|
||||
vref-supply = <&vref>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,75 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5686.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5360 and similar DACs
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- description: SPI devices
|
||||
enum:
|
||||
- adi,ad5310r
|
||||
- adi,ad5672r
|
||||
- adi,ad5674r
|
||||
- adi,ad5676
|
||||
- adi,ad5676r
|
||||
- adi,ad5679r
|
||||
- adi,ad5681r
|
||||
- adi,ad5682r
|
||||
- adi,ad5683
|
||||
- adi,ad5683r
|
||||
- adi,ad5684
|
||||
- adi,ad5684r
|
||||
- adi,ad5685r
|
||||
- adi,ad5686
|
||||
- adi,ad5686r
|
||||
- description: I2C devices
|
||||
enum:
|
||||
- adi,ad5311r
|
||||
- adi,ad5338r
|
||||
- adi,ad5671r
|
||||
- adi,ad5675r
|
||||
- adi,ad5691r
|
||||
- adi,ad5692r
|
||||
- adi,ad5693
|
||||
- adi,ad5693r
|
||||
- adi,ad5694
|
||||
- adi,ad5694r
|
||||
- adi,ad5695r
|
||||
- adi,ad5696
|
||||
- adi,ad5696r
|
||||
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vcc-supply:
|
||||
description: If not supplied the internal reference is used.
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dac@0 {
|
||||
reg = <0>;
|
||||
compatible = "adi,ad5310r";
|
||||
vcc-supply = <&dac_vref0>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,60 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5761.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5761 and similar DACs
|
||||
|
||||
maintainers:
|
||||
- Ricardo Ribalda <ribalda@kernel.org>
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
properties:
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad5721
|
||||
- adi,ad5721r
|
||||
- adi,ad5761
|
||||
- adi,ad5761r
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vref-supply:
|
||||
description: If not supplied, internal reference will be used.
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad5721
|
||||
- adi,ad5761
|
||||
then:
|
||||
required:
|
||||
- vref-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
compatible = "adi,ad5721";
|
||||
reg = <0>;
|
||||
vref-supply = <&dac_vref>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,62 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5764.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5744 and AD5764 DAC families
|
||||
|
||||
maintainers:
|
||||
- Lars-Peter Clausen <lars@metafoo.de>
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
properties:
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad5744
|
||||
- adi,ad5744r
|
||||
- adi,ad5764
|
||||
- adi,ad5764r
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vrefAB-supply: true
|
||||
vrefCD-supply: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad5744
|
||||
- adi,ad5764
|
||||
then:
|
||||
required:
|
||||
- vrefAB-supply
|
||||
- vrefCD-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
compatible = "adi,ad5744";
|
||||
reg = <0>;
|
||||
vrefAB-supply = <&dac_vref>;
|
||||
vrefCD-supply = <&dac_vref>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,52 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5791.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5791 and similar DACs
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
properties:
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad5760
|
||||
- adi,ad5780
|
||||
- adi,ad5781
|
||||
- adi,ad5790
|
||||
- adi,ad5791
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vdd-supply: true
|
||||
vss-supply: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
- vss-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
compatible = "adi,ad5791";
|
||||
reg = <0>;
|
||||
vss-supply = <&dac_vss>;
|
||||
vdd-supply = <&dac_vdd>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,60 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad8801.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD8801 and AD8803 DACs
|
||||
|
||||
maintainers:
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
properties:
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad8801
|
||||
- adi,ad8803
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vrefh-supply: true
|
||||
vrefl-supply: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vrefh-supply
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: adi,ad8803
|
||||
then:
|
||||
required:
|
||||
- vrefl-supply
|
||||
else:
|
||||
properties:
|
||||
vrefl-supply: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
compatible = "adi,ad8803";
|
||||
reg = <0>;
|
||||
vrefl-supply = <&dac_vrefl>;
|
||||
vrefh-supply = <&dac_vrefh>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,46 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/microchip,mcp4922.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip MCP4902, MCP4912 and MPC4922 dual output SPI DACs
|
||||
|
||||
maintainers:
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
- Michael Welling <mwelling@ieee.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- microchip,mcp4902
|
||||
- microchip,mcp4912
|
||||
- microchip,mcp4922
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vref-supply: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vref-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
compatible = "microchip,mcp4912";
|
||||
reg = <0>;
|
||||
vref-supply = <&dac_vref>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -34,13 +34,14 @@ properties:
|
|||
|
||||
interrupt-controller: true
|
||||
|
||||
gpios:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description: GPIO used for IRQs
|
||||
|
||||
regulators:
|
||||
type: object
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
@ -49,11 +50,13 @@ properties:
|
|||
const: 0
|
||||
|
||||
patternProperties:
|
||||
'^ldo[0-9]+@[0-9a-f]$':
|
||||
'^ldo[0-9]+$':
|
||||
type: object
|
||||
|
||||
$ref: "/schemas/regulator/regulator.yaml#"
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -63,69 +66,69 @@ additionalProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
/* pmic properties */
|
||||
|
||||
pmic: pmic@0 {
|
||||
compatible = "hisilicon,hi6421-spmi";
|
||||
compatible = "hisilicon,hi6421v600-spmi";
|
||||
reg = <0 0>;
|
||||
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-controller;
|
||||
gpios = <&gpio28 0 0>;
|
||||
interrupt-parent = <&gpio28>;
|
||||
interrupts = <0 0>;
|
||||
|
||||
regulators {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ldo3: LDO3 {
|
||||
ldo3: ldo3 {
|
||||
regulator-name = "ldo3";
|
||||
regulator-min-microvolt = <1500000>;
|
||||
regulator-max-microvolt = <2000000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
ldo4: LDO4 {
|
||||
ldo4: ldo4 {
|
||||
regulator-name = "ldo4";
|
||||
regulator-min-microvolt = <1725000>;
|
||||
regulator-max-microvolt = <1900000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
ldo9: LDO9 {
|
||||
ldo9: ldo9 {
|
||||
regulator-name = "ldo9";
|
||||
regulator-min-microvolt = <1750000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
ldo15: LDO15 {
|
||||
ldo15: ldo15 {
|
||||
regulator-name = "ldo15";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
ldo16: LDO16 {
|
||||
ldo16: ldo16 {
|
||||
regulator-name = "ldo16";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
ldo17: LDO17 {
|
||||
ldo17: ldo17 {
|
||||
regulator-name = "ldo17";
|
||||
regulator-min-microvolt = <2500000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
|
||||
ldo33: LDO33 {
|
||||
ldo33: ldo33 {
|
||||
regulator-name = "ldo33";
|
||||
regulator-min-microvolt = <2500000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
ldo34: LDO34 {
|
||||
ldo34: ldo34 {
|
||||
regulator-name = "ldo34";
|
||||
regulator-min-microvolt = <2600000>;
|
||||
regulator-max-microvolt = <3300000>;
|
|
@ -33,6 +33,8 @@ properties:
|
|||
- ad,ad7414
|
||||
# ADM9240: Complete System Hardware Monitor for uProcessor-Based Systems
|
||||
- ad,adm9240
|
||||
# AD5110 - Nonvolatile Digital Potentiometer
|
||||
- adi,ad5110
|
||||
# Analog Devices ADP5585 Keypad Decoder and I/O Expansion
|
||||
- adi,adp5585
|
||||
# Analog Devices ADP5585 Keypad Decoder and I/O Expansion with support for Row5
|
||||
|
@ -61,6 +63,8 @@ properties:
|
|||
- capella,cm32181
|
||||
# CM3232: Ambient Light Sensor
|
||||
- capella,cm3232
|
||||
# CM3323: Ambient Light Sensor
|
||||
- capella,cm3323
|
||||
# High-Precision Digital Thermometer
|
||||
- dallas,ds1631
|
||||
# Total-Elapsed-Time Recorder with Alarm
|
||||
|
@ -269,6 +273,8 @@ properties:
|
|||
- sensirion,sgpc3
|
||||
# Sensirion multi-pixel gas sensor with I2C interface
|
||||
- sensirion,sgp30
|
||||
# Sensirion gas sensor with I2C interface
|
||||
- sensirion,sgp40
|
||||
# Sensortek 3 axis accelerometer
|
||||
- sensortek,stk8312
|
||||
# Sensortek 3 axis accelerometer
|
||||
|
|
31
MAINTAINERS
31
MAINTAINERS
|
@ -459,6 +459,12 @@ S: Maintained
|
|||
W: https://parisc.wiki.kernel.org/index.php/AD1889
|
||||
F: sound/pci/ad1889.*
|
||||
|
||||
AD5110 ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
|
||||
M: Mugilraj Dhavachelvan <dmugil2000@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/iio/potentiometer/ad5110.c
|
||||
|
||||
AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
|
||||
M: Michael Hennerich <michael.hennerich@analog.com>
|
||||
S: Supported
|
||||
|
@ -8462,10 +8468,12 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
|
||||
F: drivers/spmi/hisi-spmi-controller.c
|
||||
|
||||
HISILICON STAGING DRIVERS FOR HIKEY 960/970
|
||||
HISILICON SPMI PMIC DRIVER FOR HIKEY 6421v600
|
||||
M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/staging/hikey9xx/
|
||||
F: Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
|
||||
F: drivers/mfd/hi6421-spmi-pmic.c
|
||||
|
||||
HISILICON TRUE RANDOM NUMBER GENERATOR V2 SUPPORT
|
||||
M: Zaibo Xu <xuzaibo@huawei.com>
|
||||
|
@ -15899,6 +15907,14 @@ L: linux-renesas-soc@vger.kernel.org
|
|||
S: Maintained
|
||||
F: drivers/phy/renesas/phy-rcar-gen3-usb*.c
|
||||
|
||||
RENESAS RZ/G2L A/D DRIVER
|
||||
M: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
L: linux-renesas-soc@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
|
||||
F: drivers/iio/adc/rzg2l_adc.c
|
||||
|
||||
RESET CONTROLLER FRAMEWORK
|
||||
M: Philipp Zabel <p.zabel@pengutronix.de>
|
||||
S: Maintained
|
||||
|
@ -16766,6 +16782,12 @@ F: drivers/iio/chemical/scd30_core.c
|
|||
F: drivers/iio/chemical/scd30_i2c.c
|
||||
F: drivers/iio/chemical/scd30_serial.c
|
||||
|
||||
SENSIRION SGP40 GAS SENSOR DRIVER
|
||||
M: Andreas Klinger <ak@it-klinger.de>
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-bus-iio-chemical-sgp40
|
||||
F: drivers/iio/chemical/sgp40.c
|
||||
|
||||
SENSIRION SPS30 AIR POLLUTION SENSOR DRIVER
|
||||
M: Tomasz Duszynski <tduszyns@gmail.com>
|
||||
S: Maintained
|
||||
|
@ -17670,8 +17692,9 @@ F: drivers/staging/olpc_dcon/
|
|||
|
||||
STAGING - REALTEK RTL8188EU DRIVERS
|
||||
M: Larry Finger <Larry.Finger@lwfinger.net>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/rtl8188eu/
|
||||
M: Phillip Potter <phil@philpotter.co.uk>
|
||||
S: Supported
|
||||
F: drivers/staging/r8188eu/
|
||||
|
||||
STAGING - REALTEK RTL8712U DRIVERS
|
||||
M: Larry Finger <Larry.Finger@lwfinger.net>
|
||||
|
|
|
@ -28,6 +28,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
|
|||
|
||||
/**
|
||||
* struct quad8 - device private data structure
|
||||
* @lock: lock to prevent clobbering device states during R/W ops
|
||||
* @counter: instance of the counter_device
|
||||
* @fck_prescaler: array of filter clock prescaler configurations
|
||||
* @preset: array of preset values
|
||||
|
@ -97,7 +98,8 @@ struct quad8 {
|
|||
#define QUAD8_CMR_QUADRATURE_X4 0x18
|
||||
|
||||
static int quad8_signal_read(struct counter_device *counter,
|
||||
struct counter_signal *signal, enum counter_signal_value *val)
|
||||
struct counter_signal *signal,
|
||||
enum counter_signal_level *level)
|
||||
{
|
||||
const struct quad8 *const priv = counter->priv;
|
||||
unsigned int state;
|
||||
|
@ -109,7 +111,7 @@ static int quad8_signal_read(struct counter_device *counter,
|
|||
state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS)
|
||||
& BIT(signal->id - 16);
|
||||
|
||||
*val = (state) ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
|
||||
*level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -154,7 +156,7 @@ static int quad8_count_write(struct counter_device *counter,
|
|||
|
||||
/* Only 24-bit values are supported */
|
||||
if (val > 0xFFFFFF)
|
||||
return -EINVAL;
|
||||
return -ERANGE;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
|
@ -193,11 +195,11 @@ enum quad8_count_function {
|
|||
QUAD8_COUNT_FUNCTION_QUADRATURE_X4
|
||||
};
|
||||
|
||||
static const enum counter_count_function quad8_count_functions_list[] = {
|
||||
[QUAD8_COUNT_FUNCTION_PULSE_DIRECTION] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION,
|
||||
[QUAD8_COUNT_FUNCTION_QUADRATURE_X1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A,
|
||||
[QUAD8_COUNT_FUNCTION_QUADRATURE_X2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
|
||||
[QUAD8_COUNT_FUNCTION_QUADRATURE_X4] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4
|
||||
static const enum counter_function quad8_count_functions_list[] = {
|
||||
[QUAD8_COUNT_FUNCTION_PULSE_DIRECTION] = COUNTER_FUNCTION_PULSE_DIRECTION,
|
||||
[QUAD8_COUNT_FUNCTION_QUADRATURE_X1] = COUNTER_FUNCTION_QUADRATURE_X1_A,
|
||||
[QUAD8_COUNT_FUNCTION_QUADRATURE_X2] = COUNTER_FUNCTION_QUADRATURE_X2_A,
|
||||
[QUAD8_COUNT_FUNCTION_QUADRATURE_X4] = COUNTER_FUNCTION_QUADRATURE_X4
|
||||
};
|
||||
|
||||
static int quad8_function_get(struct counter_device *counter,
|
||||
|
@ -273,6 +275,10 @@ static int quad8_function_set(struct counter_device *counter,
|
|||
*scale = 2;
|
||||
mode_cfg |= QUAD8_CMR_QUADRATURE_X4;
|
||||
break;
|
||||
default:
|
||||
/* should never reach this path */
|
||||
mutex_unlock(&priv->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,7 +355,7 @@ static int quad8_action_get(struct counter_device *counter,
|
|||
case QUAD8_COUNT_FUNCTION_PULSE_DIRECTION:
|
||||
if (synapse->signal->id == signal_a_id)
|
||||
*action = QUAD8_SYNAPSE_ACTION_RISING_EDGE;
|
||||
break;
|
||||
return 0;
|
||||
case QUAD8_COUNT_FUNCTION_QUADRATURE_X1:
|
||||
if (synapse->signal->id == signal_a_id) {
|
||||
quad8_direction_get(counter, count, &direction);
|
||||
|
@ -359,17 +365,18 @@ static int quad8_action_get(struct counter_device *counter,
|
|||
else
|
||||
*action = QUAD8_SYNAPSE_ACTION_FALLING_EDGE;
|
||||
}
|
||||
break;
|
||||
return 0;
|
||||
case QUAD8_COUNT_FUNCTION_QUADRATURE_X2:
|
||||
if (synapse->signal->id == signal_a_id)
|
||||
*action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES;
|
||||
break;
|
||||
return 0;
|
||||
case QUAD8_COUNT_FUNCTION_QUADRATURE_X4:
|
||||
*action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES;
|
||||
break;
|
||||
return 0;
|
||||
default:
|
||||
/* should never reach this path */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct counter_ops quad8_ops = {
|
||||
|
@ -529,6 +536,9 @@ static int quad8_count_mode_set(struct counter_device *counter,
|
|||
case COUNTER_COUNT_MODE_MODULO_N:
|
||||
cnt_mode = 3;
|
||||
break;
|
||||
default:
|
||||
/* should never reach this path */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
@ -661,7 +671,7 @@ static ssize_t quad8_count_preset_write(struct counter_device *counter,
|
|||
|
||||
/* Only 24-bit values are supported */
|
||||
if (preset > 0xFFFFFF)
|
||||
return -EINVAL;
|
||||
return -ERANGE;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
|
@ -706,7 +716,7 @@ static ssize_t quad8_count_ceiling_write(struct counter_device *counter,
|
|||
|
||||
/* Only 24-bit values are supported */
|
||||
if (ceiling > 0xFFFFFF)
|
||||
return -EINVAL;
|
||||
return -ERANGE;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
|
@ -715,12 +725,13 @@ static ssize_t quad8_count_ceiling_write(struct counter_device *counter,
|
|||
case 1:
|
||||
case 3:
|
||||
quad8_preset_register_set(priv, count->id, ceiling);
|
||||
break;
|
||||
mutex_unlock(&priv->lock);
|
||||
return len;
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
return len;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static ssize_t quad8_count_preset_enable_read(struct counter_device *counter,
|
||||
|
|
|
@ -289,9 +289,9 @@ struct counter_signal_unit {
|
|||
struct counter_signal *signal;
|
||||
};
|
||||
|
||||
static const char *const counter_signal_value_str[] = {
|
||||
[COUNTER_SIGNAL_LOW] = "low",
|
||||
[COUNTER_SIGNAL_HIGH] = "high"
|
||||
static const char *const counter_signal_level_str[] = {
|
||||
[COUNTER_SIGNAL_LEVEL_LOW] = "low",
|
||||
[COUNTER_SIGNAL_LEVEL_HIGH] = "high"
|
||||
};
|
||||
|
||||
static ssize_t counter_signal_show(struct device *dev,
|
||||
|
@ -302,13 +302,13 @@ static ssize_t counter_signal_show(struct device *dev,
|
|||
const struct counter_signal_unit *const component = devattr->component;
|
||||
struct counter_signal *const signal = component->signal;
|
||||
int err;
|
||||
enum counter_signal_value val;
|
||||
enum counter_signal_level level;
|
||||
|
||||
err = counter->ops->signal_read(counter, signal, &val);
|
||||
err = counter->ops->signal_read(counter, signal, &level);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return sprintf(buf, "%s\n", counter_signal_value_str[val]);
|
||||
return sprintf(buf, "%s\n", counter_signal_level_str[level]);
|
||||
}
|
||||
|
||||
struct counter_name_unit {
|
||||
|
@ -744,15 +744,15 @@ static ssize_t counter_count_store(struct device *dev,
|
|||
return len;
|
||||
}
|
||||
|
||||
static const char *const counter_count_function_str[] = {
|
||||
[COUNTER_COUNT_FUNCTION_INCREASE] = "increase",
|
||||
[COUNTER_COUNT_FUNCTION_DECREASE] = "decrease",
|
||||
[COUNTER_COUNT_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
|
||||
[COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
|
||||
[COUNTER_COUNT_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
|
||||
[COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
|
||||
[COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
|
||||
[COUNTER_COUNT_FUNCTION_QUADRATURE_X4] = "quadrature x4"
|
||||
static const char *const counter_function_str[] = {
|
||||
[COUNTER_FUNCTION_INCREASE] = "increase",
|
||||
[COUNTER_FUNCTION_DECREASE] = "decrease",
|
||||
[COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
|
||||
[COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
|
||||
[COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
|
||||
[COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
|
||||
[COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
|
||||
[COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4"
|
||||
};
|
||||
|
||||
static ssize_t counter_function_show(struct device *dev,
|
||||
|
@ -764,7 +764,7 @@ static ssize_t counter_function_show(struct device *dev,
|
|||
const struct counter_count_unit *const component = devattr->component;
|
||||
struct counter_count *const count = component->count;
|
||||
size_t func_index;
|
||||
enum counter_count_function function;
|
||||
enum counter_function function;
|
||||
|
||||
err = counter->ops->function_get(counter, count, &func_index);
|
||||
if (err)
|
||||
|
@ -773,7 +773,7 @@ static ssize_t counter_function_show(struct device *dev,
|
|||
count->function = func_index;
|
||||
|
||||
function = count->functions_list[func_index];
|
||||
return sprintf(buf, "%s\n", counter_count_function_str[function]);
|
||||
return sprintf(buf, "%s\n", counter_function_str[function]);
|
||||
}
|
||||
|
||||
static ssize_t counter_function_store(struct device *dev,
|
||||
|
@ -785,14 +785,14 @@ static ssize_t counter_function_store(struct device *dev,
|
|||
struct counter_count *const count = component->count;
|
||||
const size_t num_functions = count->num_functions;
|
||||
size_t func_index;
|
||||
enum counter_count_function function;
|
||||
enum counter_function function;
|
||||
int err;
|
||||
struct counter_device *const counter = dev_get_drvdata(dev);
|
||||
|
||||
/* Find requested Count function mode */
|
||||
for (func_index = 0; func_index < num_functions; func_index++) {
|
||||
function = count->functions_list[func_index];
|
||||
if (sysfs_streq(buf, counter_count_function_str[function]))
|
||||
if (sysfs_streq(buf, counter_function_str[function]))
|
||||
break;
|
||||
}
|
||||
/* Return error if requested Count function mode not found */
|
||||
|
@ -880,25 +880,25 @@ err_free_attr_list:
|
|||
}
|
||||
|
||||
struct counter_func_avail_unit {
|
||||
const enum counter_count_function *functions_list;
|
||||
const enum counter_function *functions_list;
|
||||
size_t num_functions;
|
||||
};
|
||||
|
||||
static ssize_t counter_count_function_available_show(struct device *dev,
|
||||
static ssize_t counter_function_available_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct counter_device_attr *const devattr = to_counter_attr(attr);
|
||||
const struct counter_func_avail_unit *const component = devattr->component;
|
||||
const enum counter_count_function *const func_list = component->functions_list;
|
||||
const enum counter_function *const func_list = component->functions_list;
|
||||
const size_t num_functions = component->num_functions;
|
||||
size_t i;
|
||||
enum counter_count_function function;
|
||||
enum counter_function function;
|
||||
ssize_t len = 0;
|
||||
|
||||
for (i = 0; i < num_functions; i++) {
|
||||
function = func_list[i];
|
||||
len += sprintf(buf + len, "%s\n",
|
||||
counter_count_function_str[function]);
|
||||
counter_function_str[function]);
|
||||
}
|
||||
|
||||
return len;
|
||||
|
@ -968,7 +968,7 @@ static int counter_count_attributes_create(
|
|||
parm.group = group;
|
||||
parm.prefix = "";
|
||||
parm.name = "function_available";
|
||||
parm.show = counter_count_function_available_show;
|
||||
parm.show = counter_function_available_show;
|
||||
parm.store = NULL;
|
||||
parm.component = avail_comp;
|
||||
err = counter_attribute_create(&parm);
|
||||
|
|
|
@ -171,9 +171,8 @@ enum ftm_quaddec_count_function {
|
|||
FTM_QUADDEC_COUNT_ENCODER_MODE_1,
|
||||
};
|
||||
|
||||
static const enum counter_count_function ftm_quaddec_count_functions[] = {
|
||||
[FTM_QUADDEC_COUNT_ENCODER_MODE_1] =
|
||||
COUNTER_COUNT_FUNCTION_QUADRATURE_X4
|
||||
static const enum counter_function ftm_quaddec_count_functions[] = {
|
||||
[FTM_QUADDEC_COUNT_ENCODER_MODE_1] = COUNTER_FUNCTION_QUADRATURE_X4
|
||||
};
|
||||
|
||||
static int ftm_quaddec_count_read(struct counter_device *counter,
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
* Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
||||
* Author: Raymond Tan <raymond.tan@intel.com>
|
||||
*/
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/counter.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -127,8 +126,8 @@ static int intel_qep_count_read(struct counter_device *counter,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const enum counter_count_function intel_qep_count_functions[] = {
|
||||
COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
|
||||
static const enum counter_function intel_qep_count_functions[] = {
|
||||
COUNTER_FUNCTION_QUADRATURE_X4,
|
||||
};
|
||||
|
||||
static int intel_qep_function_get(struct counter_device *counter,
|
||||
|
@ -320,7 +319,7 @@ static ssize_t spike_filter_ns_write(struct counter_device *counter,
|
|||
}
|
||||
|
||||
if (length > INTEL_QEPFLT_MAX_COUNT(length))
|
||||
return -EINVAL;
|
||||
return -ERANGE;
|
||||
|
||||
mutex_lock(&qep->lock);
|
||||
if (qep->enabled) {
|
||||
|
|
|
@ -107,13 +107,16 @@ static int interrupt_cnt_write(struct counter_device *counter,
|
|||
{
|
||||
struct interrupt_cnt_priv *priv = counter->priv;
|
||||
|
||||
if (val != (typeof(priv->count.counter))val)
|
||||
return -ERANGE;
|
||||
|
||||
atomic_set(&priv->count, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const enum counter_count_function interrupt_cnt_functions[] = {
|
||||
COUNTER_COUNT_FUNCTION_INCREASE,
|
||||
static const enum counter_function interrupt_cnt_functions[] = {
|
||||
COUNTER_FUNCTION_INCREASE,
|
||||
};
|
||||
|
||||
static int interrupt_cnt_function_get(struct counter_device *counter,
|
||||
|
@ -127,7 +130,7 @@ static int interrupt_cnt_function_get(struct counter_device *counter,
|
|||
|
||||
static int interrupt_cnt_signal_read(struct counter_device *counter,
|
||||
struct counter_signal *signal,
|
||||
enum counter_signal_value *val)
|
||||
enum counter_signal_level *level)
|
||||
{
|
||||
struct interrupt_cnt_priv *priv = counter->priv;
|
||||
int ret;
|
||||
|
@ -139,7 +142,7 @@ static int interrupt_cnt_signal_read(struct counter_device *counter,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = ret ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
|
||||
*level = ret ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -37,9 +37,9 @@ enum mchp_tc_count_function {
|
|||
MCHP_TC_FUNCTION_QUADRATURE,
|
||||
};
|
||||
|
||||
static const enum counter_count_function mchp_tc_count_functions[] = {
|
||||
[MCHP_TC_FUNCTION_INCREASE] = COUNTER_COUNT_FUNCTION_INCREASE,
|
||||
[MCHP_TC_FUNCTION_QUADRATURE] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
|
||||
static const enum counter_function mchp_tc_count_functions[] = {
|
||||
[MCHP_TC_FUNCTION_INCREASE] = COUNTER_FUNCTION_INCREASE,
|
||||
[MCHP_TC_FUNCTION_QUADRATURE] = COUNTER_FUNCTION_QUADRATURE_X4,
|
||||
};
|
||||
|
||||
enum mchp_tc_synapse_action {
|
||||
|
@ -133,6 +133,9 @@ static int mchp_tc_count_function_set(struct counter_device *counter,
|
|||
bmr |= ATMEL_TC_QDEN | ATMEL_TC_POSEN;
|
||||
cmr |= ATMEL_TC_ETRGEDG_RISING | ATMEL_TC_ABETRG | ATMEL_TC_XC0;
|
||||
break;
|
||||
default:
|
||||
/* should never reach this path */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_write(priv->regmap, ATMEL_TC_BMR, bmr);
|
||||
|
@ -155,7 +158,7 @@ static int mchp_tc_count_function_set(struct counter_device *counter,
|
|||
|
||||
static int mchp_tc_count_signal_read(struct counter_device *counter,
|
||||
struct counter_signal *signal,
|
||||
enum counter_signal_value *val)
|
||||
enum counter_signal_level *lvl)
|
||||
{
|
||||
struct mchp_tc_data *const priv = counter->priv;
|
||||
bool sigstatus;
|
||||
|
@ -168,7 +171,7 @@ static int mchp_tc_count_signal_read(struct counter_device *counter,
|
|||
else
|
||||
sigstatus = (sr & ATMEL_TC_MTIOA);
|
||||
|
||||
*val = sigstatus ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
|
||||
*lvl = sigstatus ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -226,6 +229,9 @@ static int mchp_tc_count_action_set(struct counter_device *counter,
|
|||
case MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE:
|
||||
edge = ATMEL_TC_ETRGEDG_BOTH;
|
||||
break;
|
||||
default:
|
||||
/* should never reach this path */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_write_bits(priv->regmap,
|
||||
|
|
|
@ -134,9 +134,9 @@ enum stm32_lptim_cnt_function {
|
|||
STM32_LPTIM_ENCODER_BOTH_EDGE,
|
||||
};
|
||||
|
||||
static const enum counter_count_function stm32_lptim_cnt_functions[] = {
|
||||
[STM32_LPTIM_COUNTER_INCREASE] = COUNTER_COUNT_FUNCTION_INCREASE,
|
||||
[STM32_LPTIM_ENCODER_BOTH_EDGE] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
|
||||
static const enum counter_function stm32_lptim_cnt_functions[] = {
|
||||
[STM32_LPTIM_COUNTER_INCREASE] = COUNTER_FUNCTION_INCREASE,
|
||||
[STM32_LPTIM_ENCODER_BOTH_EDGE] = COUNTER_FUNCTION_QUADRATURE_X4,
|
||||
};
|
||||
|
||||
enum stm32_lptim_synapse_action {
|
||||
|
@ -206,9 +206,10 @@ static int stm32_lptim_cnt_function_set(struct counter_device *counter,
|
|||
priv->quadrature_mode = 1;
|
||||
priv->polarity = STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES;
|
||||
return 0;
|
||||
default:
|
||||
/* should never reach this path */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static ssize_t stm32_lptim_cnt_enable_read(struct counter_device *counter,
|
||||
|
@ -282,7 +283,7 @@ static ssize_t stm32_lptim_cnt_ceiling_write(struct counter_device *counter,
|
|||
return ret;
|
||||
|
||||
if (ceiling > STM32_LPTIM_MAX_ARR)
|
||||
return -EINVAL;
|
||||
return -ERANGE;
|
||||
|
||||
priv->ceiling = ceiling;
|
||||
|
||||
|
@ -326,9 +327,10 @@ static int stm32_lptim_cnt_action_get(struct counter_device *counter,
|
|||
case STM32_LPTIM_ENCODER_BOTH_EDGE:
|
||||
*action = priv->polarity;
|
||||
return 0;
|
||||
default:
|
||||
/* should never reach this path */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int stm32_lptim_cnt_action_set(struct counter_device *counter,
|
||||
|
|
|
@ -50,11 +50,11 @@ enum stm32_count_function {
|
|||
STM32_COUNT_ENCODER_MODE_3,
|
||||
};
|
||||
|
||||
static const enum counter_count_function stm32_count_functions[] = {
|
||||
[STM32_COUNT_SLAVE_MODE_DISABLED] = COUNTER_COUNT_FUNCTION_INCREASE,
|
||||
[STM32_COUNT_ENCODER_MODE_1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
|
||||
[STM32_COUNT_ENCODER_MODE_2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B,
|
||||
[STM32_COUNT_ENCODER_MODE_3] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
|
||||
static const enum counter_function stm32_count_functions[] = {
|
||||
[STM32_COUNT_SLAVE_MODE_DISABLED] = COUNTER_FUNCTION_INCREASE,
|
||||
[STM32_COUNT_ENCODER_MODE_1] = COUNTER_FUNCTION_QUADRATURE_X2_A,
|
||||
[STM32_COUNT_ENCODER_MODE_2] = COUNTER_FUNCTION_QUADRATURE_X2_B,
|
||||
[STM32_COUNT_ENCODER_MODE_3] = COUNTER_FUNCTION_QUADRATURE_X4,
|
||||
};
|
||||
|
||||
static int stm32_count_read(struct counter_device *counter,
|
||||
|
|
|
@ -157,7 +157,7 @@ static int ti_eqep_action_get(struct counter_device *counter,
|
|||
* QEPA and QEPB trigger QCLK.
|
||||
*/
|
||||
*action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;
|
||||
break;
|
||||
return 0;
|
||||
case TI_EQEP_COUNT_FUNC_DIR_COUNT:
|
||||
/* In direction-count mode only rising edge of QEPA is counted
|
||||
* and QEPB gives direction.
|
||||
|
@ -165,12 +165,14 @@ static int ti_eqep_action_get(struct counter_device *counter,
|
|||
switch (synapse->signal->id) {
|
||||
case TI_EQEP_SIGNAL_QEPA:
|
||||
*action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
case TI_EQEP_SIGNAL_QEPB:
|
||||
*action = TI_EQEP_SYNAPSE_ACTION_NONE;
|
||||
break;
|
||||
return 0;
|
||||
default:
|
||||
/* should never reach this path */
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case TI_EQEP_COUNT_FUNC_UP_COUNT:
|
||||
case TI_EQEP_COUNT_FUNC_DOWN_COUNT:
|
||||
/* In up/down-count modes only QEPA is counted and QEPB is not
|
||||
|
@ -186,15 +188,18 @@ static int ti_eqep_action_get(struct counter_device *counter,
|
|||
*action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;
|
||||
else
|
||||
*action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
case TI_EQEP_SIGNAL_QEPB:
|
||||
*action = TI_EQEP_SYNAPSE_ACTION_NONE;
|
||||
break;
|
||||
return 0;
|
||||
default:
|
||||
/* should never reach this path */
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* should never reach this path */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct counter_ops ti_eqep_counter_ops = {
|
||||
|
@ -289,11 +294,11 @@ static struct counter_signal ti_eqep_signals[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const enum counter_count_function ti_eqep_position_functions[] = {
|
||||
[TI_EQEP_COUNT_FUNC_QUAD_COUNT] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
|
||||
[TI_EQEP_COUNT_FUNC_DIR_COUNT] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION,
|
||||
[TI_EQEP_COUNT_FUNC_UP_COUNT] = COUNTER_COUNT_FUNCTION_INCREASE,
|
||||
[TI_EQEP_COUNT_FUNC_DOWN_COUNT] = COUNTER_COUNT_FUNCTION_DECREASE,
|
||||
static const enum counter_function ti_eqep_position_functions[] = {
|
||||
[TI_EQEP_COUNT_FUNC_QUAD_COUNT] = COUNTER_FUNCTION_QUADRATURE_X4,
|
||||
[TI_EQEP_COUNT_FUNC_DIR_COUNT] = COUNTER_FUNCTION_PULSE_DIRECTION,
|
||||
[TI_EQEP_COUNT_FUNC_UP_COUNT] = COUNTER_FUNCTION_INCREASE,
|
||||
[TI_EQEP_COUNT_FUNC_DOWN_COUNT] = COUNTER_FUNCTION_DECREASE,
|
||||
};
|
||||
|
||||
static const enum counter_synapse_action ti_eqep_position_synapse_actions[] = {
|
||||
|
|
|
@ -143,10 +143,11 @@ config BMC150_ACCEL
|
|||
select BMC150_ACCEL_SPI if SPI
|
||||
help
|
||||
Say yes here to build support for the following Bosch accelerometers:
|
||||
BMA222, BMA222E, BMA250E, BMA253, BMA254, BMA255, BMA280, BMC150, BMI055.
|
||||
BMA222, BMA222E, BMA250E, BMA253, BMA254, BMA255, BMA280, BMC150, BMC156
|
||||
BMI055.
|
||||
|
||||
Note that some of these are combo modules:
|
||||
- BMC150: accelerometer and magnetometer
|
||||
- BMC150/BMC156: accelerometer and magnetometer
|
||||
- BMI055: accelerometer and gyroscope
|
||||
|
||||
This driver is only implementing accelerometer part, which has
|
||||
|
|
|
@ -15,6 +15,5 @@ enum adxl345_device_type {
|
|||
|
||||
int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adxl345_device_type type, const char *name);
|
||||
int adxl345_core_remove(struct device *dev);
|
||||
|
||||
#endif /* _ADXL345_H_ */
|
||||
|
|
|
@ -208,6 +208,11 @@ static const struct iio_info adxl345_info = {
|
|||
.write_raw_get_fmt = adxl345_write_raw_get_fmt,
|
||||
};
|
||||
|
||||
static void adxl345_powerdown(void *regmap)
|
||||
{
|
||||
regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY);
|
||||
}
|
||||
|
||||
int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adxl345_device_type type, const char *name)
|
||||
{
|
||||
|
@ -233,7 +238,6 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
|||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
dev_set_drvdata(dev, indio_dev);
|
||||
data->regmap = regmap;
|
||||
data->type = type;
|
||||
/* Enable full-resolution mode */
|
||||
|
@ -260,29 +264,14 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "iio_device_register failed: %d\n", ret);
|
||||
regmap_write(data->regmap, ADXL345_REG_POWER_CTL,
|
||||
ADXL345_POWER_CTL_STANDBY);
|
||||
}
|
||||
ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adxl345_core_probe);
|
||||
|
||||
int adxl345_core_remove(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct adxl345_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
return regmap_write(data->regmap, ADXL345_REG_POWER_CTL,
|
||||
ADXL345_POWER_CTL_STANDBY);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adxl345_core_remove);
|
||||
|
||||
MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>");
|
||||
MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -38,11 +38,6 @@ static int adxl345_i2c_probe(struct i2c_client *client,
|
|||
id->name);
|
||||
}
|
||||
|
||||
static int adxl345_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
return adxl345_core_remove(&client->dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adxl345_i2c_id[] = {
|
||||
{ "adxl345", ADXL345 },
|
||||
{ "adxl375", ADXL375 },
|
||||
|
@ -65,7 +60,6 @@ static struct i2c_driver adxl345_i2c_driver = {
|
|||
.of_match_table = adxl345_of_match,
|
||||
},
|
||||
.probe = adxl345_i2c_probe,
|
||||
.remove = adxl345_i2c_remove,
|
||||
.id_table = adxl345_i2c_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -42,11 +42,6 @@ static int adxl345_spi_probe(struct spi_device *spi)
|
|||
return adxl345_core_probe(&spi->dev, regmap, id->driver_data, id->name);
|
||||
}
|
||||
|
||||
static int adxl345_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
return adxl345_core_remove(&spi->dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id adxl345_spi_id[] = {
|
||||
{ "adxl345", ADXL345 },
|
||||
{ "adxl375", ADXL375 },
|
||||
|
@ -69,7 +64,6 @@ static struct spi_driver adxl345_spi_driver = {
|
|||
.of_match_table = adxl345_of_match,
|
||||
},
|
||||
.probe = adxl345_spi_probe,
|
||||
.remove = adxl345_spi_remove,
|
||||
.id_table = adxl345_spi_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -218,20 +218,33 @@ static int bma220_init(struct spi_device *spi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bma220_deinit(struct spi_device *spi)
|
||||
static int bma220_power(struct spi_device *spi, bool up)
|
||||
{
|
||||
int ret;
|
||||
int i, ret;
|
||||
|
||||
/* Make sure the chip is powered off */
|
||||
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
|
||||
if (ret == BMA220_SUSPEND_SLEEP)
|
||||
/**
|
||||
* The chip can be suspended/woken up by a simple register read.
|
||||
* So, we need up to 2 register reads of the suspend register
|
||||
* to make sure that the device is in the desired state.
|
||||
*/
|
||||
for (i = 0; i < 2; i++) {
|
||||
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret == BMA220_SUSPEND_SLEEP)
|
||||
return -EBUSY;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
if (up && ret == BMA220_SUSPEND_SLEEP)
|
||||
return 0;
|
||||
|
||||
if (!up && ret == BMA220_SUSPEND_WAKE)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static void bma220_deinit(void *spi)
|
||||
{
|
||||
bma220_power(spi, false);
|
||||
}
|
||||
|
||||
static int bma220_probe(struct spi_device *spi)
|
||||
|
@ -248,7 +261,6 @@ static int bma220_probe(struct spi_device *spi)
|
|||
|
||||
data = iio_priv(indio_dev);
|
||||
data->spi_device = spi;
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->info = &bma220_info;
|
||||
|
@ -262,49 +274,33 @@ static int bma220_probe(struct spi_device *spi)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
|
||||
bma220_trigger_handler, NULL);
|
||||
ret = devm_add_action_or_reset(&spi->dev, bma220_deinit, spi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
bma220_trigger_handler, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "iio triggered buffer setup failed\n");
|
||||
goto err_suspend;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "iio_device_register failed\n");
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
goto err_suspend;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_suspend:
|
||||
return bma220_deinit(spi);
|
||||
}
|
||||
|
||||
static int bma220_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
return bma220_deinit(spi);
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static __maybe_unused int bma220_suspend(struct device *dev)
|
||||
{
|
||||
struct bma220_data *data = iio_priv(dev_get_drvdata(dev));
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
/* The chip can be suspended/woken up by a simple register read. */
|
||||
return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
|
||||
return bma220_power(spi, false);
|
||||
}
|
||||
|
||||
static __maybe_unused int bma220_resume(struct device *dev)
|
||||
{
|
||||
struct bma220_data *data = iio_priv(dev_get_drvdata(dev));
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
|
||||
return bma220_power(spi, true);
|
||||
}
|
||||
static SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume);
|
||||
|
||||
|
@ -326,7 +322,6 @@ static struct spi_driver bma220_driver = {
|
|||
.acpi_match_table = bma220_acpi_id,
|
||||
},
|
||||
.probe = bma220_probe,
|
||||
.remove = bma220_remove,
|
||||
.id_table = bma220_spi_id,
|
||||
};
|
||||
module_spi_driver(bma220_driver);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
@ -57,12 +58,18 @@
|
|||
#define BMC150_ACCEL_RESET_VAL 0xB6
|
||||
|
||||
#define BMC150_ACCEL_REG_INT_MAP_0 0x19
|
||||
#define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE BIT(2)
|
||||
#define BMC150_ACCEL_INT_MAP_0_BIT_INT1_SLOPE BIT(2)
|
||||
|
||||
#define BMC150_ACCEL_REG_INT_MAP_1 0x1A
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_DATA BIT(0)
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_FWM BIT(1)
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL BIT(2)
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_DATA BIT(0)
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_FWM BIT(1)
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_FFULL BIT(2)
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_FFULL BIT(5)
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_FWM BIT(6)
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_DATA BIT(7)
|
||||
|
||||
#define BMC150_ACCEL_REG_INT_MAP_2 0x1B
|
||||
#define BMC150_ACCEL_INT_MAP_2_BIT_INT2_SLOPE BIT(2)
|
||||
|
||||
#define BMC150_ACCEL_REG_INT_RST_LATCH 0x21
|
||||
#define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80
|
||||
|
@ -81,6 +88,7 @@
|
|||
|
||||
#define BMC150_ACCEL_REG_INT_OUT_CTRL 0x20
|
||||
#define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0)
|
||||
#define BMC150_ACCEL_INT_OUT_CTRL_INT2_LVL BIT(2)
|
||||
|
||||
#define BMC150_ACCEL_REG_INT_5 0x27
|
||||
#define BMC150_ACCEL_SLOPE_DUR_MASK 0x03
|
||||
|
@ -476,21 +484,24 @@ static bool bmc150_apply_acpi_orientation(struct device *dev,
|
|||
}
|
||||
#endif
|
||||
|
||||
static const struct bmc150_accel_interrupt_info {
|
||||
struct bmc150_accel_interrupt_info {
|
||||
u8 map_reg;
|
||||
u8 map_bitmask;
|
||||
u8 en_reg;
|
||||
u8 en_bitmask;
|
||||
} bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
|
||||
};
|
||||
|
||||
static const struct bmc150_accel_interrupt_info
|
||||
bmc150_accel_interrupts_int1[BMC150_ACCEL_INTERRUPTS] = {
|
||||
{ /* data ready interrupt */
|
||||
.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
|
||||
.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA,
|
||||
.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT1_DATA,
|
||||
.en_reg = BMC150_ACCEL_REG_INT_EN_1,
|
||||
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN,
|
||||
},
|
||||
{ /* motion interrupt */
|
||||
.map_reg = BMC150_ACCEL_REG_INT_MAP_0,
|
||||
.map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_SLOPE,
|
||||
.map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_INT1_SLOPE,
|
||||
.en_reg = BMC150_ACCEL_REG_INT_EN_0,
|
||||
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X |
|
||||
BMC150_ACCEL_INT_EN_BIT_SLP_Y |
|
||||
|
@ -498,19 +509,56 @@ static const struct bmc150_accel_interrupt_info {
|
|||
},
|
||||
{ /* fifo watermark interrupt */
|
||||
.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
|
||||
.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM,
|
||||
.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT1_FWM,
|
||||
.en_reg = BMC150_ACCEL_REG_INT_EN_1,
|
||||
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct bmc150_accel_interrupt_info
|
||||
bmc150_accel_interrupts_int2[BMC150_ACCEL_INTERRUPTS] = {
|
||||
{ /* data ready interrupt */
|
||||
.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
|
||||
.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT2_DATA,
|
||||
.en_reg = BMC150_ACCEL_REG_INT_EN_1,
|
||||
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN,
|
||||
},
|
||||
{ /* motion interrupt */
|
||||
.map_reg = BMC150_ACCEL_REG_INT_MAP_2,
|
||||
.map_bitmask = BMC150_ACCEL_INT_MAP_2_BIT_INT2_SLOPE,
|
||||
.en_reg = BMC150_ACCEL_REG_INT_EN_0,
|
||||
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X |
|
||||
BMC150_ACCEL_INT_EN_BIT_SLP_Y |
|
||||
BMC150_ACCEL_INT_EN_BIT_SLP_Z
|
||||
},
|
||||
{ /* fifo watermark interrupt */
|
||||
.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
|
||||
.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT2_FWM,
|
||||
.en_reg = BMC150_ACCEL_REG_INT_EN_1,
|
||||
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
|
||||
},
|
||||
};
|
||||
|
||||
static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
|
||||
struct bmc150_accel_data *data)
|
||||
struct bmc150_accel_data *data, int irq)
|
||||
{
|
||||
const struct bmc150_accel_interrupt_info *irq_info = NULL;
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
int i;
|
||||
|
||||
/*
|
||||
* For now we map all interrupts to the same output pin.
|
||||
* However, some boards may have just INT2 (and not INT1) connected,
|
||||
* so we try to detect which IRQ it is based on the interrupt-names.
|
||||
* Without interrupt-names, we assume the irq belongs to INT1.
|
||||
*/
|
||||
irq_info = bmc150_accel_interrupts_int1;
|
||||
if (data->type == BOSCH_BMC156 ||
|
||||
irq == of_irq_get_byname(dev->of_node, "INT2"))
|
||||
irq_info = bmc150_accel_interrupts_int2;
|
||||
|
||||
for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++)
|
||||
data->interrupts[i].info = &bmc150_accel_interrupts[i];
|
||||
data->interrupts[i].info = &irq_info[i];
|
||||
}
|
||||
|
||||
static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
|
||||
|
@ -1127,7 +1175,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
|
|||
{306458, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
{
|
||||
.name = "BMA253/BMA254/BMA255/BMC150/BMI055",
|
||||
.name = "BMA253/BMA254/BMA255/BMC150/BMC156/BMI055",
|
||||
.chip_id = 0xFA,
|
||||
.channels = bmc150_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
|
||||
|
@ -1614,7 +1662,8 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
|
|||
}
|
||||
|
||||
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
||||
const char *name, bool block_supported)
|
||||
enum bmc150_type type, const char *name,
|
||||
bool block_supported)
|
||||
{
|
||||
const struct attribute **fifo_attrs;
|
||||
struct bmc150_accel_data *data;
|
||||
|
@ -1629,6 +1678,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
|||
dev_set_drvdata(dev, indio_dev);
|
||||
|
||||
data->regmap = regmap;
|
||||
data->type = type;
|
||||
|
||||
if (!bmc150_apply_acpi_orientation(dev, &data->orientation)) {
|
||||
ret = iio_read_mount_matrix(dev, &data->orientation);
|
||||
|
@ -1714,7 +1764,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
|||
goto err_buffer_cleanup;
|
||||
}
|
||||
|
||||
bmc150_accel_interrupts_setup(indio_dev, data);
|
||||
bmc150_accel_interrupts_setup(indio_dev, data, irq);
|
||||
|
||||
ret = bmc150_accel_triggers_setup(indio_dev, data);
|
||||
if (ret)
|
||||
|
|
|
@ -176,6 +176,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
|
|||
{
|
||||
struct regmap *regmap;
|
||||
const char *name = NULL;
|
||||
enum bmc150_type type = BOSCH_UNKNOWN;
|
||||
bool block_supported =
|
||||
i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
|
||||
i2c_check_functionality(client->adapter,
|
||||
|
@ -188,10 +189,13 @@ static int bmc150_accel_probe(struct i2c_client *client,
|
|||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
if (id)
|
||||
if (id) {
|
||||
name = id->name;
|
||||
type = id->driver_data;
|
||||
}
|
||||
|
||||
ret = bmc150_accel_core_probe(&client->dev, regmap, client->irq, name, block_supported);
|
||||
ret = bmc150_accel_core_probe(&client->dev, regmap, client->irq,
|
||||
type, name, block_supported);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -236,6 +240,7 @@ static const struct i2c_device_id bmc150_accel_id[] = {
|
|||
{"bma255"},
|
||||
{"bma280"},
|
||||
{"bmc150_accel"},
|
||||
{"bmc156_accel", BOSCH_BMC156},
|
||||
{"bmi055_accel"},
|
||||
{}
|
||||
};
|
||||
|
@ -251,6 +256,7 @@ static const struct of_device_id bmc150_accel_of_match[] = {
|
|||
{ .compatible = "bosch,bma255" },
|
||||
{ .compatible = "bosch,bma280" },
|
||||
{ .compatible = "bosch,bmc150_accel" },
|
||||
{ .compatible = "bosch,bmc156_accel" },
|
||||
{ .compatible = "bosch,bmi055_accel" },
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
static int bmc150_accel_probe(struct spi_device *spi)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
const char *name = NULL;
|
||||
enum bmc150_type type = BOSCH_UNKNOWN;
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &bmc150_regmap_conf);
|
||||
|
@ -24,7 +26,12 @@ static int bmc150_accel_probe(struct spi_device *spi)
|
|||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, id->name,
|
||||
if (id) {
|
||||
name = id->name;
|
||||
type = id->driver_data;
|
||||
}
|
||||
|
||||
return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, type, name,
|
||||
true);
|
||||
}
|
||||
|
||||
|
@ -54,6 +61,7 @@ static const struct spi_device_id bmc150_accel_id[] = {
|
|||
{"bma255"},
|
||||
{"bma280"},
|
||||
{"bmc150_accel"},
|
||||
{"bmc156_accel", BOSCH_BMC156},
|
||||
{"bmi055_accel"},
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -13,6 +13,22 @@ struct i2c_client;
|
|||
struct bmc150_accel_chip_info;
|
||||
struct bmc150_accel_interrupt_info;
|
||||
|
||||
/*
|
||||
* We can often guess better than "UNKNOWN" based on the device IDs
|
||||
* but unfortunately this information is not always accurate. There are some
|
||||
* devices where ACPI firmware specifies an ID like "BMA250E" when the device
|
||||
* actually has a BMA222E. The driver attempts to detect those by reading the
|
||||
* chip ID from the registers but this information is not always enough either.
|
||||
*
|
||||
* Therefore, this enum should be only used when the chip ID detection is not
|
||||
* enough and we can be reasonably sure that the device IDs are reliable
|
||||
* in practice (e.g. for device tree platforms).
|
||||
*/
|
||||
enum bmc150_type {
|
||||
BOSCH_UNKNOWN,
|
||||
BOSCH_BMC156,
|
||||
};
|
||||
|
||||
struct bmc150_accel_interrupt {
|
||||
const struct bmc150_accel_interrupt_info *info;
|
||||
atomic_t users;
|
||||
|
@ -62,6 +78,7 @@ struct bmc150_accel_data {
|
|||
int ev_enable_state;
|
||||
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
|
||||
const struct bmc150_accel_chip_info *chip_info;
|
||||
enum bmc150_type type;
|
||||
struct i2c_client *second_device;
|
||||
void (*resume_callback)(struct device *dev);
|
||||
struct delayed_work resume_work;
|
||||
|
@ -69,7 +86,8 @@ struct bmc150_accel_data {
|
|||
};
|
||||
|
||||
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
||||
const char *name, bool block_supported);
|
||||
enum bmc150_type type, const char *name,
|
||||
bool block_supported);
|
||||
int bmc150_accel_core_remove(struct device *dev);
|
||||
extern const struct dev_pm_ops bmc150_accel_pm_ops;
|
||||
extern const struct regmap_config bmc150_regmap_conf;
|
||||
|
|
|
@ -100,6 +100,11 @@ static enum da280_chipset da280_match_acpi_device(struct device *dev)
|
|||
return (enum da280_chipset) id->driver_data;
|
||||
}
|
||||
|
||||
static void da280_disable(void *client)
|
||||
{
|
||||
da280_enable(client, false);
|
||||
}
|
||||
|
||||
static int da280_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -118,7 +123,6 @@ static int da280_probe(struct i2c_client *client,
|
|||
|
||||
data = iio_priv(indio_dev);
|
||||
data->client = client;
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
indio_dev->info = &da280_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
@ -142,22 +146,11 @@ static int da280_probe(struct i2c_client *client,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "device_register failed\n");
|
||||
da280_enable(client, false);
|
||||
}
|
||||
ret = devm_add_action_or_reset(&client->dev, da280_disable, client);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int da280_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
return da280_enable(client, false);
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -194,7 +187,6 @@ static struct i2c_driver da280_driver = {
|
|||
.pm = &da280_pm_ops,
|
||||
},
|
||||
.probe = da280_probe,
|
||||
.remove = da280_remove,
|
||||
.id_table = da280_i2c_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -212,6 +212,11 @@ static const struct iio_info da311_info = {
|
|||
.read_raw = da311_read_raw,
|
||||
};
|
||||
|
||||
static void da311_disable(void *client)
|
||||
{
|
||||
da311_enable(client, false);
|
||||
}
|
||||
|
||||
static int da311_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -229,7 +234,6 @@ static int da311_probe(struct i2c_client *client,
|
|||
|
||||
data = iio_priv(indio_dev);
|
||||
data->client = client;
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
indio_dev->info = &da311_info;
|
||||
indio_dev->name = "da311";
|
||||
|
@ -245,22 +249,11 @@ static int da311_probe(struct i2c_client *client,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "device_register failed\n");
|
||||
da311_enable(client, false);
|
||||
}
|
||||
ret = devm_add_action_or_reset(&client->dev, da311_disable, client);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int da311_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
return da311_enable(client, false);
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -289,7 +282,6 @@ static struct i2c_driver da311_driver = {
|
|||
.pm = &da311_pm_ops,
|
||||
},
|
||||
.probe = da311_probe,
|
||||
.remove = da311_remove,
|
||||
.id_table = da311_i2c_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -170,6 +170,11 @@ static const struct iio_info dmard10_info = {
|
|||
.read_raw = dmard10_read_raw,
|
||||
};
|
||||
|
||||
static void dmard10_shutdown_cleanup(void *client)
|
||||
{
|
||||
dmard10_shutdown(client);
|
||||
}
|
||||
|
||||
static int dmard10_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -194,7 +199,6 @@ static int dmard10_probe(struct i2c_client *client,
|
|||
|
||||
data = iio_priv(indio_dev);
|
||||
data->client = client;
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
indio_dev->info = &dmard10_info;
|
||||
indio_dev->name = "dmard10";
|
||||
|
@ -206,22 +210,12 @@ static int dmard10_probe(struct i2c_client *client,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "device_register failed\n");
|
||||
dmard10_shutdown(client);
|
||||
}
|
||||
ret = devm_add_action_or_reset(&client->dev, dmard10_shutdown_cleanup,
|
||||
client);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dmard10_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
return dmard10_shutdown(client);
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -250,7 +244,6 @@ static struct i2c_driver dmard10_driver = {
|
|||
.pm = &dmard10_pm_ops,
|
||||
},
|
||||
.probe = dmard10_probe,
|
||||
.remove = dmard10_remove,
|
||||
.id_table = dmard10_i2c_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -367,7 +367,8 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "failed to setup common attributes\n");
|
||||
return ret;
|
||||
}
|
||||
indio_dev->channels = kmemdup(channel_spec, channel_size, GFP_KERNEL);
|
||||
indio_dev->channels = devm_kmemdup(&pdev->dev, channel_spec,
|
||||
channel_size, GFP_KERNEL);
|
||||
|
||||
if (!indio_dev->channels) {
|
||||
dev_err(&pdev->dev, "failed to duplicate channels\n");
|
||||
|
@ -378,7 +379,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
|
|||
hsdev->usage, accel_state);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to setup attributes\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->info = &accel_3d_info;
|
||||
|
@ -391,7 +392,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
|
|||
&accel_state->common_attributes);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "trigger setup failed\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
@ -416,8 +417,6 @@ error_iio_unreg:
|
|||
iio_device_unregister(indio_dev);
|
||||
error_remove_trigger:
|
||||
hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
|
||||
error_free_dev_mem:
|
||||
kfree(indio_dev->channels);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -431,7 +430,6 @@ static int hid_accel_3d_remove(struct platform_device *pdev)
|
|||
sensor_hub_remove_callback(hsdev, hsdev->usage);
|
||||
iio_device_unregister(indio_dev);
|
||||
hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
|
||||
kfree(indio_dev->channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,6 @@ enum st_accel_type {
|
|||
|
||||
#ifdef CONFIG_IIO_BUFFER
|
||||
int st_accel_allocate_ring(struct iio_dev *indio_dev);
|
||||
void st_accel_deallocate_ring(struct iio_dev *indio_dev);
|
||||
int st_accel_trig_set_state(struct iio_trigger *trig, bool state);
|
||||
#define ST_ACCEL_TRIGGER_SET_STATE (&st_accel_trig_set_state)
|
||||
#else /* CONFIG_IIO_BUFFER */
|
||||
|
@ -72,9 +71,6 @@ static inline int st_accel_allocate_ring(struct iio_dev *indio_dev)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void st_accel_deallocate_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
}
|
||||
#define ST_ACCEL_TRIGGER_SET_STATE NULL
|
||||
#endif /* CONFIG_IIO_BUFFER */
|
||||
|
||||
|
|
|
@ -9,14 +9,9 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
|
@ -67,13 +62,8 @@ static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = {
|
|||
|
||||
int st_accel_allocate_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
return iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
&st_sensors_trigger_handler, &st_accel_buffer_setup_ops);
|
||||
}
|
||||
|
||||
void st_accel_deallocate_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
|
||||
NULL, &st_sensors_trigger_handler, &st_accel_buffer_setup_ops);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
|
||||
|
|
|
@ -9,17 +9,13 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
#include "st_accel.h"
|
||||
|
@ -1381,7 +1377,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
|
|||
err = st_sensors_allocate_trigger(indio_dev,
|
||||
ST_ACCEL_TRIGGER_OPS);
|
||||
if (err < 0)
|
||||
goto st_accel_probe_trigger_error;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = iio_device_register(indio_dev);
|
||||
|
@ -1396,8 +1392,6 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
|
|||
st_accel_device_register_error:
|
||||
if (adata->irq > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
st_accel_probe_trigger_error:
|
||||
st_accel_deallocate_ring(indio_dev);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(st_accel_common_probe);
|
||||
|
@ -1409,8 +1403,6 @@ void st_accel_common_remove(struct iio_dev *indio_dev)
|
|||
iio_device_unregister(indio_dev);
|
||||
if (adata->irq > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
|
||||
st_accel_deallocate_ring(indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(st_accel_common_remove);
|
||||
|
||||
|
|
|
@ -9,11 +9,10 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors_i2c.h>
|
||||
#include "st_accel.h"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
|
|
|
@ -887,6 +887,16 @@ config ROCKCHIP_SARADC
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called rockchip_saradc.
|
||||
|
||||
config RZG2L_ADC
|
||||
tristate "Renesas RZ/G2L ADC driver"
|
||||
depends on ARCH_R9A07G044 || COMPILE_TEST
|
||||
help
|
||||
Say yes here to build support for the ADC found in Renesas
|
||||
RZ/G2L family.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called rzg2l_adc.
|
||||
|
||||
config SC27XX_ADC
|
||||
tristate "Spreadtrum SC27xx series PMICs ADC"
|
||||
depends on MFD_SC27XX_PMIC || COMPILE_TEST
|
||||
|
|
|
@ -82,6 +82,7 @@ obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
|
|||
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
|
||||
obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o
|
||||
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
|
||||
obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o
|
||||
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
|
||||
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
|
||||
obj-$(CONFIG_STX104) += stx104.o
|
||||
|
|
|
@ -205,7 +205,7 @@ static int ep93xx_adc_probe(struct platform_device *pdev)
|
|||
*/
|
||||
}
|
||||
|
||||
ret = clk_enable(priv->clk);
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Cannot enable clock\n");
|
||||
return ret;
|
||||
|
@ -213,7 +213,7 @@ static int ep93xx_adc_probe(struct platform_device *pdev)
|
|||
|
||||
ret = iio_device_register(iiodev);
|
||||
if (ret)
|
||||
clk_disable(priv->clk);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -224,7 +224,7 @@ static int ep93xx_adc_remove(struct platform_device *pdev)
|
|||
struct ep93xx_adc_priv *priv = iio_priv(iiodev);
|
||||
|
||||
iio_device_unregister(iiodev);
|
||||
clk_disable(priv->clk);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -201,11 +201,11 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
|
|||
*/
|
||||
priv->vref[MX25_ADC_REFP_INT] = NULL;
|
||||
priv->vref[MX25_ADC_REFP_EXT] =
|
||||
devm_regulator_get_optional(&pdev->dev, "vref-ext");
|
||||
devm_regulator_get_optional(dev, "vref-ext");
|
||||
priv->vref[MX25_ADC_REFP_XP] =
|
||||
devm_regulator_get_optional(&pdev->dev, "vref-xp");
|
||||
devm_regulator_get_optional(dev, "vref-xp");
|
||||
priv->vref[MX25_ADC_REFP_YP] =
|
||||
devm_regulator_get_optional(&pdev->dev, "vref-yp");
|
||||
devm_regulator_get_optional(dev, "vref-yp");
|
||||
|
||||
for_each_child_of_node(np, child) {
|
||||
u32 reg;
|
||||
|
@ -307,7 +307,7 @@ static int mx25_gcq_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
int i;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -347,14 +347,11 @@ static int mx25_gcq_probe(struct platform_device *pdev)
|
|||
goto err_vref_disable;
|
||||
}
|
||||
|
||||
priv->irq = platform_get_irq(pdev, 0);
|
||||
if (priv->irq <= 0) {
|
||||
ret = priv->irq;
|
||||
if (!ret)
|
||||
ret = -ENXIO;
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0)
|
||||
goto err_clk_unprepare;
|
||||
}
|
||||
|
||||
priv->irq = ret;
|
||||
ret = request_irq(priv->irq, mx25_gcq_irq, 0, pdev->name, priv);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed requesting IRQ\n");
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#define JZ_ADC_REG_CFG_SAMPLE_NUM(n) ((n) << 10)
|
||||
#define JZ_ADC_REG_CFG_PULL_UP(n) ((n) << 16)
|
||||
#define JZ_ADC_REG_CFG_CMD_SEL BIT(22)
|
||||
#define JZ_ADC_REG_CFG_VBAT_SEL BIT(30)
|
||||
#define JZ_ADC_REG_CFG_TOUCH_OPS_MASK (BIT(31) | GENMASK(23, 10))
|
||||
#define JZ_ADC_REG_ADCLK_CLKDIV_LSB 0
|
||||
#define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB 16
|
||||
|
@ -71,6 +72,7 @@
|
|||
#define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10
|
||||
#define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986)
|
||||
#define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12
|
||||
#define JZ4760_ADC_BATTERY_VREF 2500
|
||||
#define JZ4770_ADC_BATTERY_VREF 1200
|
||||
#define JZ4770_ADC_BATTERY_VREF_BITS 12
|
||||
|
||||
|
@ -92,7 +94,7 @@ struct ingenic_adc_soc_data {
|
|||
const int *battery_scale_avail;
|
||||
size_t battery_scale_avail_size;
|
||||
unsigned int battery_vref_mode: 1;
|
||||
unsigned int has_aux2: 1;
|
||||
unsigned int has_aux_md: 1;
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned int num_channels;
|
||||
int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc);
|
||||
|
@ -295,6 +297,10 @@ static const int jz4740_adc_battery_scale_avail[] = {
|
|||
JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
|
||||
};
|
||||
|
||||
static const int jz4760_adc_battery_scale_avail[] = {
|
||||
JZ4760_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS,
|
||||
};
|
||||
|
||||
static const int jz4770_adc_battery_raw_avail[] = {
|
||||
0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1,
|
||||
};
|
||||
|
@ -400,6 +406,47 @@ static const struct iio_chan_spec jz4740_channels[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec jz4760_channels[] = {
|
||||
{
|
||||
.extend_name = "aux",
|
||||
.type = IIO_VOLTAGE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.indexed = 1,
|
||||
.channel = INGENIC_ADC_AUX0,
|
||||
.scan_index = -1,
|
||||
},
|
||||
{
|
||||
.extend_name = "aux1",
|
||||
.type = IIO_VOLTAGE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.indexed = 1,
|
||||
.channel = INGENIC_ADC_AUX,
|
||||
.scan_index = -1,
|
||||
},
|
||||
{
|
||||
.extend_name = "aux2",
|
||||
.type = IIO_VOLTAGE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.indexed = 1,
|
||||
.channel = INGENIC_ADC_AUX2,
|
||||
.scan_index = -1,
|
||||
},
|
||||
{
|
||||
.extend_name = "battery",
|
||||
.type = IIO_VOLTAGE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.indexed = 1,
|
||||
.channel = INGENIC_ADC_BATTERY,
|
||||
.scan_index = -1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec jz4770_channels[] = {
|
||||
{
|
||||
.type = IIO_VOLTAGE,
|
||||
|
@ -506,7 +553,7 @@ static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
|
|||
.battery_scale_avail = jz4725b_adc_battery_scale_avail,
|
||||
.battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
|
||||
.battery_vref_mode = true,
|
||||
.has_aux2 = false,
|
||||
.has_aux_md = false,
|
||||
.channels = jz4740_channels,
|
||||
.num_channels = ARRAY_SIZE(jz4740_channels),
|
||||
.init_clk_div = jz4725b_adc_init_clk_div,
|
||||
|
@ -520,12 +567,26 @@ static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
|
|||
.battery_scale_avail = jz4740_adc_battery_scale_avail,
|
||||
.battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
|
||||
.battery_vref_mode = true,
|
||||
.has_aux2 = false,
|
||||
.has_aux_md = false,
|
||||
.channels = jz4740_channels,
|
||||
.num_channels = ARRAY_SIZE(jz4740_channels),
|
||||
.init_clk_div = NULL, /* no ADCLK register on JZ4740 */
|
||||
};
|
||||
|
||||
static const struct ingenic_adc_soc_data jz4760_adc_soc_data = {
|
||||
.battery_high_vref = JZ4760_ADC_BATTERY_VREF,
|
||||
.battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS,
|
||||
.battery_raw_avail = jz4770_adc_battery_raw_avail,
|
||||
.battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail),
|
||||
.battery_scale_avail = jz4760_adc_battery_scale_avail,
|
||||
.battery_scale_avail_size = ARRAY_SIZE(jz4760_adc_battery_scale_avail),
|
||||
.battery_vref_mode = false,
|
||||
.has_aux_md = true,
|
||||
.channels = jz4760_channels,
|
||||
.num_channels = ARRAY_SIZE(jz4760_channels),
|
||||
.init_clk_div = jz4770_adc_init_clk_div,
|
||||
};
|
||||
|
||||
static const struct ingenic_adc_soc_data jz4770_adc_soc_data = {
|
||||
.battery_high_vref = JZ4770_ADC_BATTERY_VREF,
|
||||
.battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS,
|
||||
|
@ -534,7 +595,7 @@ static const struct ingenic_adc_soc_data jz4770_adc_soc_data = {
|
|||
.battery_scale_avail = jz4770_adc_battery_scale_avail,
|
||||
.battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail),
|
||||
.battery_vref_mode = false,
|
||||
.has_aux2 = true,
|
||||
.has_aux_md = true,
|
||||
.channels = jz4770_channels,
|
||||
.num_channels = ARRAY_SIZE(jz4770_channels),
|
||||
.init_clk_div = jz4770_adc_init_clk_div,
|
||||
|
@ -569,7 +630,7 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
|
|||
struct iio_chan_spec const *chan,
|
||||
int *val)
|
||||
{
|
||||
int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY);
|
||||
int cmd, ret, engine = (chan->channel == INGENIC_ADC_BATTERY);
|
||||
struct ingenic_adc *adc = iio_priv(iio_dev);
|
||||
|
||||
ret = clk_enable(adc->clk);
|
||||
|
@ -579,11 +640,22 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* We cannot sample AUX/AUX2 in parallel. */
|
||||
/* We cannot sample the aux channels in parallel. */
|
||||
mutex_lock(&adc->aux_lock);
|
||||
if (adc->soc_data->has_aux2 && engine == 0) {
|
||||
bit = BIT(chan->channel == INGENIC_ADC_AUX2);
|
||||
ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit);
|
||||
if (adc->soc_data->has_aux_md && engine == 0) {
|
||||
switch (chan->channel) {
|
||||
case INGENIC_ADC_AUX0:
|
||||
cmd = 0;
|
||||
break;
|
||||
case INGENIC_ADC_AUX:
|
||||
cmd = 1;
|
||||
break;
|
||||
case INGENIC_ADC_AUX2:
|
||||
cmd = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, cmd);
|
||||
}
|
||||
|
||||
ret = ingenic_adc_capture(adc, engine);
|
||||
|
@ -591,6 +663,7 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
|
|||
goto out;
|
||||
|
||||
switch (chan->channel) {
|
||||
case INGENIC_ADC_AUX0:
|
||||
case INGENIC_ADC_AUX:
|
||||
case INGENIC_ADC_AUX2:
|
||||
*val = readw(adc->base + JZ_ADC_REG_ADSDAT);
|
||||
|
@ -621,6 +694,7 @@ static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
|
|||
return ingenic_adc_read_chan_info_raw(iio_dev, chan, val);
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->channel) {
|
||||
case INGENIC_ADC_AUX0:
|
||||
case INGENIC_ADC_AUX:
|
||||
case INGENIC_ADC_AUX2:
|
||||
*val = JZ_ADC_AUX_VREF;
|
||||
|
@ -806,6 +880,14 @@ static int ingenic_adc_probe(struct platform_device *pdev)
|
|||
/* Put hardware in a known passive state. */
|
||||
writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
|
||||
writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
|
||||
|
||||
/* JZ4760B specific */
|
||||
if (device_property_present(dev, "ingenic,use-internal-divider"))
|
||||
ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_VBAT_SEL,
|
||||
JZ_ADC_REG_CFG_VBAT_SEL);
|
||||
else
|
||||
ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_VBAT_SEL, 0);
|
||||
|
||||
usleep_range(2000, 3000); /* Must wait at least 2ms. */
|
||||
clk_disable(adc->clk);
|
||||
|
||||
|
@ -832,6 +914,8 @@ static int ingenic_adc_probe(struct platform_device *pdev)
|
|||
static const struct of_device_id ingenic_adc_of_match[] = {
|
||||
{ .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
|
||||
{ .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
|
||||
{ .compatible = "ingenic,jz4760-adc", .data = &jz4760_adc_soc_data, },
|
||||
{ .compatible = "ingenic,jz4760b-adc", .data = &jz4760_adc_soc_data, },
|
||||
{ .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, },
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -347,7 +347,7 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev,
|
|||
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
|
||||
int regval, fifo_chan, fifo_val, count;
|
||||
|
||||
if(!wait_for_completion_timeout(&priv->done,
|
||||
if (!wait_for_completion_timeout(&priv->done,
|
||||
msecs_to_jiffies(MESON_SAR_ADC_TIMEOUT)))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
|
@ -497,8 +497,8 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
|
|||
if (priv->param->has_bl30_integration) {
|
||||
/* prevent BL30 from using the SAR ADC while we are using it */
|
||||
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
|
||||
MESON_SAR_ADC_DELAY_KERNEL_BUSY,
|
||||
MESON_SAR_ADC_DELAY_KERNEL_BUSY);
|
||||
MESON_SAR_ADC_DELAY_KERNEL_BUSY,
|
||||
MESON_SAR_ADC_DELAY_KERNEL_BUSY);
|
||||
|
||||
/*
|
||||
* wait until BL30 releases it's lock (so we can use the SAR
|
||||
|
@ -525,7 +525,7 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
|
|||
if (priv->param->has_bl30_integration)
|
||||
/* allow BL30 to use the SAR ADC again */
|
||||
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
|
||||
MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
|
||||
MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
|
||||
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
}
|
||||
|
@ -791,7 +791,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
|
|||
* on the vendor driver), which we don't support at the moment.
|
||||
*/
|
||||
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
|
||||
MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0);
|
||||
MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0);
|
||||
|
||||
/* disable all channels by default */
|
||||
regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0);
|
||||
|
@ -1104,6 +1104,14 @@ static const struct meson_sar_adc_param meson_sar_adc_gxl_param = {
|
|||
.resolution = 12,
|
||||
};
|
||||
|
||||
static const struct meson_sar_adc_param meson_sar_adc_g12a_param = {
|
||||
.has_bl30_integration = false,
|
||||
.clock_rate = 1200000,
|
||||
.bandgap_reg = MESON_SAR_ADC_REG11,
|
||||
.regmap_config = &meson_sar_adc_regmap_config_gxbb,
|
||||
.resolution = 12,
|
||||
};
|
||||
|
||||
static const struct meson_sar_adc_data meson_sar_adc_meson8_data = {
|
||||
.param = &meson_sar_adc_meson8_param,
|
||||
.name = "meson-meson8-saradc",
|
||||
|
@ -1140,7 +1148,7 @@ static const struct meson_sar_adc_data meson_sar_adc_axg_data = {
|
|||
};
|
||||
|
||||
static const struct meson_sar_adc_data meson_sar_adc_g12a_data = {
|
||||
.param = &meson_sar_adc_gxl_param,
|
||||
.param = &meson_sar_adc_g12a_param,
|
||||
.name = "meson-g12a-saradc",
|
||||
};
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#define SARADC_DLY_PU_SOC_MASK 0x3f
|
||||
|
||||
#define SARADC_TIMEOUT msecs_to_jiffies(100)
|
||||
#define SARADC_MAX_CHANNELS 6
|
||||
#define SARADC_MAX_CHANNELS 8
|
||||
|
||||
struct rockchip_saradc_data {
|
||||
const struct iio_chan_spec *channels;
|
||||
|
@ -49,10 +49,12 @@ struct rockchip_saradc {
|
|||
struct clk *clk;
|
||||
struct completion completion;
|
||||
struct regulator *vref;
|
||||
int uv_vref;
|
||||
struct reset_control *reset;
|
||||
const struct rockchip_saradc_data *data;
|
||||
u16 last_val;
|
||||
const struct iio_chan_spec *last_chan;
|
||||
struct notifier_block nb;
|
||||
};
|
||||
|
||||
static void rockchip_saradc_power_down(struct rockchip_saradc *info)
|
||||
|
@ -105,13 +107,7 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
|
|||
mutex_unlock(&indio_dev->mlock);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = regulator_get_voltage(info->vref);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "failed to get voltage\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
*val = ret / 1000;
|
||||
*val = info->uv_vref / 1000;
|
||||
*val2 = chan->scan_type.realbits;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
default:
|
||||
|
@ -192,6 +188,23 @@ static const struct rockchip_saradc_data rk3399_saradc_data = {
|
|||
.clk_rate = 1000000,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec rockchip_rk3568_saradc_iio_channels[] = {
|
||||
SARADC_CHANNEL(0, "adc0", 10),
|
||||
SARADC_CHANNEL(1, "adc1", 10),
|
||||
SARADC_CHANNEL(2, "adc2", 10),
|
||||
SARADC_CHANNEL(3, "adc3", 10),
|
||||
SARADC_CHANNEL(4, "adc4", 10),
|
||||
SARADC_CHANNEL(5, "adc5", 10),
|
||||
SARADC_CHANNEL(6, "adc6", 10),
|
||||
SARADC_CHANNEL(7, "adc7", 10),
|
||||
};
|
||||
|
||||
static const struct rockchip_saradc_data rk3568_saradc_data = {
|
||||
.channels = rockchip_rk3568_saradc_iio_channels,
|
||||
.num_channels = ARRAY_SIZE(rockchip_rk3568_saradc_iio_channels),
|
||||
.clk_rate = 1000000,
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_saradc_match[] = {
|
||||
{
|
||||
.compatible = "rockchip,saradc",
|
||||
|
@ -202,6 +215,9 @@ static const struct of_device_id rockchip_saradc_match[] = {
|
|||
}, {
|
||||
.compatible = "rockchip,rk3399-saradc",
|
||||
.data = &rk3399_saradc_data,
|
||||
}, {
|
||||
.compatible = "rockchip,rk3568-saradc",
|
||||
.data = &rk3568_saradc_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
@ -278,6 +294,26 @@ out:
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rockchip_saradc_volt_notify(struct notifier_block *nb,
|
||||
unsigned long event,
|
||||
void *data)
|
||||
{
|
||||
struct rockchip_saradc *info =
|
||||
container_of(nb, struct rockchip_saradc, nb);
|
||||
|
||||
if (event & REGULATOR_EVENT_VOLTAGE_CHANGE)
|
||||
info->uv_vref = (unsigned long)data;
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static void rockchip_saradc_regulator_unreg_notifier(void *data)
|
||||
{
|
||||
struct rockchip_saradc *info = data;
|
||||
|
||||
regulator_unregister_notifier(info->vref, &info->nb);
|
||||
}
|
||||
|
||||
static int rockchip_saradc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rockchip_saradc *info = NULL;
|
||||
|
@ -390,6 +426,12 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_get_voltage(info->vref);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
info->uv_vref = ret;
|
||||
|
||||
ret = clk_prepare_enable(info->pclk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to enable pclk\n");
|
||||
|
@ -430,6 +472,17 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
info->nb.notifier_call = rockchip_saradc_volt_notify;
|
||||
ret = regulator_register_notifier(info->vref, &info->nb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev,
|
||||
rockchip_saradc_regulator_unreg_notifier,
|
||||
info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(&pdev->dev, indio_dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,600 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* RZ/G2L A/D Converter driver
|
||||
*
|
||||
* Copyright (c) 2021 Renesas Electronics Europe GmbH
|
||||
*
|
||||
* Author: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#define DRIVER_NAME "rzg2l-adc"
|
||||
|
||||
#define RZG2L_ADM(n) ((n) * 0x4)
|
||||
#define RZG2L_ADM0_ADCE BIT(0)
|
||||
#define RZG2L_ADM0_ADBSY BIT(1)
|
||||
#define RZG2L_ADM0_PWDWNB BIT(2)
|
||||
#define RZG2L_ADM0_SRESB BIT(15)
|
||||
#define RZG2L_ADM1_TRG BIT(0)
|
||||
#define RZG2L_ADM1_MS BIT(2)
|
||||
#define RZG2L_ADM1_BS BIT(4)
|
||||
#define RZG2L_ADM1_EGA_MASK GENMASK(13, 12)
|
||||
#define RZG2L_ADM2_CHSEL_MASK GENMASK(7, 0)
|
||||
#define RZG2L_ADM3_ADIL_MASK GENMASK(31, 24)
|
||||
#define RZG2L_ADM3_ADCMP_MASK GENMASK(23, 16)
|
||||
#define RZG2L_ADM3_ADCMP_E FIELD_PREP(RZG2L_ADM3_ADCMP_MASK, 0xe)
|
||||
#define RZG2L_ADM3_ADSMP_MASK GENMASK(15, 0)
|
||||
|
||||
#define RZG2L_ADINT 0x20
|
||||
#define RZG2L_ADINT_INTEN_MASK GENMASK(7, 0)
|
||||
#define RZG2L_ADINT_CSEEN BIT(16)
|
||||
#define RZG2L_ADINT_INTS BIT(31)
|
||||
|
||||
#define RZG2L_ADSTS 0x24
|
||||
#define RZG2L_ADSTS_CSEST BIT(16)
|
||||
#define RZG2L_ADSTS_INTST_MASK GENMASK(7, 0)
|
||||
|
||||
#define RZG2L_ADIVC 0x28
|
||||
#define RZG2L_ADIVC_DIVADC_MASK GENMASK(8, 0)
|
||||
#define RZG2L_ADIVC_DIVADC_4 FIELD_PREP(RZG2L_ADIVC_DIVADC_MASK, 0x4)
|
||||
|
||||
#define RZG2L_ADFIL 0x2c
|
||||
|
||||
#define RZG2L_ADCR(n) (0x30 + ((n) * 0x4))
|
||||
#define RZG2L_ADCR_AD_MASK GENMASK(11, 0)
|
||||
|
||||
#define RZG2L_ADSMP_DEFUALT_SAMPLING 0x578
|
||||
|
||||
#define RZG2L_ADC_MAX_CHANNELS 8
|
||||
#define RZG2L_ADC_CHN_MASK 0x7
|
||||
#define RZG2L_ADC_TIMEOUT usecs_to_jiffies(1 * 4)
|
||||
|
||||
struct rzg2l_adc_data {
|
||||
const struct iio_chan_spec *channels;
|
||||
u8 num_channels;
|
||||
};
|
||||
|
||||
struct rzg2l_adc {
|
||||
void __iomem *base;
|
||||
struct clk *pclk;
|
||||
struct clk *adclk;
|
||||
struct reset_control *presetn;
|
||||
struct reset_control *adrstn;
|
||||
struct completion completion;
|
||||
const struct rzg2l_adc_data *data;
|
||||
struct mutex lock;
|
||||
u16 last_val[RZG2L_ADC_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
static const char * const rzg2l_adc_channel_name[] = {
|
||||
"adc0",
|
||||
"adc1",
|
||||
"adc2",
|
||||
"adc3",
|
||||
"adc4",
|
||||
"adc5",
|
||||
"adc6",
|
||||
"adc7",
|
||||
};
|
||||
|
||||
static unsigned int rzg2l_adc_readl(struct rzg2l_adc *adc, u32 reg)
|
||||
{
|
||||
return readl(adc->base + reg);
|
||||
}
|
||||
|
||||
static void rzg2l_adc_writel(struct rzg2l_adc *adc, unsigned int reg, u32 val)
|
||||
{
|
||||
writel(val, adc->base + reg);
|
||||
}
|
||||
|
||||
static void rzg2l_adc_pwr(struct rzg2l_adc *adc, bool on)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
|
||||
if (on)
|
||||
reg |= RZG2L_ADM0_PWDWNB;
|
||||
else
|
||||
reg &= ~RZG2L_ADM0_PWDWNB;
|
||||
rzg2l_adc_writel(adc, RZG2L_ADM(0), reg);
|
||||
udelay(2);
|
||||
}
|
||||
|
||||
static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start)
|
||||
{
|
||||
int timeout = 5;
|
||||
u32 reg;
|
||||
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
|
||||
if (start)
|
||||
reg |= RZG2L_ADM0_ADCE;
|
||||
else
|
||||
reg &= ~RZG2L_ADM0_ADCE;
|
||||
rzg2l_adc_writel(adc, RZG2L_ADM(0), reg);
|
||||
|
||||
if (start)
|
||||
return;
|
||||
|
||||
do {
|
||||
usleep_range(100, 200);
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
|
||||
timeout--;
|
||||
if (!timeout) {
|
||||
pr_err("%s stopping ADC timed out\n", __func__);
|
||||
break;
|
||||
}
|
||||
} while (((reg & RZG2L_ADM0_ADBSY) || (reg & RZG2L_ADM0_ADCE)));
|
||||
}
|
||||
|
||||
static void rzg2l_set_trigger(struct rzg2l_adc *adc)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Setup ADM1 for SW trigger
|
||||
* EGA[13:12] - Set 00 to indicate hardware trigger is invalid
|
||||
* BS[4] - Enable 1-buffer mode
|
||||
* MS[1] - Enable Select mode
|
||||
* TRG[0] - Enable software trigger mode
|
||||
*/
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(1));
|
||||
reg &= ~RZG2L_ADM1_EGA_MASK;
|
||||
reg &= ~RZG2L_ADM1_BS;
|
||||
reg &= ~RZG2L_ADM1_TRG;
|
||||
reg |= RZG2L_ADM1_MS;
|
||||
rzg2l_adc_writel(adc, RZG2L_ADM(1), reg);
|
||||
}
|
||||
|
||||
static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_ADBSY)
|
||||
return -EBUSY;
|
||||
|
||||
rzg2l_set_trigger(adc);
|
||||
|
||||
/* Select analog input channel subjected to conversion. */
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(2));
|
||||
reg &= ~RZG2L_ADM2_CHSEL_MASK;
|
||||
reg |= BIT(ch);
|
||||
rzg2l_adc_writel(adc, RZG2L_ADM(2), reg);
|
||||
|
||||
/*
|
||||
* Setup ADINT
|
||||
* INTS[31] - Select pulse signal
|
||||
* CSEEN[16] - Enable channel select error interrupt
|
||||
* INTEN[7:0] - Select channel interrupt
|
||||
*/
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADINT);
|
||||
reg &= ~RZG2L_ADINT_INTS;
|
||||
reg &= ~RZG2L_ADINT_INTEN_MASK;
|
||||
reg |= (RZG2L_ADINT_CSEEN | BIT(ch));
|
||||
rzg2l_adc_writel(adc, RZG2L_ADINT, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzg2l_adc_set_power(struct iio_dev *indio_dev, bool on)
|
||||
{
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
|
||||
if (on)
|
||||
return pm_runtime_resume_and_get(dev);
|
||||
|
||||
return pm_runtime_put_sync(dev);
|
||||
}
|
||||
|
||||
static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc, u8 ch)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rzg2l_adc_set_power(indio_dev, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rzg2l_adc_conversion_setup(adc, ch);
|
||||
if (ret) {
|
||||
rzg2l_adc_set_power(indio_dev, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reinit_completion(&adc->completion);
|
||||
|
||||
rzg2l_adc_start_stop(adc, true);
|
||||
|
||||
if (!wait_for_completion_timeout(&adc->completion, RZG2L_ADC_TIMEOUT)) {
|
||||
rzg2l_adc_writel(adc, RZG2L_ADINT,
|
||||
rzg2l_adc_readl(adc, RZG2L_ADINT) & ~RZG2L_ADINT_INTEN_MASK);
|
||||
rzg2l_adc_start_stop(adc, false);
|
||||
rzg2l_adc_set_power(indio_dev, false);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return rzg2l_adc_set_power(indio_dev, false);
|
||||
}
|
||||
|
||||
static int rzg2l_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct rzg2l_adc *adc = iio_priv(indio_dev);
|
||||
int ret;
|
||||
u8 ch;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (chan->type != IIO_VOLTAGE)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&adc->lock);
|
||||
ch = chan->channel & RZG2L_ADC_CHN_MASK;
|
||||
ret = rzg2l_adc_conversion(indio_dev, adc, ch);
|
||||
if (ret) {
|
||||
mutex_unlock(&adc->lock);
|
||||
return ret;
|
||||
}
|
||||
*val = adc->last_val[ch];
|
||||
mutex_unlock(&adc->lock);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int rzg2l_adc_read_label(struct iio_dev *iio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
char *label)
|
||||
{
|
||||
if (chan->channel >= RZG2L_ADC_MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
return sysfs_emit(label, "%s\n", rzg2l_adc_channel_name[chan->channel]);
|
||||
}
|
||||
|
||||
static const struct iio_info rzg2l_adc_iio_info = {
|
||||
.read_raw = rzg2l_adc_read_raw,
|
||||
.read_label = rzg2l_adc_read_label,
|
||||
};
|
||||
|
||||
static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct rzg2l_adc *adc = dev_id;
|
||||
unsigned long intst;
|
||||
u32 reg;
|
||||
int ch;
|
||||
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADSTS);
|
||||
|
||||
/* A/D conversion channel select error interrupt */
|
||||
if (reg & RZG2L_ADSTS_CSEST) {
|
||||
rzg2l_adc_writel(adc, RZG2L_ADSTS, reg);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
intst = reg & RZG2L_ADSTS_INTST_MASK;
|
||||
if (!intst)
|
||||
return IRQ_NONE;
|
||||
|
||||
for_each_set_bit(ch, &intst, RZG2L_ADC_MAX_CHANNELS)
|
||||
adc->last_val[ch] = rzg2l_adc_readl(adc, RZG2L_ADCR(ch)) & RZG2L_ADCR_AD_MASK;
|
||||
|
||||
/* clear the channel interrupt */
|
||||
rzg2l_adc_writel(adc, RZG2L_ADSTS, reg);
|
||||
|
||||
complete(&adc->completion);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc)
|
||||
{
|
||||
struct iio_chan_spec *chan_array;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct rzg2l_adc_data *data;
|
||||
unsigned int channel;
|
||||
int num_channels;
|
||||
int ret;
|
||||
u8 i;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
num_channels = device_get_child_node_count(&pdev->dev);
|
||||
if (!num_channels) {
|
||||
dev_err(&pdev->dev, "no channel children\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (num_channels > RZG2L_ADC_MAX_CHANNELS) {
|
||||
dev_err(&pdev->dev, "num of channel children out of range\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chan_array = devm_kcalloc(&pdev->dev, num_channels, sizeof(*chan_array),
|
||||
GFP_KERNEL);
|
||||
if (!chan_array)
|
||||
return -ENOMEM;
|
||||
|
||||
i = 0;
|
||||
device_for_each_child_node(&pdev->dev, fwnode) {
|
||||
ret = fwnode_property_read_u32(fwnode, "reg", &channel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (channel >= RZG2L_ADC_MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
chan_array[i].type = IIO_VOLTAGE;
|
||||
chan_array[i].indexed = 1;
|
||||
chan_array[i].channel = channel;
|
||||
chan_array[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
|
||||
chan_array[i].datasheet_name = rzg2l_adc_channel_name[channel];
|
||||
i++;
|
||||
}
|
||||
|
||||
data->num_channels = num_channels;
|
||||
data->channels = chan_array;
|
||||
adc->data = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzg2l_adc_hw_init(struct rzg2l_adc *adc)
|
||||
{
|
||||
int timeout = 5;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(adc->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* SW reset */
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
|
||||
reg |= RZG2L_ADM0_SRESB;
|
||||
rzg2l_adc_writel(adc, RZG2L_ADM(0), reg);
|
||||
|
||||
while (!(rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_SRESB)) {
|
||||
if (!timeout) {
|
||||
ret = -EBUSY;
|
||||
goto exit_hw_init;
|
||||
}
|
||||
timeout--;
|
||||
usleep_range(100, 200);
|
||||
}
|
||||
|
||||
/* Only division by 4 can be set */
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADIVC);
|
||||
reg &= ~RZG2L_ADIVC_DIVADC_MASK;
|
||||
reg |= RZG2L_ADIVC_DIVADC_4;
|
||||
rzg2l_adc_writel(adc, RZG2L_ADIVC, reg);
|
||||
|
||||
/*
|
||||
* Setup AMD3
|
||||
* ADIL[31:24] - Should be always set to 0
|
||||
* ADCMP[23:16] - Should be always set to 0xe
|
||||
* ADSMP[15:0] - Set default (0x578) sampling period
|
||||
*/
|
||||
reg = rzg2l_adc_readl(adc, RZG2L_ADM(3));
|
||||
reg &= ~RZG2L_ADM3_ADIL_MASK;
|
||||
reg &= ~RZG2L_ADM3_ADCMP_MASK;
|
||||
reg &= ~RZG2L_ADM3_ADSMP_MASK;
|
||||
reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFUALT_SAMPLING);
|
||||
rzg2l_adc_writel(adc, RZG2L_ADM(3), reg);
|
||||
|
||||
exit_hw_init:
|
||||
clk_disable_unprepare(adc->pclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rzg2l_adc_pm_runtime_disable(void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
|
||||
pm_runtime_disable(dev->parent);
|
||||
}
|
||||
|
||||
static void rzg2l_adc_pm_runtime_set_suspended(void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
|
||||
pm_runtime_set_suspended(dev->parent);
|
||||
}
|
||||
|
||||
static void rzg2l_adc_reset_assert(void *data)
|
||||
{
|
||||
reset_control_assert(data);
|
||||
}
|
||||
|
||||
static int rzg2l_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct rzg2l_adc *adc;
|
||||
int ret;
|
||||
int irq;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
adc = iio_priv(indio_dev);
|
||||
|
||||
ret = rzg2l_adc_parse_properties(pdev, adc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
adc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(adc->base))
|
||||
return PTR_ERR(adc->base);
|
||||
|
||||
adc->pclk = devm_clk_get(dev, "pclk");
|
||||
if (IS_ERR(adc->pclk)) {
|
||||
dev_err(dev, "Failed to get pclk");
|
||||
return PTR_ERR(adc->pclk);
|
||||
}
|
||||
|
||||
adc->adclk = devm_clk_get(dev, "adclk");
|
||||
if (IS_ERR(adc->adclk)) {
|
||||
dev_err(dev, "Failed to get adclk");
|
||||
return PTR_ERR(adc->adclk);
|
||||
}
|
||||
|
||||
adc->adrstn = devm_reset_control_get_exclusive(dev, "adrst-n");
|
||||
if (IS_ERR(adc->adrstn)) {
|
||||
dev_err(dev, "failed to get adrstn\n");
|
||||
return PTR_ERR(adc->adrstn);
|
||||
}
|
||||
|
||||
adc->presetn = devm_reset_control_get_exclusive(dev, "presetn");
|
||||
if (IS_ERR(adc->presetn)) {
|
||||
dev_err(dev, "failed to get presetn\n");
|
||||
return PTR_ERR(adc->presetn);
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(adc->adrstn);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to deassert adrstn pin, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev,
|
||||
rzg2l_adc_reset_assert, adc->adrstn);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register adrstn assert devm action, %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(adc->presetn);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to deassert presetn pin, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev,
|
||||
rzg2l_adc_reset_assert, adc->presetn);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register presetn assert devm action, %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rzg2l_adc_hw_init(adc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize ADC HW, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "no irq resource\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq, rzg2l_adc_isr,
|
||||
0, dev_name(dev), adc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
init_completion(&adc->completion);
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
indio_dev->name = DRIVER_NAME;
|
||||
indio_dev->info = &rzg2l_adc_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = adc->data->channels;
|
||||
indio_dev->num_channels = adc->data->num_channels;
|
||||
|
||||
pm_runtime_set_suspended(dev);
|
||||
ret = devm_add_action_or_reset(&pdev->dev,
|
||||
rzg2l_adc_pm_runtime_set_suspended, &indio_dev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
ret = devm_add_action_or_reset(&pdev->dev,
|
||||
rzg2l_adc_pm_runtime_disable, &indio_dev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id rzg2l_adc_match[] = {
|
||||
{ .compatible = "renesas,rzg2l-adc",},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rzg2l_adc_match);
|
||||
|
||||
static int __maybe_unused rzg2l_adc_pm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct rzg2l_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
rzg2l_adc_pwr(adc, false);
|
||||
clk_disable_unprepare(adc->adclk);
|
||||
clk_disable_unprepare(adc->pclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused rzg2l_adc_pm_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct rzg2l_adc *adc = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(adc->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(adc->adclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rzg2l_adc_pwr(adc, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rzg2l_adc_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend,
|
||||
rzg2l_adc_pm_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver rzg2l_adc_driver = {
|
||||
.probe = rzg2l_adc_probe,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = rzg2l_adc_match,
|
||||
.pm = &rzg2l_adc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(rzg2l_adc_driver);
|
||||
|
||||
MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>");
|
||||
MODULE_DESCRIPTION("Renesas RZ/G2L ADC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -131,6 +131,17 @@ config SENSIRION_SGP30
|
|||
To compile this driver as module, choose M here: the
|
||||
module will be called sgp30.
|
||||
|
||||
config SENSIRION_SGP40
|
||||
tristate "Sensirion SGP40 gas sensor"
|
||||
depends on I2C
|
||||
select CRC8
|
||||
help
|
||||
Say Y here to build I2C interface to support Sensirion SGP40 gas
|
||||
sensor
|
||||
|
||||
To compile this driver as module, choose M here: the
|
||||
module will be called sgp40.
|
||||
|
||||
config SPS30
|
||||
tristate
|
||||
select IIO_BUFFER
|
||||
|
|
|
@ -16,6 +16,7 @@ obj-$(CONFIG_SCD30_CORE) += scd30_core.o
|
|||
obj-$(CONFIG_SCD30_I2C) += scd30_i2c.o
|
||||
obj-$(CONFIG_SCD30_SERIAL) += scd30_serial.o
|
||||
obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o
|
||||
obj-$(CONFIG_SENSIRION_SGP40) += sgp40.o
|
||||
obj-$(CONFIG_SPS30) += sps30.o
|
||||
obj-$(CONFIG_SPS30_I2C) += sps30_i2c.o
|
||||
obj-$(CONFIG_SPS30_SERIAL) += sps30_serial.o
|
||||
|
|
|
@ -0,0 +1,378 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* sgp40.c - Support for Sensirion SGP40 Gas Sensor
|
||||
*
|
||||
* Copyright (C) 2021 Andreas Klinger <ak@it-klinger.de>
|
||||
*
|
||||
* I2C slave address: 0x59
|
||||
*
|
||||
* Datasheet can be found here:
|
||||
* https://www.sensirion.com/file/datasheet_sgp40
|
||||
*
|
||||
* There are two functionalities supported:
|
||||
*
|
||||
* 1) read raw logarithmic resistance value from sensor
|
||||
* --> useful to pass it to the algorithm of the sensor vendor for
|
||||
* measuring deteriorations and improvements of air quality.
|
||||
*
|
||||
* 2) calculate an estimated absolute voc index (0 - 500 index points) for
|
||||
* measuring the air quality.
|
||||
* For this purpose the value of the resistance for which the voc index
|
||||
* will be 250 can be set up using calibbias.
|
||||
*
|
||||
* Compensation values of relative humidity and temperature can be set up
|
||||
* by writing to the out values of temp and humidityrelative.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/crc8.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
/*
|
||||
* floating point calculation of voc is done as integer
|
||||
* where numbers are multiplied by 1 << SGP40_CALC_POWER
|
||||
*/
|
||||
#define SGP40_CALC_POWER 14
|
||||
|
||||
#define SGP40_CRC8_POLYNOMIAL 0x31
|
||||
#define SGP40_CRC8_INIT 0xff
|
||||
|
||||
DECLARE_CRC8_TABLE(sgp40_crc8_table);
|
||||
|
||||
struct sgp40_data {
|
||||
struct device *dev;
|
||||
struct i2c_client *client;
|
||||
int rht;
|
||||
int temp;
|
||||
int res_calibbias;
|
||||
/* Prevent concurrent access to rht, tmp, calibbias */
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
struct sgp40_tg_measure {
|
||||
u8 command[2];
|
||||
__be16 rht_ticks;
|
||||
u8 rht_crc;
|
||||
__be16 temp_ticks;
|
||||
u8 temp_crc;
|
||||
} __packed;
|
||||
|
||||
struct sgp40_tg_result {
|
||||
__be16 res_ticks;
|
||||
u8 res_crc;
|
||||
} __packed;
|
||||
|
||||
static const struct iio_chan_spec sgp40_channels[] = {
|
||||
{
|
||||
.type = IIO_CONCENTRATION,
|
||||
.channel2 = IIO_MOD_VOC,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
},
|
||||
{
|
||||
.type = IIO_RESISTANCE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS),
|
||||
},
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.output = 1,
|
||||
},
|
||||
{
|
||||
.type = IIO_HUMIDITYRELATIVE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.output = 1,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* taylor approximation of e^x:
|
||||
* y = 1 + x + x^2 / 2 + x^3 / 6 + x^4 / 24 + ... + x^n / n!
|
||||
*
|
||||
* Because we are calculating x real value multiplied by 2^power we get
|
||||
* an additional 2^power^n to divide for every element. For a reasonable
|
||||
* precision this would overflow after a few iterations. Therefore we
|
||||
* divide the x^n part whenever its about to overflow (xmax).
|
||||
*/
|
||||
|
||||
static u32 sgp40_exp(int exp, u32 power, u32 rounds)
|
||||
{
|
||||
u32 x, y, xp;
|
||||
u32 factorial, divider, xmax;
|
||||
int sign = 1;
|
||||
int i;
|
||||
|
||||
if (exp == 0)
|
||||
return 1 << power;
|
||||
else if (exp < 0) {
|
||||
sign = -1;
|
||||
exp *= -1;
|
||||
}
|
||||
|
||||
xmax = 0x7FFFFFFF / exp;
|
||||
x = exp;
|
||||
xp = 1;
|
||||
factorial = 1;
|
||||
y = 1 << power;
|
||||
divider = 0;
|
||||
|
||||
for (i = 1; i <= rounds; i++) {
|
||||
xp *= x;
|
||||
factorial *= i;
|
||||
y += (xp >> divider) / factorial;
|
||||
divider += power;
|
||||
/* divide when next multiplication would overflow */
|
||||
if (xp >= xmax) {
|
||||
xp >>= power;
|
||||
divider -= power;
|
||||
}
|
||||
}
|
||||
|
||||
if (sign == -1)
|
||||
return (1 << (power * 2)) / y;
|
||||
else
|
||||
return y;
|
||||
}
|
||||
|
||||
static int sgp40_calc_voc(struct sgp40_data *data, u16 resistance_raw, int *voc)
|
||||
{
|
||||
int x;
|
||||
u32 exp = 0;
|
||||
|
||||
/* we calculate as a multiple of 16384 (2^14) */
|
||||
mutex_lock(&data->lock);
|
||||
x = ((int)resistance_raw - data->res_calibbias) * 106;
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
/* voc = 500 / (1 + e^x) */
|
||||
exp = sgp40_exp(x, SGP40_CALC_POWER, 18);
|
||||
*voc = 500 * ((1 << (SGP40_CALC_POWER * 2)) / ((1<<SGP40_CALC_POWER) + exp));
|
||||
|
||||
dev_dbg(data->dev, "raw: %d res_calibbias: %d x: %d exp: %d voc: %d\n",
|
||||
resistance_raw, data->res_calibbias, x, exp, *voc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sgp40_measure_resistance_raw(struct sgp40_data *data, u16 *resistance_raw)
|
||||
{
|
||||
int ret;
|
||||
struct i2c_client *client = data->client;
|
||||
u32 ticks;
|
||||
u16 ticks16;
|
||||
u8 crc;
|
||||
struct sgp40_tg_measure tg = {.command = {0x26, 0x0F}};
|
||||
struct sgp40_tg_result tgres;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
ticks = (data->rht / 10) * 65535 / 10000;
|
||||
ticks16 = (u16)clamp(ticks, 0u, 65535u); /* clamp between 0 .. 100 %rH */
|
||||
tg.rht_ticks = cpu_to_be16(ticks16);
|
||||
tg.rht_crc = crc8(sgp40_crc8_table, (u8 *)&tg.rht_ticks, 2, SGP40_CRC8_INIT);
|
||||
|
||||
ticks = ((data->temp + 45000) / 10 ) * 65535 / 17500;
|
||||
ticks16 = (u16)clamp(ticks, 0u, 65535u); /* clamp between -45 .. +130 °C */
|
||||
tg.temp_ticks = cpu_to_be16(ticks16);
|
||||
tg.temp_crc = crc8(sgp40_crc8_table, (u8 *)&tg.temp_ticks, 2, SGP40_CRC8_INIT);
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
ret = i2c_master_send(client, (const char *)&tg, sizeof(tg));
|
||||
if (ret != sizeof(tg)) {
|
||||
dev_warn(data->dev, "i2c_master_send ret: %d sizeof: %zu\n", ret, sizeof(tg));
|
||||
return -EIO;
|
||||
}
|
||||
msleep(30);
|
||||
|
||||
ret = i2c_master_recv(client, (u8 *)&tgres, sizeof(tgres));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != sizeof(tgres)) {
|
||||
dev_warn(data->dev, "i2c_master_recv ret: %d sizeof: %zu\n", ret, sizeof(tgres));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
crc = crc8(sgp40_crc8_table, (u8 *)&tgres.res_ticks, 2, SGP40_CRC8_INIT);
|
||||
if (crc != tgres.res_crc) {
|
||||
dev_err(data->dev, "CRC error while measure-raw\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*resistance_raw = be16_to_cpu(tgres.res_ticks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sgp40_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct sgp40_data *data = iio_priv(indio_dev);
|
||||
int ret, voc;
|
||||
u16 resistance_raw;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
switch (chan->type) {
|
||||
case IIO_RESISTANCE:
|
||||
ret = sgp40_measure_resistance_raw(data, &resistance_raw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = resistance_raw;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_TEMP:
|
||||
mutex_lock(&data->lock);
|
||||
*val = data->temp;
|
||||
mutex_unlock(&data->lock);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_HUMIDITYRELATIVE:
|
||||
mutex_lock(&data->lock);
|
||||
*val = data->rht;
|
||||
mutex_unlock(&data->lock);
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
ret = sgp40_measure_resistance_raw(data, &resistance_raw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sgp40_calc_voc(data, resistance_raw, &voc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = voc / (1 << SGP40_CALC_POWER);
|
||||
/*
|
||||
* calculation should fit into integer, where:
|
||||
* voc <= (500 * 2^SGP40_CALC_POWER) = 8192000
|
||||
* (with SGP40_CALC_POWER = 14)
|
||||
*/
|
||||
*val2 = ((voc % (1 << SGP40_CALC_POWER)) * 244) / (1 << (SGP40_CALC_POWER - 12));
|
||||
dev_dbg(data->dev, "voc: %d val: %d.%06d\n", voc, *val, *val2);
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
mutex_lock(&data->lock);
|
||||
*val = data->res_calibbias;
|
||||
mutex_unlock(&data->lock);
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int sgp40_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int val,
|
||||
int val2, long mask)
|
||||
{
|
||||
struct sgp40_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
if ((val < -45000) || (val > 130000))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
data->temp = val;
|
||||
mutex_unlock(&data->lock);
|
||||
return 0;
|
||||
case IIO_HUMIDITYRELATIVE:
|
||||
if ((val < 0) || (val > 100000))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
data->rht = val;
|
||||
mutex_unlock(&data->lock);
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
if ((val < 20000) || (val > 52768))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
data->res_calibbias = val;
|
||||
mutex_unlock(&data->lock);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info sgp40_info = {
|
||||
.read_raw = sgp40_read_raw,
|
||||
.write_raw = sgp40_write_raw,
|
||||
};
|
||||
|
||||
static int sgp40_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct sgp40_data *data;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
data->client = client;
|
||||
data->dev = dev;
|
||||
|
||||
crc8_populate_msb(sgp40_crc8_table, SGP40_CRC8_POLYNOMIAL);
|
||||
|
||||
mutex_init(&data->lock);
|
||||
|
||||
/* set default values */
|
||||
data->rht = 50000; /* 50 % */
|
||||
data->temp = 25000; /* 25 °C */
|
||||
data->res_calibbias = 30000; /* resistance raw value for voc index of 250 */
|
||||
|
||||
indio_dev->info = &sgp40_info;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = sgp40_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(sgp40_channels);
|
||||
|
||||
ret = devm_iio_device_register(dev, indio_dev);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to register iio device\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id sgp40_id[] = {
|
||||
{ "sgp40" },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, sgp40_id);
|
||||
|
||||
static const struct of_device_id sgp40_dt_ids[] = {
|
||||
{ .compatible = "sensirion,sgp40" },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, sgp40_dt_ids);
|
||||
|
||||
static struct i2c_driver sgp40_driver = {
|
||||
.driver = {
|
||||
.name = "sgp40",
|
||||
.of_match_table = sgp40_dt_ids,
|
||||
},
|
||||
.probe = sgp40_probe,
|
||||
.id_table = sgp40_id,
|
||||
};
|
||||
module_i2c_driver(sgp40_driver);
|
||||
|
||||
MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
|
||||
MODULE_DESCRIPTION("Sensirion SGP40 gas sensor");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -9,13 +9,11 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/regmap.h>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
#ifndef __ST_SENSORS_CORE_H
|
||||
#define __ST_SENSORS_CORE_H
|
||||
struct iio_dev;
|
||||
int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
|
||||
u8 reg_addr, u8 mask, u8 data);
|
||||
#endif
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
* Denis Ciocca <denis.ciocca@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors_i2c.h>
|
||||
|
||||
|
||||
#define ST_SENSORS_I2C_MULTIREAD 0x80
|
||||
|
||||
static const struct regmap_config st_sensors_i2c_regmap_config = {
|
||||
|
|
|
@ -9,13 +9,12 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors_spi.h>
|
||||
#include "st_sensors_core.h"
|
||||
|
||||
#define ST_SENSORS_SPI_MULTIREAD 0xc0
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
|
|
@ -229,7 +229,7 @@ static int ad5624r_probe(struct spi_device *spi)
|
|||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
st = iio_priv(indio_dev);
|
||||
st->reg = devm_regulator_get(&spi->dev, "vcc");
|
||||
st->reg = devm_regulator_get_optional(&spi->dev, "vref");
|
||||
if (!IS_ERR(st->reg)) {
|
||||
ret = regulator_enable(st->reg);
|
||||
if (ret)
|
||||
|
@ -240,6 +240,22 @@ static int ad5624r_probe(struct spi_device *spi)
|
|||
goto error_disable_reg;
|
||||
|
||||
voltage_uv = ret;
|
||||
} else {
|
||||
if (PTR_ERR(st->reg) != -ENODEV)
|
||||
return PTR_ERR(st->reg);
|
||||
/* Backwards compatibility. This naming is not correct */
|
||||
st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
|
||||
if (!IS_ERR(st->reg)) {
|
||||
ret = regulator_enable(st->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_get_voltage(st->reg);
|
||||
if (ret < 0)
|
||||
goto error_disable_reg;
|
||||
|
||||
voltage_uv = ret;
|
||||
}
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
|
|
@ -294,6 +294,11 @@ static const struct iio_info max5821_info = {
|
|||
.write_raw = max5821_write_raw,
|
||||
};
|
||||
|
||||
static void max5821_regulator_disable(void *reg)
|
||||
{
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static int max5821_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -306,7 +311,6 @@ static int max5821_probe(struct i2c_client *client,
|
|||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
|
@ -321,21 +325,29 @@ static int max5821_probe(struct i2c_client *client,
|
|||
ret = PTR_ERR(data->vref_reg);
|
||||
dev_err(&client->dev,
|
||||
"Failed to get vref regulator: %d\n", ret);
|
||||
goto error_free_reg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_enable(data->vref_reg);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to enable vref regulator: %d\n", ret);
|
||||
goto error_free_reg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&client->dev, max5821_regulator_disable,
|
||||
data->vref_reg);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to add action to managed regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_get_voltage(data->vref_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to get voltage on regulator: %d\n", ret);
|
||||
goto error_disable_reg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->vref_mv = ret / 1000;
|
||||
|
@ -346,25 +358,7 @@ static int max5821_probe(struct i2c_client *client,
|
|||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &max5821_info;
|
||||
|
||||
return iio_device_register(indio_dev);
|
||||
|
||||
error_disable_reg:
|
||||
regulator_disable(data->vref_reg);
|
||||
|
||||
error_free_reg:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max5821_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct max5821_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
regulator_disable(data->vref_reg);
|
||||
|
||||
return 0;
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max5821_id[] = {
|
||||
|
@ -386,7 +380,6 @@ static struct i2c_driver max5821_driver = {
|
|||
.pm = &max5821_pm_ops,
|
||||
},
|
||||
.probe = max5821_probe,
|
||||
.remove = max5821_remove,
|
||||
.id_table = max5821_id,
|
||||
};
|
||||
module_i2c_driver(max5821_driver);
|
||||
|
|
|
@ -303,8 +303,8 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->channels = kmemdup(gyro_3d_channels,
|
||||
sizeof(gyro_3d_channels), GFP_KERNEL);
|
||||
indio_dev->channels = devm_kmemdup(&pdev->dev, gyro_3d_channels,
|
||||
sizeof(gyro_3d_channels), GFP_KERNEL);
|
||||
if (!indio_dev->channels) {
|
||||
dev_err(&pdev->dev, "failed to duplicate channels\n");
|
||||
return -ENOMEM;
|
||||
|
@ -315,7 +315,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
|
|||
HID_USAGE_SENSOR_GYRO_3D, gyro_state);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to setup attributes\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels);
|
||||
|
@ -329,7 +329,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
|
|||
&gyro_state->common_attributes);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "trigger setup failed\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
@ -354,8 +354,6 @@ error_iio_unreg:
|
|||
iio_device_unregister(indio_dev);
|
||||
error_remove_trigger:
|
||||
hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
|
||||
error_free_dev_mem:
|
||||
kfree(indio_dev->channels);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -369,7 +367,6 @@ static int hid_gyro_3d_remove(struct platform_device *pdev)
|
|||
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
|
||||
iio_device_unregister(indio_dev);
|
||||
hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
|
||||
kfree(indio_dev->channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
#ifdef CONFIG_IIO_BUFFER
|
||||
int st_gyro_allocate_ring(struct iio_dev *indio_dev);
|
||||
void st_gyro_deallocate_ring(struct iio_dev *indio_dev);
|
||||
int st_gyro_trig_set_state(struct iio_trigger *trig, bool state);
|
||||
#define ST_GYRO_TRIGGER_SET_STATE (&st_gyro_trig_set_state)
|
||||
#else /* CONFIG_IIO_BUFFER */
|
||||
|
@ -34,9 +33,6 @@ static inline int st_gyro_allocate_ring(struct iio_dev *indio_dev)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void st_gyro_deallocate_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
}
|
||||
#define ST_GYRO_TRIGGER_SET_STATE NULL
|
||||
#endif /* CONFIG_IIO_BUFFER */
|
||||
|
||||
|
|
|
@ -9,14 +9,9 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
|
@ -66,13 +61,8 @@ static const struct iio_buffer_setup_ops st_gyro_buffer_setup_ops = {
|
|||
|
||||
int st_gyro_allocate_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
return iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
&st_sensors_trigger_handler, &st_gyro_buffer_setup_ops);
|
||||
}
|
||||
|
||||
void st_gyro_deallocate_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
|
||||
NULL, &st_sensors_trigger_handler, &st_gyro_buffer_setup_ops);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
|
||||
|
|
|
@ -9,17 +9,12 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
#include "st_gyro.h"
|
||||
|
@ -517,7 +512,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
|
|||
err = st_sensors_allocate_trigger(indio_dev,
|
||||
ST_GYRO_TRIGGER_OPS);
|
||||
if (err < 0)
|
||||
goto st_gyro_probe_trigger_error;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = iio_device_register(indio_dev);
|
||||
|
@ -532,8 +527,6 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
|
|||
st_gyro_device_register_error:
|
||||
if (gdata->irq > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
st_gyro_probe_trigger_error:
|
||||
st_gyro_deallocate_ring(indio_dev);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(st_gyro_common_probe);
|
||||
|
@ -545,8 +538,6 @@ void st_gyro_common_remove(struct iio_dev *indio_dev)
|
|||
iio_device_unregister(indio_dev);
|
||||
if (gdata->irq > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
|
||||
st_gyro_deallocate_ring(indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(st_gyro_common_remove);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
|
|
|
@ -143,6 +143,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6050,
|
||||
.fifo_size = 1024,
|
||||
.temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6050_GYRO_STARTUP_TIME, INV_MPU6050_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_MPU6500_WHOAMI_VALUE,
|
||||
|
@ -151,6 +152,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6500,
|
||||
.fifo_size = 512,
|
||||
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_MPU6515_WHOAMI_VALUE,
|
||||
|
@ -159,6 +161,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6500,
|
||||
.fifo_size = 512,
|
||||
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_MPU6880_WHOAMI_VALUE,
|
||||
|
@ -167,6 +170,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6500,
|
||||
.fifo_size = 4096,
|
||||
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_MPU6000_WHOAMI_VALUE,
|
||||
|
@ -175,6 +179,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6050,
|
||||
.fifo_size = 1024,
|
||||
.temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6050_GYRO_STARTUP_TIME, INV_MPU6050_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_MPU9150_WHOAMI_VALUE,
|
||||
|
@ -183,6 +188,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6050,
|
||||
.fifo_size = 1024,
|
||||
.temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6050_GYRO_STARTUP_TIME, INV_MPU6050_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_MPU9250_WHOAMI_VALUE,
|
||||
|
@ -191,6 +197,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6500,
|
||||
.fifo_size = 512,
|
||||
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_MPU9255_WHOAMI_VALUE,
|
||||
|
@ -199,6 +206,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6500,
|
||||
.fifo_size = 512,
|
||||
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_ICM20608_WHOAMI_VALUE,
|
||||
|
@ -207,6 +215,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6500,
|
||||
.fifo_size = 512,
|
||||
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_ICM20609_WHOAMI_VALUE,
|
||||
|
@ -215,6 +224,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6500,
|
||||
.fifo_size = 4 * 1024,
|
||||
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_ICM20689_WHOAMI_VALUE,
|
||||
|
@ -223,6 +233,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6500,
|
||||
.fifo_size = 4 * 1024,
|
||||
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_ICM20602_WHOAMI_VALUE,
|
||||
|
@ -231,6 +242,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6500,
|
||||
.fifo_size = 1008,
|
||||
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
|
||||
.startup_time = {INV_ICM20602_GYRO_STARTUP_TIME, INV_ICM20602_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_ICM20690_WHOAMI_VALUE,
|
||||
|
@ -239,6 +251,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6500,
|
||||
.fifo_size = 1024,
|
||||
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
|
||||
.startup_time = {INV_ICM20690_GYRO_STARTUP_TIME, INV_ICM20690_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
{
|
||||
.whoami = INV_IAM20680_WHOAMI_VALUE,
|
||||
|
@ -247,6 +260,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
|||
.config = &chip_config_6500,
|
||||
.fifo_size = 512,
|
||||
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
|
||||
.startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -379,12 +393,12 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en,
|
|||
sleep = 0;
|
||||
if (en) {
|
||||
if (mask & INV_MPU6050_SENSOR_ACCL) {
|
||||
if (sleep < INV_MPU6050_ACCEL_UP_TIME)
|
||||
sleep = INV_MPU6050_ACCEL_UP_TIME;
|
||||
if (sleep < st->hw->startup_time.accel)
|
||||
sleep = st->hw->startup_time.accel;
|
||||
}
|
||||
if (mask & INV_MPU6050_SENSOR_GYRO) {
|
||||
if (sleep < INV_MPU6050_GYRO_UP_TIME)
|
||||
sleep = INV_MPU6050_GYRO_UP_TIME;
|
||||
if (sleep < st->hw->startup_time.gyro)
|
||||
sleep = st->hw->startup_time.gyro;
|
||||
}
|
||||
} else {
|
||||
if (mask & INV_MPU6050_SENSOR_GYRO) {
|
||||
|
|
|
@ -149,6 +149,10 @@ struct inv_mpu6050_hw {
|
|||
int offset;
|
||||
int scale;
|
||||
} temp;
|
||||
struct {
|
||||
unsigned int accel;
|
||||
unsigned int gyro;
|
||||
} startup_time;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -320,11 +324,21 @@ struct inv_mpu6050_state {
|
|||
/* delay time in milliseconds */
|
||||
#define INV_MPU6050_POWER_UP_TIME 100
|
||||
#define INV_MPU6050_TEMP_UP_TIME 100
|
||||
#define INV_MPU6050_ACCEL_UP_TIME 20
|
||||
#define INV_MPU6050_GYRO_UP_TIME 35
|
||||
#define INV_MPU6050_ACCEL_STARTUP_TIME 20
|
||||
#define INV_MPU6050_GYRO_STARTUP_TIME 60
|
||||
#define INV_MPU6050_GYRO_DOWN_TIME 150
|
||||
#define INV_MPU6050_SUSPEND_DELAY_MS 2000
|
||||
|
||||
#define INV_MPU6500_GYRO_STARTUP_TIME 70
|
||||
#define INV_MPU6500_ACCEL_STARTUP_TIME 30
|
||||
|
||||
#define INV_ICM20602_GYRO_STARTUP_TIME 100
|
||||
#define INV_ICM20602_ACCEL_STARTUP_TIME 20
|
||||
|
||||
#define INV_ICM20690_GYRO_STARTUP_TIME 80
|
||||
#define INV_ICM20690_ACCEL_STARTUP_TIME 10
|
||||
|
||||
|
||||
/* delay time in microseconds */
|
||||
#define INV_MPU6050_REG_UP_TIME_MIN 5000
|
||||
#define INV_MPU6050_REG_UP_TIME_MAX 10000
|
||||
|
|
|
@ -91,22 +91,11 @@ static unsigned int inv_scan_query(struct iio_dev *indio_dev)
|
|||
|
||||
static unsigned int inv_compute_skip_samples(const struct inv_mpu6050_state *st)
|
||||
{
|
||||
unsigned int gyro_skip = 0;
|
||||
unsigned int magn_skip = 0;
|
||||
unsigned int skip_samples;
|
||||
|
||||
/* gyro first sample is out of specs, skip it */
|
||||
if (st->chip_config.gyro_fifo_enable)
|
||||
gyro_skip = 1;
|
||||
unsigned int skip_samples = 0;
|
||||
|
||||
/* mag first sample is always not ready, skip it */
|
||||
if (st->chip_config.magn_fifo_enable)
|
||||
magn_skip = 1;
|
||||
|
||||
/* compute first samples to skip */
|
||||
skip_samples = gyro_skip;
|
||||
if (magn_skip > skip_samples)
|
||||
skip_samples = magn_skip;
|
||||
skip_samples = 1;
|
||||
|
||||
return skip_samples;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors_i2c.h>
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors_spi.h>
|
||||
|
|
|
@ -354,13 +354,14 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev,
|
|||
const unsigned long *mask;
|
||||
unsigned long *trialmask;
|
||||
|
||||
trialmask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL);
|
||||
if (trialmask == NULL)
|
||||
return -ENOMEM;
|
||||
if (!indio_dev->masklength) {
|
||||
WARN(1, "Trying to set scanmask prior to registering buffer\n");
|
||||
goto err_invalid_mask;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
trialmask = bitmap_alloc(indio_dev->masklength, GFP_KERNEL);
|
||||
if (!trialmask)
|
||||
return -ENOMEM;
|
||||
bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
|
||||
set_bit(bit, trialmask);
|
||||
|
||||
|
|
|
@ -740,10 +740,13 @@ static ssize_t iio_read_channel_label(struct device *dev,
|
|||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
|
||||
if (!indio_dev->info->read_label)
|
||||
return -EINVAL;
|
||||
if (indio_dev->info->read_label)
|
||||
return indio_dev->info->read_label(indio_dev, this_attr->c, buf);
|
||||
|
||||
return indio_dev->info->read_label(indio_dev, this_attr->c, buf);
|
||||
if (this_attr->c->extend_name)
|
||||
return sprintf(buf, "%s\n", this_attr->c->extend_name);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static ssize_t iio_read_channel_info(struct device *dev,
|
||||
|
@ -1183,7 +1186,7 @@ static int iio_device_add_channel_label(struct iio_dev *indio_dev,
|
|||
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (!indio_dev->info->read_label)
|
||||
if (!indio_dev->info->read_label && !chan->extend_name)
|
||||
return 0;
|
||||
|
||||
ret = __iio_add_chan_devattr("label",
|
||||
|
@ -1858,6 +1861,24 @@ static int iio_check_unique_scan_index(struct iio_dev *indio_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int iio_check_extended_name(const struct iio_dev *indio_dev)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!indio_dev->info->read_label)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < indio_dev->num_channels; i++) {
|
||||
if (indio_dev->channels[i].extend_name) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"Cannot use labels and extend_name at the same time\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops noop_ring_setup_ops;
|
||||
|
||||
int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
|
||||
|
@ -1882,6 +1903,10 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_check_extended_name(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
iio_device_register_debugfs(indio_dev);
|
||||
|
||||
ret = iio_buffers_alloc_sysfs_and_mask(indio_dev);
|
||||
|
|
|
@ -54,7 +54,10 @@
|
|||
|
||||
struct adjd_s311_data {
|
||||
struct i2c_client *client;
|
||||
u16 *buffer;
|
||||
struct {
|
||||
s16 chans[4];
|
||||
s64 ts __aligned(8);
|
||||
} scan;
|
||||
};
|
||||
|
||||
enum adjd_s311_channel_idx {
|
||||
|
@ -129,10 +132,10 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
|
|||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
data->buffer[j++] = ret & ADJD_S311_DATA_MASK;
|
||||
data->scan.chans[j++] = ret & ADJD_S311_DATA_MASK;
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, time_ns);
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns);
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
@ -225,23 +228,9 @@ static int adjd_s311_write_raw(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adjd_s311_update_scan_mode(struct iio_dev *indio_dev,
|
||||
const unsigned long *scan_mask)
|
||||
{
|
||||
struct adjd_s311_data *data = iio_priv(indio_dev);
|
||||
|
||||
kfree(data->buffer);
|
||||
data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
|
||||
if (data->buffer == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_info adjd_s311_info = {
|
||||
.read_raw = adjd_s311_read_raw,
|
||||
.write_raw = adjd_s311_write_raw,
|
||||
.update_scan_mode = adjd_s311_update_scan_mode,
|
||||
};
|
||||
|
||||
static int adjd_s311_probe(struct i2c_client *client,
|
||||
|
@ -256,7 +245,6 @@ static int adjd_s311_probe(struct i2c_client *client,
|
|||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
|
||||
indio_dev->info = &adjd_s311_info;
|
||||
|
@ -265,34 +253,12 @@ static int adjd_s311_probe(struct i2c_client *client,
|
|||
indio_dev->num_channels = ARRAY_SIZE(adjd_s311_channels);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
err = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
adjd_s311_trigger_handler, NULL);
|
||||
err = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
|
||||
adjd_s311_trigger_handler, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = iio_device_register(indio_dev);
|
||||
if (err)
|
||||
goto exit_unreg_buffer;
|
||||
|
||||
dev_info(&client->dev, "ADJD-S311 color sensor registered\n");
|
||||
|
||||
return 0;
|
||||
|
||||
exit_unreg_buffer:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adjd_s311_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct adjd_s311_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
kfree(data->buffer);
|
||||
|
||||
return 0;
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adjd_s311_id[] = {
|
||||
|
@ -306,7 +272,6 @@ static struct i2c_driver adjd_s311_driver = {
|
|||
.name = ADJD_S311_DRV_NAME,
|
||||
},
|
||||
.probe = adjd_s311_probe,
|
||||
.remove = adjd_s311_remove,
|
||||
.id_table = adjd_s311_id,
|
||||
};
|
||||
module_i2c_driver(adjd_s311_driver);
|
||||
|
|
|
@ -256,9 +256,16 @@ static const struct i2c_device_id cm3323_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cm3323_id);
|
||||
|
||||
static const struct of_device_id cm3323_of_match[] = {
|
||||
{ .compatible = "capella,cm3323", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cm3323_of_match);
|
||||
|
||||
static struct i2c_driver cm3323_driver = {
|
||||
.driver = {
|
||||
.name = CM3323_DRV_NAME,
|
||||
.of_match_table = cm3323_of_match,
|
||||
},
|
||||
.probe = cm3323_probe,
|
||||
.id_table = cm3323_id,
|
||||
|
|
|
@ -294,8 +294,8 @@ static int hid_als_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->channels = kmemdup(als_channels,
|
||||
sizeof(als_channels), GFP_KERNEL);
|
||||
indio_dev->channels = devm_kmemdup(&pdev->dev, als_channels,
|
||||
sizeof(als_channels), GFP_KERNEL);
|
||||
if (!indio_dev->channels) {
|
||||
dev_err(&pdev->dev, "failed to duplicate channels\n");
|
||||
return -ENOMEM;
|
||||
|
@ -306,7 +306,7 @@ static int hid_als_probe(struct platform_device *pdev)
|
|||
HID_USAGE_SENSOR_ALS, als_state);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to setup attributes\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->num_channels =
|
||||
|
@ -321,7 +321,7 @@ static int hid_als_probe(struct platform_device *pdev)
|
|||
&als_state->common_attributes);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "trigger setup failed\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
@ -346,8 +346,6 @@ error_iio_unreg:
|
|||
iio_device_unregister(indio_dev);
|
||||
error_remove_trigger:
|
||||
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
|
||||
error_free_dev_mem:
|
||||
kfree(indio_dev->channels);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -361,7 +359,6 @@ static int hid_als_remove(struct platform_device *pdev)
|
|||
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS);
|
||||
iio_device_unregister(indio_dev);
|
||||
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
|
||||
kfree(indio_dev->channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -253,8 +253,8 @@ static int hid_prox_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->channels = kmemdup(prox_channels, sizeof(prox_channels),
|
||||
GFP_KERNEL);
|
||||
indio_dev->channels = devm_kmemdup(&pdev->dev, prox_channels,
|
||||
sizeof(prox_channels), GFP_KERNEL);
|
||||
if (!indio_dev->channels) {
|
||||
dev_err(&pdev->dev, "failed to duplicate channels\n");
|
||||
return -ENOMEM;
|
||||
|
@ -265,7 +265,7 @@ static int hid_prox_probe(struct platform_device *pdev)
|
|||
HID_USAGE_SENSOR_PROX, prox_state);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to setup attributes\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->num_channels = ARRAY_SIZE(prox_channels);
|
||||
|
@ -279,7 +279,7 @@ static int hid_prox_probe(struct platform_device *pdev)
|
|||
&prox_state->common_attributes);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "trigger setup failed\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
@ -304,8 +304,6 @@ error_iio_unreg:
|
|||
iio_device_unregister(indio_dev);
|
||||
error_remove_trigger:
|
||||
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
|
||||
error_free_dev_mem:
|
||||
kfree(indio_dev->channels);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -319,7 +317,6 @@ static int hid_prox_remove(struct platform_device *pdev)
|
|||
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX);
|
||||
iio_device_unregister(indio_dev);
|
||||
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
|
||||
kfree(indio_dev->channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -220,7 +220,6 @@ static int __si1145_command_reset(struct si1145_data *data)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
msleep(SI1145_COMMAND_MINSLEEP_MS);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -267,6 +267,18 @@ static const struct iio_buffer_setup_ops tcs3414_buffer_setup_ops = {
|
|||
.predisable = tcs3414_buffer_predisable,
|
||||
};
|
||||
|
||||
static int tcs3414_powerdown(struct tcs3414_data *data)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
|
||||
data->control & ~(TCS3414_CONTROL_POWER |
|
||||
TCS3414_CONTROL_ADC_EN));
|
||||
}
|
||||
|
||||
static void tcs3414_powerdown_cleanup(void *data)
|
||||
{
|
||||
tcs3414_powerdown(data);
|
||||
}
|
||||
|
||||
static int tcs3414_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -309,6 +321,11 @@ static int tcs3414_probe(struct i2c_client *client,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&client->dev, tcs3414_powerdown_cleanup,
|
||||
data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->timing = TCS3414_INTEG_12MS; /* free running */
|
||||
ret = i2c_smbus_write_byte_data(data->client, TCS3414_TIMING,
|
||||
data->timing);
|
||||
|
@ -320,38 +337,12 @@ static int tcs3414_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
data->gain = ret;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
|
||||
tcs3414_trigger_handler, &tcs3414_buffer_setup_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0)
|
||||
goto buffer_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tcs3414_powerdown(struct tcs3414_data *data)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
|
||||
data->control & ~(TCS3414_CONTROL_POWER |
|
||||
TCS3414_CONTROL_ADC_EN));
|
||||
}
|
||||
|
||||
static int tcs3414_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
tcs3414_powerdown(iio_priv(indio_dev));
|
||||
|
||||
return 0;
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -385,7 +376,6 @@ static struct i2c_driver tcs3414_driver = {
|
|||
.pm = &tcs3414_pm_ops,
|
||||
},
|
||||
.probe = tcs3414_probe,
|
||||
.remove = tcs3414_remove,
|
||||
.id_table = tcs3414_id,
|
||||
};
|
||||
module_i2c_driver(tcs3414_driver);
|
||||
|
|
|
@ -25,25 +25,13 @@
|
|||
|
||||
#ifdef CONFIG_IIO_BUFFER
|
||||
int st_magn_allocate_ring(struct iio_dev *indio_dev);
|
||||
void st_magn_deallocate_ring(struct iio_dev *indio_dev);
|
||||
int st_magn_trig_set_state(struct iio_trigger *trig, bool state);
|
||||
#define ST_MAGN_TRIGGER_SET_STATE (&st_magn_trig_set_state)
|
||||
#else /* CONFIG_IIO_BUFFER */
|
||||
static inline int st_magn_probe_trigger(struct iio_dev *indio_dev, int irq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void st_magn_remove_trigger(struct iio_dev *indio_dev, int irq)
|
||||
{
|
||||
return;
|
||||
}
|
||||
static inline int st_magn_allocate_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void st_magn_deallocate_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
}
|
||||
#define ST_MAGN_TRIGGER_SET_STATE NULL
|
||||
#endif /* CONFIG_IIO_BUFFER */
|
||||
|
||||
|
|
|
@ -9,14 +9,9 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
|
@ -46,13 +41,8 @@ static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
|
|||
|
||||
int st_magn_allocate_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
return iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
&st_sensors_trigger_handler, &st_magn_buffer_setup_ops);
|
||||
}
|
||||
|
||||
void st_magn_deallocate_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
|
||||
NULL, &st_sensors_trigger_handler, &st_magn_buffer_setup_ops);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
|
||||
|
|
|
@ -9,16 +9,11 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
#include "st_magn.h"
|
||||
|
@ -652,7 +647,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
|
|||
err = st_sensors_allocate_trigger(indio_dev,
|
||||
ST_MAGN_TRIGGER_OPS);
|
||||
if (err < 0)
|
||||
goto st_magn_probe_trigger_error;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = iio_device_register(indio_dev);
|
||||
|
@ -667,8 +662,6 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
|
|||
st_magn_device_register_error:
|
||||
if (mdata->irq > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
st_magn_probe_trigger_error:
|
||||
st_magn_deallocate_ring(indio_dev);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(st_magn_common_probe);
|
||||
|
@ -680,8 +673,6 @@ void st_magn_common_remove(struct iio_dev *indio_dev)
|
|||
iio_device_unregister(indio_dev);
|
||||
if (mdata->irq > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
|
||||
st_magn_deallocate_ring(indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(st_magn_common_remove);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
|
|
|
@ -326,8 +326,8 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->channels = kmemdup(incl_3d_channels,
|
||||
sizeof(incl_3d_channels), GFP_KERNEL);
|
||||
indio_dev->channels = devm_kmemdup(&pdev->dev, incl_3d_channels,
|
||||
sizeof(incl_3d_channels), GFP_KERNEL);
|
||||
if (!indio_dev->channels) {
|
||||
dev_err(&pdev->dev, "failed to duplicate channels\n");
|
||||
return -ENOMEM;
|
||||
|
@ -339,7 +339,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
|
|||
incl_state);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to setup attributes\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->num_channels = ARRAY_SIZE(incl_3d_channels);
|
||||
|
@ -353,7 +353,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
|
|||
&incl_state->common_attributes);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "trigger setup failed\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
@ -379,8 +379,6 @@ error_iio_unreg:
|
|||
iio_device_unregister(indio_dev);
|
||||
error_remove_trigger:
|
||||
hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
|
||||
error_free_dev_mem:
|
||||
kfree(indio_dev->channels);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -394,7 +392,6 @@ static int hid_incl_3d_remove(struct platform_device *pdev)
|
|||
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D);
|
||||
iio_device_unregister(indio_dev);
|
||||
hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
|
||||
kfree(indio_dev->channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,16 @@
|
|||
|
||||
menu "Digital potentiometers"
|
||||
|
||||
config AD5110
|
||||
tristate "Analog Devices AD5110 and similar Digital Potentiometer driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for the Analog Devices AD5110, AD5112
|
||||
and AD5114 digital potentiometer chip.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad5110.
|
||||
|
||||
config AD5272
|
||||
tristate "Analog Devices AD5272 and similar Digital Potentiometer driver"
|
||||
depends on I2C
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_AD5110) += ad5110.o
|
||||
obj-$(CONFIG_AD5272) += ad5272.o
|
||||
obj-$(CONFIG_DS1803) += ds1803.o
|
||||
obj-$(CONFIG_MAX5432) += max5432.o
|
||||
|
|
|
@ -0,0 +1,344 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Analog Devices AD5110 digital potentiometer driver
|
||||
*
|
||||
* Copyright (C) 2021 Mugilraj Dhavachelvan <dmugil2000@gmail.com>
|
||||
*
|
||||
* Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/AD5110_5112_5114.pdf
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
/* AD5110 commands */
|
||||
#define AD5110_EEPROM_WR 1
|
||||
#define AD5110_RDAC_WR 2
|
||||
#define AD5110_SHUTDOWN 3
|
||||
#define AD5110_RESET 4
|
||||
#define AD5110_RDAC_RD 5
|
||||
#define AD5110_EEPROM_RD 6
|
||||
|
||||
/* AD5110_EEPROM_RD data */
|
||||
#define AD5110_WIPER_POS 0
|
||||
#define AD5110_RESISTOR_TOL 1
|
||||
|
||||
#define AD5110_WIPER_RESISTANCE 70
|
||||
|
||||
struct ad5110_cfg {
|
||||
int max_pos;
|
||||
int kohms;
|
||||
int shift;
|
||||
};
|
||||
|
||||
enum ad5110_type {
|
||||
AD5110_10,
|
||||
AD5110_80,
|
||||
AD5112_05,
|
||||
AD5112_10,
|
||||
AD5112_80,
|
||||
AD5114_10,
|
||||
AD5114_80,
|
||||
};
|
||||
|
||||
static const struct ad5110_cfg ad5110_cfg[] = {
|
||||
[AD5110_10] = { .max_pos = 128, .kohms = 10 },
|
||||
[AD5110_80] = { .max_pos = 128, .kohms = 80 },
|
||||
[AD5112_05] = { .max_pos = 64, .kohms = 5, .shift = 1 },
|
||||
[AD5112_10] = { .max_pos = 64, .kohms = 10, .shift = 1 },
|
||||
[AD5112_80] = { .max_pos = 64, .kohms = 80, .shift = 1 },
|
||||
[AD5114_10] = { .max_pos = 32, .kohms = 10, .shift = 2 },
|
||||
[AD5114_80] = { .max_pos = 32, .kohms = 80, .shift = 2 },
|
||||
};
|
||||
|
||||
struct ad5110_data {
|
||||
struct i2c_client *client;
|
||||
s16 tol; /* resistor tolerance */
|
||||
bool enable;
|
||||
struct mutex lock;
|
||||
const struct ad5110_cfg *cfg;
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires the
|
||||
* transfer buffers to live in their own cache lines.
|
||||
*/
|
||||
u8 buf[2] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad5110_channels[] = {
|
||||
{
|
||||
.type = IIO_RESISTANCE,
|
||||
.output = 1,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static int ad5110_read(struct ad5110_data *data, u8 cmd, int *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
data->buf[0] = cmd;
|
||||
data->buf[1] = *val;
|
||||
|
||||
ret = i2c_master_send_dmasafe(data->client, data->buf, sizeof(data->buf));
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
} else if (ret != sizeof(data->buf)) {
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = i2c_master_recv_dmasafe(data->client, data->buf, 1);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
} else if (ret != 1) {
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*val = data->buf[0];
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad5110_write(struct ad5110_data *data, u8 cmd, u8 val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
data->buf[0] = cmd;
|
||||
data->buf[1] = val;
|
||||
|
||||
ret = i2c_master_send_dmasafe(data->client, data->buf, sizeof(data->buf));
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
} else if (ret != sizeof(data->buf)) {
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad5110_resistor_tol(struct ad5110_data *data, u8 cmd, int val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ad5110_read(data, cmd, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->tol = data->cfg->kohms * (val & GENMASK(6, 0)) * 10 / 8;
|
||||
if (!(val & BIT(7)))
|
||||
data->tol *= -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_eeprom_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad5110_data *data = iio_priv(indio_dev);
|
||||
int val = AD5110_WIPER_POS;
|
||||
int ret;
|
||||
|
||||
ret = ad5110_read(data, AD5110_EEPROM_RD, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = val >> data->cfg->shift;
|
||||
return iio_format_value(buf, IIO_VAL_INT, 1, &val);
|
||||
}
|
||||
|
||||
static ssize_t store_eeprom_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad5110_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = ad5110_write(data, AD5110_EEPROM_WR, 0);
|
||||
if (ret) {
|
||||
dev_err(&data->client->dev, "RDAC to EEPROM write failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The storing of EEPROM data takes approximately 18 ms. */
|
||||
msleep(20);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR_RW(store_eeprom, 0);
|
||||
|
||||
static struct attribute *ad5110_attributes[] = {
|
||||
&iio_dev_attr_store_eeprom.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ad5110_attribute_group = {
|
||||
.attrs = ad5110_attributes,
|
||||
};
|
||||
|
||||
static int ad5110_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct ad5110_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = ad5110_read(data, AD5110_RDAC_RD, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = *val >> data->cfg->shift;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = AD5110_WIPER_RESISTANCE * data->cfg->max_pos;
|
||||
*val2 = 1000 * data->cfg->kohms + data->tol;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 1000 * data->cfg->kohms + data->tol;
|
||||
*val2 = data->cfg->max_pos;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_CHAN_INFO_ENABLE:
|
||||
*val = data->enable;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad5110_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct ad5110_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (val > data->cfg->max_pos || val < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return ad5110_write(data, AD5110_RDAC_WR, val << data->cfg->shift);
|
||||
case IIO_CHAN_INFO_ENABLE:
|
||||
if (val < 0 || val > 1)
|
||||
return -EINVAL;
|
||||
if (data->enable == val)
|
||||
return 0;
|
||||
ret = ad5110_write(data, AD5110_SHUTDOWN, val ? 0 : 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
data->enable = val;
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info ad5110_info = {
|
||||
.read_raw = ad5110_read_raw,
|
||||
.write_raw = ad5110_write_raw,
|
||||
.attrs = &ad5110_attribute_group,
|
||||
};
|
||||
|
||||
#define AD5110_COMPATIBLE(of_compatible, cfg) { \
|
||||
.compatible = of_compatible, \
|
||||
.data = &ad5110_cfg[cfg], \
|
||||
}
|
||||
|
||||
static const struct of_device_id ad5110_of_match[] = {
|
||||
AD5110_COMPATIBLE("adi,ad5110-10", AD5110_10),
|
||||
AD5110_COMPATIBLE("adi,ad5110-80", AD5110_80),
|
||||
AD5110_COMPATIBLE("adi,ad5112-05", AD5112_05),
|
||||
AD5110_COMPATIBLE("adi,ad5112-10", AD5112_10),
|
||||
AD5110_COMPATIBLE("adi,ad5112-80", AD5112_80),
|
||||
AD5110_COMPATIBLE("adi,ad5114-10", AD5114_10),
|
||||
AD5110_COMPATIBLE("adi,ad5114-80", AD5114_80),
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad5110_of_match);
|
||||
|
||||
static const struct i2c_device_id ad5110_id[] = {
|
||||
{ "ad5110-10", AD5110_10 },
|
||||
{ "ad5110-80", AD5110_80 },
|
||||
{ "ad5112-05", AD5112_05 },
|
||||
{ "ad5112-10", AD5112_10 },
|
||||
{ "ad5112-80", AD5112_80 },
|
||||
{ "ad5114-10", AD5114_10 },
|
||||
{ "ad5114-80", AD5114_80 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ad5110_id);
|
||||
|
||||
static int ad5110_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad5110_data *data;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
data->enable = 1;
|
||||
data->cfg = device_get_match_data(dev);
|
||||
|
||||
/* refresh RDAC register with EEPROM */
|
||||
ret = ad5110_write(data, AD5110_RESET, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "Refresh RDAC with EEPROM failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad5110_resistor_tol(data, AD5110_EEPROM_RD, AD5110_RESISTOR_TOL);
|
||||
if (ret) {
|
||||
dev_err(dev, "Read resistor tolerance failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &ad5110_info;
|
||||
indio_dev->channels = ad5110_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ad5110_channels);
|
||||
indio_dev->name = client->name;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static struct i2c_driver ad5110_driver = {
|
||||
.driver = {
|
||||
.name = "ad5110",
|
||||
.of_match_table = ad5110_of_match,
|
||||
},
|
||||
.probe_new = ad5110_probe,
|
||||
.id_table = ad5110_id,
|
||||
};
|
||||
module_i2c_driver(ad5110_driver);
|
||||
|
||||
MODULE_AUTHOR("Mugilraj Dhavachelvan <dmugil2000@gmail.com>");
|
||||
MODULE_DESCRIPTION("AD5110 digital potentiometer");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -125,6 +125,11 @@ static const struct of_device_id max5481_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, max5481_match);
|
||||
|
||||
static void max5481_wiper_save(void *data)
|
||||
{
|
||||
max5481_write_cmd(data, MAX5481_COPY_AB_TO_NV, 0);
|
||||
}
|
||||
|
||||
static int max5481_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
|
@ -136,7 +141,6 @@ static int max5481_probe(struct spi_device *spi)
|
|||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
data = iio_priv(indio_dev);
|
||||
|
||||
data->spi = spi;
|
||||
|
@ -158,18 +162,11 @@ static int max5481_probe(struct spi_device *spi)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return iio_device_register(indio_dev);
|
||||
}
|
||||
ret = devm_add_action(&spi->dev, max5481_wiper_save, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
static int max5481_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct max5481_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
/* save wiper reg to NV reg */
|
||||
return max5481_write_cmd(data, MAX5481_COPY_AB_TO_NV, 0);
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id max5481_id_table[] = {
|
||||
|
@ -187,7 +184,6 @@ static struct spi_driver max5481_driver = {
|
|||
.of_match_table = max5481_match,
|
||||
},
|
||||
.probe = max5481_probe,
|
||||
.remove = max5481_remove,
|
||||
.id_table = max5481_id_table,
|
||||
};
|
||||
|
||||
|
|
|
@ -13,17 +13,24 @@
|
|||
#include <linux/iio/buffer.h>
|
||||
#include "../common/hid-sensors/hid-sensor-trigger.h"
|
||||
|
||||
#define CHANNEL_SCAN_INDEX_PRESSURE 0
|
||||
enum {
|
||||
CHANNEL_SCAN_INDEX_PRESSURE,
|
||||
CHANNEL_SCAN_INDEX_TIMESTAMP,
|
||||
};
|
||||
|
||||
struct press_state {
|
||||
struct hid_sensor_hub_callbacks callbacks;
|
||||
struct hid_sensor_common common_attributes;
|
||||
struct hid_sensor_hub_attribute_info press_attr;
|
||||
u32 press_data;
|
||||
struct {
|
||||
u32 press_data;
|
||||
u64 timestamp __aligned(8);
|
||||
} scan;
|
||||
int scale_pre_decml;
|
||||
int scale_post_decml;
|
||||
int scale_precision;
|
||||
int value_offset;
|
||||
s64 timestamp;
|
||||
};
|
||||
|
||||
static const u32 press_sensitivity_addresses[] = {
|
||||
|
@ -41,7 +48,9 @@ static const struct iio_chan_spec press_channels[] = {
|
|||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_HYSTERESIS),
|
||||
.scan_index = CHANNEL_SCAN_INDEX_PRESSURE,
|
||||
}
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
|
||||
|
||||
};
|
||||
|
||||
/* Adjust channel real bits based on report descriptor */
|
||||
|
@ -154,14 +163,6 @@ static const struct iio_info press_info = {
|
|||
.write_raw = &press_write_raw,
|
||||
};
|
||||
|
||||
/* Function to push data to buffer */
|
||||
static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
|
||||
int len)
|
||||
{
|
||||
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
|
||||
iio_push_to_buffers(indio_dev, data);
|
||||
}
|
||||
|
||||
/* Callback handler to send event after all samples are received and captured */
|
||||
static int press_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
unsigned usage_id,
|
||||
|
@ -171,10 +172,13 @@ static int press_proc_event(struct hid_sensor_hub_device *hsdev,
|
|||
struct press_state *press_state = iio_priv(indio_dev);
|
||||
|
||||
dev_dbg(&indio_dev->dev, "press_proc_event\n");
|
||||
if (atomic_read(&press_state->common_attributes.data_ready))
|
||||
hid_sensor_push_data(indio_dev,
|
||||
&press_state->press_data,
|
||||
sizeof(press_state->press_data));
|
||||
if (atomic_read(&press_state->common_attributes.data_ready)) {
|
||||
if (!press_state->timestamp)
|
||||
press_state->timestamp = iio_get_time_ns(indio_dev);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(
|
||||
indio_dev, &press_state->scan, press_state->timestamp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -191,9 +195,13 @@ static int press_capture_sample(struct hid_sensor_hub_device *hsdev,
|
|||
|
||||
switch (usage_id) {
|
||||
case HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE:
|
||||
press_state->press_data = *(u32 *)raw_data;
|
||||
press_state->scan.press_data = *(u32 *)raw_data;
|
||||
ret = 0;
|
||||
break;
|
||||
case HID_USAGE_SENSOR_TIME_TIMESTAMP:
|
||||
press_state->timestamp = hid_sensor_convert_timestamp(
|
||||
&press_state->common_attributes, *(s64 *)raw_data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -259,8 +267,8 @@ static int hid_press_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->channels = kmemdup(press_channels, sizeof(press_channels),
|
||||
GFP_KERNEL);
|
||||
indio_dev->channels = devm_kmemdup(&pdev->dev, press_channels,
|
||||
sizeof(press_channels), GFP_KERNEL);
|
||||
if (!indio_dev->channels) {
|
||||
dev_err(&pdev->dev, "failed to duplicate channels\n");
|
||||
return -ENOMEM;
|
||||
|
@ -271,7 +279,7 @@ static int hid_press_probe(struct platform_device *pdev)
|
|||
HID_USAGE_SENSOR_PRESSURE, press_state);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to setup attributes\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->num_channels =
|
||||
|
@ -286,7 +294,7 @@ static int hid_press_probe(struct platform_device *pdev)
|
|||
&press_state->common_attributes);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "trigger setup failed\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
@ -311,8 +319,6 @@ error_iio_unreg:
|
|||
iio_device_unregister(indio_dev);
|
||||
error_remove_trigger:
|
||||
hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
|
||||
error_free_dev_mem:
|
||||
kfree(indio_dev->channels);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -326,7 +332,6 @@ static int hid_press_remove(struct platform_device *pdev)
|
|||
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
|
||||
iio_device_unregister(indio_dev);
|
||||
hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
|
||||
kfree(indio_dev->channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче