First set of new IIO and counter device support, cleanups and features for 5.15

Usual mix of cleanups and new device support.
 
 Counter
 ======
 
 Cleanups and refactoring:
 * treewide
   - Ensure attempts to set invalid modes result in -EINVAL return.
   - Rename counter_count_function to counter_function as the middle count
     is redundant.
   - Standardize error returns when limits are exceeded.
 * 104-quad:
   - Document the lock.
   - Return an error if attempt to set the ceiling value in a mode that
     doesn't support it.
 * intel-qep
   - Drop unused bitops.h include
 
 IIO
 ===
 
 New device support
 * bma255
   - Add support fo the bosch,bmc156_accel which oddly only exposes the INT2
     interrupt pin and not INT1. Patch set includes enabling use of INT2.
 * ingenic_adc
   - Add support for JZ4760 and similar and update bindings
   - Add support for JZ4760B and update bindings
 * rockchip_saradc
   - Add support for rk3568 ADC (separate channel array as more channels)
 * sgp40 gas sensor used to measure air quality
   - New driver including binding and ABI documentation.
 
 Bindings
 --------
 
 * Add missing bindings for many DACs where the binding was effectively
   implicit due to fallback probe methods in I2C and SPI.
   adi,ad5064
   adi,ad5360
   adi,ad5380
   adi,ad5421
   adi,ad5449
   adi,ad5504
   adi,ad5624r
   adi,ad5686 / adi,ad5696
   adi,ad5761
   adi,ad5764
   adi,ad5791
   adi,ad8801
   capella,cm3323 (also add explicit of_device_id table)
   microchip,mcp4922
 * bosch,bma255
   - Interrupt type in example was opposite of what the device expects.
     It's possible that a particular board had an inverter, but we
     definitely don't want the example to suggest this would be normal.
   - Add interrupt-names to allow for cases where only INT2 is connected.
   - Sort compatibles
   - Merge in very similar bosch,bma180 binding.
 
 New feature
 -----------
 
 * Devices only allowed to provide either extended_name or a label for given
   channel. If extend_name is used (generally discouraged but can't be
   removed as it would be a userspaece ABI change), then the label sysfs
   attribute will provide the extended_name. This allows some userspace
   parser simplications and hardening.
 * hid-sensors-pres
   - Add a timestamp channel (either from hardware, or locally filled).
 * vcnl3020
   - Add periodic sensor mode used to provide IIO events.
 
 Cleanups / minor fixes
 ----------------------
 
 * core/buffers
   - Avoid unnecessary zeroing of bitmaps that are immediately overwritten.
   - Move a sanity check earlier to simplify error path.
 * Quite a few cases of refactors to use devm_* for all of probe and drop
   remove
   - adjd_s311
   - adxl345
   - bma220
   - da280
   - dmard10
   - ds311
   - max5481
   - max5821
   - rfd77402
   - tcs3414
   - tmp006
 * ad5624r
   - Fix incorrect handling of a regulator that was preventing use of
     internal regulators.
 * adjd_s311
   - Allocate a buffer as part of iio_priv() structure as maximum size
     is small enough, no significant advantage in making it flexible sized.
 * bma220
   - Make handling of suspend and resume closer to the probe() wrt to the
     rather odd interface, that suspend mode is entered by reading a register.
 * ep93xx
   - Prepare clock before using (part of conversion to CCF)
 * fsl-imx25-gcq
   - Use local device pointer.
   - Adjust handling of platform_get_irq() to not check for 0 as an error.
     The function is documented as never returning it.
 * hid-sensors
   - Use devm_kmemdup() consistently across all drivers to simplify channel
     structure allocation management.
 * meson-saradc
   - Drop BL30 integration on G12A and newer SoCs as not used.
   - Whitespace fixes.
 * mpu6050
   - Add per device type startup times. This avoids an issue with having
     to dsicard initial data from gyroscopes when they were still stabilizing.
 * rfd77402
   - Change from passing private data, to passing i2c_client where only
     that is needed, reducing back and forth in pm functions.
 * si1145
   - Drop pointless continue
 * st-sensors
   - Cleanup of includes to remove unused and add missing headers that are used.
   - Use some devm functions to simplify probe() and remove() - gets us part way
     towards a fully device managed driver.
 * sx9310
   - Switch from of to generic properties to enable ACPI bindings.
 * vcnl3020
   - Add DMA safe buffer for bulk transfers.
   - Drop use of iio_claim_direct() in a driver that has no mode changes.
     A local lock is more appropriate.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAmEX9x4RHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0FohFFg//ezTrpdh7w2F4iTmMfWHks3GKloah3U0p
 DnuhfrW6w0uEsHCtuHE3ogL+5LssHgoRpBuIU6gXr0yNFxsfqWjeJQ34eTCOa5HK
 G532ecgexDF6LPIuvZi/4iv8xPFdjbFN2nQCkikNE9Ko7mcpdJP5xJL7Xa5htzm9
 r76ugJn7p1u0sZmcStWzIX/cZl2QI/5/NqZz/F2x2fWh8WKEZPns/SmqSIcsaPTu
 XHg4D8HnauRS1qDiO5XJlY0sPbwyjC3sOsziq0JcIbnp3+McF2Kypu3BrizJLl4Z
 vL0+iUvoYqt3OetALECxXuCFu0hDjJrqs2EWdEpXoc4A0rNh7Jhnc86Qb+s4Sath
 KvMyGf1qDc3rX2C4ADXdlq/YompQuhsYc1gmeGGG3YCDbfvnEPIPdwIU0stXlWy/
 0+f4Wifa0ABw5upyXly+AwWMWCpnl8XsPTEb7WiKpItviNktyssPTwbCggjITW8x
 17YbH2B0Rx5xIlVIinGEQXVELuA4gOjwBBjpFQCT6Z07tBHkbPpwS5fJeoHTjBmM
 ZAV3x54UUo7RIKVrFF/szsVwXRBJGu5cYWuCAzaA6Z37agxBrJShxbmBE7nJiB1n
 /x4oqywXL6RjfN1HSrJvd6SjHBv3oK98CNryD9V0F3ppzIZvYb/cAzHOI922iEQR
 tcXSUf4CQik=
 =cDKa
 -----END PGP SIGNATURE-----

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

Jonathan writes:

First set of new IIO and counter device support, cleanups and features for 5.15

Usual mix of cleanups and new device support.

Counter
======

Cleanups and refactoring:
* treewide
  - Ensure attempts to set invalid modes result in -EINVAL return.
  - Rename counter_count_function to counter_function as the middle count
    is redundant.
  - Standardize error returns when limits are exceeded.
* 104-quad:
  - Document the lock.
  - Return an error if attempt to set the ceiling value in a mode that
    doesn't support it.
* intel-qep
  - Drop unused bitops.h include

IIO
===

New device support
* bma255
  - Add support fo the bosch,bmc156_accel which oddly only exposes the INT2
    interrupt pin and not INT1. Patch set includes enabling use of INT2.
* ingenic_adc
  - Add support for JZ4760 and similar and update bindings
  - Add support for JZ4760B and update bindings
* rockchip_saradc
  - Add support for rk3568 ADC (separate channel array as more channels)
* sgp40 gas sensor used to measure air quality
  - New driver including binding and ABI documentation.

Bindings
--------

* Add missing bindings for many DACs where the binding was effectively
  implicit due to fallback probe methods in I2C and SPI.
  adi,ad5064
  adi,ad5360
  adi,ad5380
  adi,ad5421
  adi,ad5449
  adi,ad5504
  adi,ad5624r
  adi,ad5686 / adi,ad5696
  adi,ad5761
  adi,ad5764
  adi,ad5791
  adi,ad8801
  capella,cm3323 (also add explicit of_device_id table)
  microchip,mcp4922
* bosch,bma255
  - Interrupt type in example was opposite of what the device expects.
    It's possible that a particular board had an inverter, but we
    definitely don't want the example to suggest this would be normal.
  - Add interrupt-names to allow for cases where only INT2 is connected.
  - Sort compatibles
  - Merge in very similar bosch,bma180 binding.

New feature
-----------

* Devices only allowed to provide either extended_name or a label for given
  channel. If extend_name is used (generally discouraged but can't be
  removed as it would be a userspaece ABI change), then the label sysfs
  attribute will provide the extended_name. This allows some userspace
  parser simplications and hardening.
* hid-sensors-pres
  - Add a timestamp channel (either from hardware, or locally filled).
* vcnl3020
  - Add periodic sensor mode used to provide IIO events.

Cleanups / minor fixes
----------------------

* core/buffers
  - Avoid unnecessary zeroing of bitmaps that are immediately overwritten.
  - Move a sanity check earlier to simplify error path.
* Quite a few cases of refactors to use devm_* for all of probe and drop
  remove
  - adjd_s311
  - adxl345
  - bma220
  - da280
  - dmard10
  - ds311
  - max5481
  - max5821
  - rfd77402
  - tcs3414
  - tmp006
* ad5624r
  - Fix incorrect handling of a regulator that was preventing use of
    internal regulators.
* adjd_s311
  - Allocate a buffer as part of iio_priv() structure as maximum size
    is small enough, no significant advantage in making it flexible sized.
* bma220
  - Make handling of suspend and resume closer to the probe() wrt to the
    rather odd interface, that suspend mode is entered by reading a register.
* ep93xx
  - Prepare clock before using (part of conversion to CCF)
* fsl-imx25-gcq
  - Use local device pointer.
  - Adjust handling of platform_get_irq() to not check for 0 as an error.
    The function is documented as never returning it.
* hid-sensors
  - Use devm_kmemdup() consistently across all drivers to simplify channel
    structure allocation management.
* meson-saradc
  - Drop BL30 integration on G12A and newer SoCs as not used.
  - Whitespace fixes.
* mpu6050
  - Add per device type startup times. This avoids an issue with having
    to dsicard initial data from gyroscopes when they were still stabilizing.
* rfd77402
  - Change from passing private data, to passing i2c_client where only
    that is needed, reducing back and forth in pm functions.
* si1145
  - Drop pointless continue
* st-sensors
  - Cleanup of includes to remove unused and add missing headers that are used.
  - Use some devm functions to simplify probe() and remove() - gets us part way
    towards a fully device managed driver.
* sx9310
  - Switch from of to generic properties to enable ACPI bindings.
* vcnl3020
  - Add DMA safe buffer for bulk transfers.
  - Drop use of iio_claim_direct() in a driver that has no mode changes.
    A local lock is more appropriate.

* tag 'iio-for-5.15a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (77 commits)
  counter: 104-quad-8: Describe member 'lock' in 'quad8'
  iio: hid-sensor-press: Add timestamp channel
  counter: Rename counter_count_function to counter_function
  counter: Rename counter_signal_value to counter_signal_level
  counter: Standardize to ERANGE for limit exceeded errors
  counter: Return error code on invalid modes
  counter: 104-quad-8: Return error when invalid mode during ceiling_write
  iio: accel: bmc150: Add support for BMC156
  iio: accel: bmc150: Make it possible to configure INT2 instead of INT1
  dt-bindings: iio: accel: bma255: Add bosch,bmc156_accel
  dt-bindings: iio: accel: bma255: Add interrupt-names
  iio: light: cm3323: Add of_device_id table
  dt-bindings: Add bindings for Capella cm3323 Ambient Light Sensor
  iio: chemical: Add driver support for sgp40
  dt-bindings: iio: chemical: Add trivial DT binding for sgp40
  iio: ep93xx: Prepare clock before using it
  iio: adc: fsl-imx25-gcq: adjust irq check to match docs and simplify code
  iio: dac: max5821: convert device register to device managed function
  dt-bindings: iio/adc: ingenic: add the JZ4760(B) socs to the sadc Documentation
  iio/adc: ingenic: add JZ4760B support to the sadc driver
  ...
This commit is contained in:
Greg Kroah-Hartman 2021-08-15 08:32:07 +02:00
commit f805ef1ce5
103 changed files with 2613 additions and 809 deletions

View File

@ -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

View File

@ -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)>;
};
};
...

View File

@ -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";
};
};
- |

View File

@ -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'

View File

@ -20,6 +20,7 @@ properties:
- rockchip,px30-saradc
- rockchip,rk3308-saradc
- rockchip,rk3328-saradc
- rockchip,rk3568-saradc
- rockchip,rv1108-saradc
- const: rockchip,rk3399-saradc

View File

@ -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>;
};
};
...

View File

@ -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>;
};
};
...

View File

@ -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";
};
};
...

View File

@ -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>;
};
};
...

View File

@ -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>;
};
};
...

View File

@ -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>;
};
};
...

View File

@ -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>;
};
};
...

View File

@ -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>;
};
};
...

View File

@ -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>;
};
};
...

View File

@ -0,0 +1,62 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/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>;
};
};
...

View File

@ -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>;
};
};
...

View File

@ -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>;
};
};
...

View File

@ -0,0 +1,46 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/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>;
};
};
...

View File

@ -61,6 +61,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 +271,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

View File

@ -16717,6 +16717,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

View File

@ -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,

View File

@ -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);

View File

@ -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,

View File

@ -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) {

View File

@ -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;
}

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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[] = {

View File

@ -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

View File

@ -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_ */

View File

@ -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");

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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);

View File

@ -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)

View File

@ -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" },
{ },
};

View File

@ -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"},
{}
};

View File

@ -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;

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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;
}

View File

@ -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 */

View File

@ -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>");

View File

@ -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);

View File

@ -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"

View File

@ -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>

View File

@ -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;
}

View File

@ -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");

View File

@ -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, },
{ },
};

View File

@ -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",
};

View File

@ -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;
@ -192,6 +192,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 +219,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,
},
{},
};

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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 = {

View File

@ -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

View File

@ -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>

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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 */

View File

@ -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>");

View File

@ -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);

View File

@ -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>

View File

@ -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>

View File

@ -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) {

View File

@ -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

View File

@ -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;
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
}

View File

@ -220,7 +220,6 @@ static int __si1145_command_reset(struct si1145_data *data)
return -ETIMEDOUT;
}
msleep(SI1145_COMMAND_MINSLEEP_MS);
continue;
}
}

View File

@ -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);

View File

@ -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 */

View File

@ -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>");

View File

@ -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);

View File

@ -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>

View File

@ -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>

View File

@ -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;
}

View File

@ -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,
};

View File

@ -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;
}

View File

@ -43,7 +43,6 @@ static __maybe_unused const struct st_sensors_platform_data default_press_pdata
#ifdef CONFIG_IIO_BUFFER
int st_press_allocate_ring(struct iio_dev *indio_dev);
void st_press_deallocate_ring(struct iio_dev *indio_dev);
int st_press_trig_set_state(struct iio_trigger *trig, bool state);
#define ST_PRESS_TRIGGER_SET_STATE (&st_press_trig_set_state)
#else /* CONFIG_IIO_BUFFER */
@ -51,10 +50,6 @@ static inline int st_press_allocate_ring(struct iio_dev *indio_dev)
{
return 0;
}
static inline void st_press_deallocate_ring(struct iio_dev *indio_dev)
{
}
#define ST_PRESS_TRIGGER_SET_STATE NULL
#endif /* CONFIG_IIO_BUFFER */

View File

@ -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_press_buffer_setup_ops = {
int st_press_allocate_ring(struct iio_dev *indio_dev)
{
return iio_triggered_buffer_setup(indio_dev, NULL,
&st_sensors_trigger_handler, &st_press_buffer_setup_ops);
}
void st_press_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_press_buffer_setup_ops);
}
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");

View File

@ -9,17 +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/trigger.h>
#include <linux/iio/buffer.h>
#include <asm/unaligned.h>
#include <linux/iio/common/st_sensors.h>
@ -724,7 +718,7 @@ int st_press_common_probe(struct iio_dev *indio_dev)
err = st_sensors_allocate_trigger(indio_dev,
ST_PRESS_TRIGGER_OPS);
if (err < 0)
goto st_press_probe_trigger_error;
return err;
}
err = iio_device_register(indio_dev);
@ -739,8 +733,6 @@ int st_press_common_probe(struct iio_dev *indio_dev)
st_press_device_register_error:
if (press_data->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
st_press_probe_trigger_error:
st_press_deallocate_ring(indio_dev);
return err;
}
EXPORT_SYMBOL(st_press_common_probe);
@ -752,8 +744,6 @@ void st_press_common_remove(struct iio_dev *indio_dev)
iio_device_unregister(indio_dev);
if (press_data->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
st_press_deallocate_ring(indio_dev);
}
EXPORT_SYMBOL(st_press_common_remove);

View File

@ -7,9 +7,10 @@
* Denis Ciocca <denis.ciocca@st.com>
*/
#include <linux/acpi.h>
#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>

View File

@ -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>

View File

@ -90,18 +90,18 @@ static const struct iio_chan_spec rfd77402_channels[] = {
},
};
static int rfd77402_set_state(struct rfd77402_data *data, u8 state, u16 check)
static int rfd77402_set_state(struct i2c_client *client, u8 state, u16 check)
{
int ret;
ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R,
ret = i2c_smbus_write_byte_data(client, RFD77402_CMD_R,
state | RFD77402_CMD_VALID);
if (ret < 0)
return ret;
usleep_range(10000, 20000);
ret = i2c_smbus_read_word_data(data->client, RFD77402_STATUS_R);
ret = i2c_smbus_read_word_data(client, RFD77402_STATUS_R);
if (ret < 0)
return ret;
if ((ret & RFD77402_STATUS_PM_MASK) != check)
@ -110,24 +110,24 @@ static int rfd77402_set_state(struct rfd77402_data *data, u8 state, u16 check)
return 0;
}
static int rfd77402_measure(struct rfd77402_data *data)
static int rfd77402_measure(struct i2c_client *client)
{
int ret;
int tries = 10;
ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
ret = rfd77402_set_state(client, RFD77402_CMD_MCPU_ON,
RFD77402_STATUS_MCPU_ON);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R,
ret = i2c_smbus_write_byte_data(client, RFD77402_CMD_R,
RFD77402_CMD_SINGLE |
RFD77402_CMD_VALID);
if (ret < 0)
goto err;
while (tries-- > 0) {
ret = i2c_smbus_read_byte_data(data->client, RFD77402_ICSR);
ret = i2c_smbus_read_byte_data(client, RFD77402_ICSR);
if (ret < 0)
goto err;
if (ret & RFD77402_ICSR_RESULT)
@ -140,7 +140,7 @@ static int rfd77402_measure(struct rfd77402_data *data)
goto err;
}
ret = i2c_smbus_read_word_data(data->client, RFD77402_RESULT_R);
ret = i2c_smbus_read_word_data(client, RFD77402_RESULT_R);
if (ret < 0)
goto err;
@ -153,7 +153,7 @@ static int rfd77402_measure(struct rfd77402_data *data)
return (ret & RFD77402_RESULT_DIST_MASK) >> 2;
err:
rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
rfd77402_set_state(client, RFD77402_CMD_MCPU_OFF,
RFD77402_STATUS_MCPU_OFF);
return ret;
}
@ -168,7 +168,7 @@ static int rfd77402_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->lock);
ret = rfd77402_measure(data);
ret = rfd77402_measure(data->client);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
@ -188,23 +188,23 @@ static const struct iio_info rfd77402_info = {
.read_raw = rfd77402_read_raw,
};
static int rfd77402_init(struct rfd77402_data *data)
static int rfd77402_init(struct i2c_client *client)
{
int ret, i;
ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
ret = rfd77402_set_state(client, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
if (ret < 0)
return ret;
/* configure INT pad as push-pull, active low */
ret = i2c_smbus_write_byte_data(data->client, RFD77402_ICSR,
ret = i2c_smbus_write_byte_data(client, RFD77402_ICSR,
RFD77402_ICSR_INT_MODE);
if (ret < 0)
return ret;
/* I2C configuration */
ret = i2c_smbus_write_word_data(data->client, RFD77402_I2C_INIT_CFG,
ret = i2c_smbus_write_word_data(client, RFD77402_I2C_INIT_CFG,
RFD77402_I2C_ADDR_INCR |
RFD77402_I2C_DATA_INCR |
RFD77402_I2C_HOST_DEBUG |
@ -213,45 +213,50 @@ static int rfd77402_init(struct rfd77402_data *data)
return ret;
/* set initialization */
ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0500);
ret = i2c_smbus_write_word_data(client, RFD77402_PMU_CFG, 0x0500);
if (ret < 0)
return ret;
ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
ret = rfd77402_set_state(client, RFD77402_CMD_MCPU_OFF,
RFD77402_STATUS_MCPU_OFF);
if (ret < 0)
return ret;
/* set initialization */
ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0600);
ret = i2c_smbus_write_word_data(client, RFD77402_PMU_CFG, 0x0600);
if (ret < 0)
return ret;
ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
ret = rfd77402_set_state(client, RFD77402_CMD_MCPU_ON,
RFD77402_STATUS_MCPU_ON);
if (ret < 0)
return ret;
for (i = 0; i < ARRAY_SIZE(rf77402_tof_config); i++) {
ret = i2c_smbus_write_word_data(data->client,
ret = i2c_smbus_write_word_data(client,
rf77402_tof_config[i].reg,
rf77402_tof_config[i].val);
if (ret < 0)
return ret;
}
ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
ret = rfd77402_set_state(client, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
return ret;
}
static int rfd77402_powerdown(struct rfd77402_data *data)
static int rfd77402_powerdown(struct i2c_client *client)
{
return rfd77402_set_state(data, RFD77402_CMD_STANDBY,
return rfd77402_set_state(client, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
}
static void rfd77402_disable(void *client)
{
rfd77402_powerdown(client);
}
static int rfd77402_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -270,7 +275,6 @@ static int rfd77402_probe(struct i2c_client *client,
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->lock);
@ -280,46 +284,26 @@ static int rfd77402_probe(struct i2c_client *client,
indio_dev->name = RFD77402_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = rfd77402_init(data);
ret = rfd77402_init(client);
if (ret < 0)
return ret;
ret = iio_device_register(indio_dev);
ret = devm_add_action_or_reset(&client->dev, rfd77402_disable, client);
if (ret)
goto err_powerdown;
return ret;
return 0;
err_powerdown:
rfd77402_powerdown(data);
return ret;
}
static int rfd77402_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
rfd77402_powerdown(iio_priv(indio_dev));
return 0;
return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
static int rfd77402_suspend(struct device *dev)
{
struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
return rfd77402_powerdown(data);
return rfd77402_powerdown(to_i2c_client(dev));
}
static int rfd77402_resume(struct device *dev)
{
struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
return rfd77402_init(data);
return rfd77402_init(to_i2c_client(dev));
}
#endif
@ -337,7 +321,6 @@ static struct i2c_driver rfd77402_driver = {
.pm = &rfd77402_pm_ops,
},
.probe = rfd77402_probe,
.remove = rfd77402_remove,
.id_table = rfd77402_id,
};

View File

@ -20,6 +20,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@ -1221,10 +1222,9 @@ static int sx9310_init_compensation(struct iio_dev *indio_dev)
}
static const struct sx9310_reg_default *
sx9310_get_default_reg(struct sx9310_data *data, int idx,
sx9310_get_default_reg(struct device *dev, int idx,
struct sx9310_reg_default *reg_def)
{
const struct device_node *np = data->client->dev.of_node;
u32 combined[SX9310_NUM_CHANNELS];
u32 start = 0, raw = 0, pos = 0;
unsigned long comb_mask = 0;
@ -1232,39 +1232,23 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx,
const char *res;
memcpy(reg_def, &sx9310_default_regs[idx], sizeof(*reg_def));
if (!np)
return reg_def;
switch (reg_def->reg) {
case SX9310_REG_PROX_CTRL2:
if (of_property_read_bool(np, "semtech,cs0-ground")) {
if (device_property_read_bool(dev, "semtech,cs0-ground")) {
reg_def->def &= ~SX9310_REG_PROX_CTRL2_SHIELDEN_MASK;
reg_def->def |= SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND;
}
count = of_property_count_elems_of_size(np, "semtech,combined-sensors",
sizeof(u32));
if (count > 0 && count <= ARRAY_SIZE(combined)) {
ret = of_property_read_u32_array(np, "semtech,combined-sensors",
combined, count);
if (ret)
break;
} else {
/*
* Either the property does not exist in the DT or the
* number of entries is incorrect.
*/
count = device_property_count_u32(dev, "semtech,combined-sensors");
if (count < 0 || count > ARRAY_SIZE(combined))
break;
}
for (i = 0; i < count; i++) {
if (combined[i] >= SX9310_NUM_CHANNELS) {
/* Invalid sensor (invalid DT). */
break;
}
ret = device_property_read_u32_array(dev, "semtech,combined-sensors",
combined, count);
if (ret)
break;
for (i = 0; i < count; i++)
comb_mask |= BIT(combined[i]);
}
if (i < count)
break;
reg_def->def &= ~SX9310_REG_PROX_CTRL2_COMBMODE_MASK;
if (comb_mask == (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
@ -1278,7 +1262,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx,
break;
case SX9310_REG_PROX_CTRL4:
ret = of_property_read_string(np, "semtech,resolution", &res);
ret = device_property_read_string(dev, "semtech,resolution", &res);
if (ret)
break;
@ -1302,7 +1286,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx,
break;
case SX9310_REG_PROX_CTRL5:
ret = of_property_read_u32(np, "semtech,startup-sensor", &start);
ret = device_property_read_u32(dev, "semtech,startup-sensor", &start);
if (ret) {
start = FIELD_GET(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK,
reg_def->def);
@ -1312,7 +1296,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx,
reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK,
start);
ret = of_property_read_u32(np, "semtech,proxraw-strength", &raw);
ret = device_property_read_u32(dev, "semtech,proxraw-strength", &raw);
if (ret) {
raw = FIELD_GET(SX9310_REG_PROX_CTRL5_RAWFILT_MASK,
reg_def->def);
@ -1325,7 +1309,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx,
raw);
break;
case SX9310_REG_PROX_CTRL7:
ret = of_property_read_u32(np, "semtech,avg-pos-strength", &pos);
ret = device_property_read_u32(dev, "semtech,avg-pos-strength", &pos);
if (ret)
break;
@ -1361,7 +1345,7 @@ static int sx9310_init_device(struct iio_dev *indio_dev)
/* Program some sane defaults. */
for (i = 0; i < ARRAY_SIZE(sx9310_default_regs); i++) {
initval = sx9310_get_default_reg(data, i, &tmp);
initval = sx9310_get_default_reg(&indio_dev->dev, i, &tmp);
ret = regmap_write(data->regmap, initval->reg, initval->def);
if (ret)
return ret;

View File

@ -2,8 +2,6 @@
/*
* Support for Vishay VCNL3020 proximity sensor on i2c bus.
* Based on Vishay VCNL4000 driver code.
*
* TODO: interrupts.
*/
#include <linux/module.h>
@ -11,9 +9,10 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#define VCNL3020_PROD_ID 0x21
@ -37,6 +36,21 @@
* measurement
*/
/* Enables periodic proximity measurement */
#define VCNL_PS_EN BIT(1)
/* Enables state machine and LP oscillator for self timed measurements */
#define VCNL_PS_SELFTIMED_EN BIT(0)
/* Bit masks for ICR */
/* Enable interrupts on low or high thresholds */
#define VCNL_ICR_THRES_EN BIT(1)
/* Bit masks for ISR */
#define VCNL_INT_TH_HI BIT(0) /* High threshold hit */
#define VCNL_INT_TH_LOW BIT(1) /* Low threshold hit */
#define VCNL_ON_DEMAND_TIMEOUT_US 100000
#define VCNL_POLL_US 20000
@ -57,12 +71,14 @@ static const int vcnl3020_prox_sampling_frequency[][2] = {
* @dev: vcnl3020 device.
* @rev: revision id.
* @lock: lock for protecting access to device hardware registers.
* @buf: DMA safe __be16 buffer.
*/
struct vcnl3020_data {
struct regmap *regmap;
struct device *dev;
u8 rev;
struct mutex lock;
__be16 buf ____cacheline_aligned;
};
/**
@ -140,14 +156,34 @@ static int vcnl3020_init(struct vcnl3020_data *data)
vcnl3020_led_current_property);
};
static bool vcnl3020_is_in_periodic_mode(struct vcnl3020_data *data)
{
int rc;
unsigned int cmd;
rc = regmap_read(data->regmap, VCNL_COMMAND, &cmd);
if (rc) {
dev_err(data->dev,
"Error (%d) reading command register\n", rc);
return false;
}
return !!(cmd & VCNL_PS_SELFTIMED_EN);
}
static int vcnl3020_measure_proximity(struct vcnl3020_data *data, int *val)
{
int rc;
unsigned int reg;
__be16 res;
mutex_lock(&data->lock);
/* Protect against event capture. */
if (vcnl3020_is_in_periodic_mode(data)) {
rc = -EBUSY;
goto err_unlock;
}
rc = regmap_write(data->regmap, VCNL_COMMAND, VCNL_PS_OD);
if (rc)
goto err_unlock;
@ -163,12 +199,12 @@ static int vcnl3020_measure_proximity(struct vcnl3020_data *data, int *val)
}
/* high & low result bytes read */
rc = regmap_bulk_read(data->regmap, VCNL_PS_RESULT_HI, &res,
sizeof(res));
rc = regmap_bulk_read(data->regmap, VCNL_PS_RESULT_HI, &data->buf,
sizeof(data->buf));
if (rc)
goto err_unlock;
*val = be16_to_cpu(res);
*val = be16_to_cpu(data->buf);
err_unlock:
mutex_unlock(&data->lock);
@ -200,6 +236,15 @@ static int vcnl3020_write_proxy_samp_freq(struct vcnl3020_data *data, int val,
{
unsigned int i;
int index = -1;
int rc;
mutex_lock(&data->lock);
/* Protect against event capture. */
if (vcnl3020_is_in_periodic_mode(data)) {
rc = -EBUSY;
goto err_unlock;
}
for (i = 0; i < ARRAY_SIZE(vcnl3020_prox_sampling_frequency); i++) {
if (val == vcnl3020_prox_sampling_frequency[i][0] &&
@ -209,18 +254,250 @@ static int vcnl3020_write_proxy_samp_freq(struct vcnl3020_data *data, int val,
}
}
if (index < 0)
return -EINVAL;
if (index < 0) {
rc = -EINVAL;
goto err_unlock;
}
return regmap_write(data->regmap, VCNL_PROXIMITY_RATE, index);
rc = regmap_write(data->regmap, VCNL_PROXIMITY_RATE, index);
if (rc)
dev_err(data->dev,
"Error (%d) writing proximity rate register\n", rc);
err_unlock:
mutex_unlock(&data->lock);
return rc;
}
static bool vcnl3020_is_thr_enabled(struct vcnl3020_data *data)
{
int rc;
unsigned int icr;
rc = regmap_read(data->regmap, VCNL_PS_ICR, &icr);
if (rc) {
dev_err(data->dev,
"Error (%d) reading ICR register\n", rc);
return false;
}
return !!(icr & VCNL_ICR_THRES_EN);
}
static int vcnl3020_read_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
int rc;
struct vcnl3020_data *data = iio_priv(indio_dev);
switch (info) {
case IIO_EV_INFO_VALUE:
switch (dir) {
case IIO_EV_DIR_RISING:
rc = regmap_bulk_read(data->regmap, VCNL_PS_HI_THR_HI,
&data->buf, sizeof(data->buf));
if (rc < 0)
return rc;
*val = be16_to_cpu(data->buf);
return IIO_VAL_INT;
case IIO_EV_DIR_FALLING:
rc = regmap_bulk_read(data->regmap, VCNL_PS_LO_THR_HI,
&data->buf, sizeof(data->buf));
if (rc < 0)
return rc;
*val = be16_to_cpu(data->buf);
return IIO_VAL_INT;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int vcnl3020_write_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
int rc;
struct vcnl3020_data *data = iio_priv(indio_dev);
mutex_lock(&data->lock);
switch (info) {
case IIO_EV_INFO_VALUE:
switch (dir) {
case IIO_EV_DIR_RISING:
/* 16 bit word/ low * high */
data->buf = cpu_to_be16(val);
rc = regmap_bulk_write(data->regmap, VCNL_PS_HI_THR_HI,
&data->buf, sizeof(data->buf));
if (rc < 0)
goto err_unlock;
rc = IIO_VAL_INT;
goto err_unlock;
case IIO_EV_DIR_FALLING:
data->buf = cpu_to_be16(val);
rc = regmap_bulk_write(data->regmap, VCNL_PS_LO_THR_HI,
&data->buf, sizeof(data->buf));
if (rc < 0)
goto err_unlock;
rc = IIO_VAL_INT;
goto err_unlock;
default:
rc = -EINVAL;
goto err_unlock;
}
default:
rc = -EINVAL;
goto err_unlock;
}
err_unlock:
mutex_unlock(&data->lock);
return rc;
}
static int vcnl3020_enable_periodic(struct iio_dev *indio_dev,
struct vcnl3020_data *data)
{
int rc;
int cmd;
mutex_lock(&data->lock);
/* Enable periodic measurement of proximity data. */
cmd = VCNL_PS_EN | VCNL_PS_SELFTIMED_EN;
rc = regmap_write(data->regmap, VCNL_COMMAND, cmd);
if (rc) {
dev_err(data->dev,
"Error (%d) writing command register\n", rc);
goto err_unlock;
}
/*
* Enable interrupts on threshold, for proximity data by
* default.
*/
rc = regmap_write(data->regmap, VCNL_PS_ICR, VCNL_ICR_THRES_EN);
if (rc)
dev_err(data->dev,
"Error (%d) reading ICR register\n", rc);
err_unlock:
mutex_unlock(&data->lock);
return rc;
}
static int vcnl3020_disable_periodic(struct iio_dev *indio_dev,
struct vcnl3020_data *data)
{
int rc;
mutex_lock(&data->lock);
rc = regmap_write(data->regmap, VCNL_COMMAND, 0);
if (rc) {
dev_err(data->dev,
"Error (%d) writing command register\n", rc);
goto err_unlock;
}
rc = regmap_write(data->regmap, VCNL_PS_ICR, 0);
if (rc) {
dev_err(data->dev,
"Error (%d) writing ICR register\n", rc);
goto err_unlock;
}
/* Clear interrupt flag bit */
rc = regmap_write(data->regmap, VCNL_ISR, 0);
if (rc)
dev_err(data->dev,
"Error (%d) writing ISR register\n", rc);
err_unlock:
mutex_unlock(&data->lock);
return rc;
}
static int vcnl3020_config_threshold(struct iio_dev *indio_dev, bool state)
{
struct vcnl3020_data *data = iio_priv(indio_dev);
if (state) {
return vcnl3020_enable_periodic(indio_dev, data);
} else {
if (!vcnl3020_is_thr_enabled(data))
return 0;
return vcnl3020_disable_periodic(indio_dev, data);
}
}
static int vcnl3020_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
{
switch (chan->type) {
case IIO_PROXIMITY:
return vcnl3020_config_threshold(indio_dev, state);
default:
return -EINVAL;
}
}
static int vcnl3020_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
struct vcnl3020_data *data = iio_priv(indio_dev);
switch (chan->type) {
case IIO_PROXIMITY:
return vcnl3020_is_thr_enabled(data);
default:
return -EINVAL;
}
}
static const struct iio_event_spec vcnl3020_event_spec[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
},
};
static const struct iio_chan_spec vcnl3020_channels[] = {
{
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SAMP_FREQ),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.event_spec = vcnl3020_event_spec,
.num_event_specs = ARRAY_SIZE(vcnl3020_event_spec),
},
};
@ -251,17 +528,11 @@ static int vcnl3020_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
int rc;
struct vcnl3020_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
rc = iio_device_claim_direct_mode(indio_dev);
if (rc)
return rc;
rc = vcnl3020_write_proxy_samp_freq(data, val, val2);
iio_device_release_direct_mode(indio_dev);
return rc;
return vcnl3020_write_proxy_samp_freq(data, val, val2);
default:
return -EINVAL;
}
@ -287,6 +558,10 @@ static const struct iio_info vcnl3020_info = {
.read_raw = vcnl3020_read_raw,
.write_raw = vcnl3020_write_raw,
.read_avail = vcnl3020_read_avail,
.read_event_value = vcnl3020_read_event,
.write_event_value = vcnl3020_write_event,
.read_event_config = vcnl3020_read_event_config,
.write_event_config = vcnl3020_write_event_config,
};
static const struct regmap_config vcnl3020_regmap_config = {
@ -295,6 +570,37 @@ static const struct regmap_config vcnl3020_regmap_config = {
.max_register = VCNL_PS_MOD_ADJ,
};
static irqreturn_t vcnl3020_handle_irq_thread(int irq, void *p)
{
struct iio_dev *indio_dev = p;
struct vcnl3020_data *data = iio_priv(indio_dev);
unsigned int isr;
int rc;
rc = regmap_read(data->regmap, VCNL_ISR, &isr);
if (rc) {
dev_err(data->dev, "Error (%d) reading reg (0x%x)\n",
rc, VCNL_ISR);
return IRQ_HANDLED;
}
if (!(isr & VCNL_ICR_THRES_EN))
return IRQ_NONE;
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
iio_get_time_ns(indio_dev));
rc = regmap_write(data->regmap, VCNL_ISR, isr & VCNL_ICR_THRES_EN);
if (rc)
dev_err(data->dev, "Error (%d) writing in reg (0x%x)\n",
rc, VCNL_ISR);
return IRQ_HANDLED;
}
static int vcnl3020_probe(struct i2c_client *client)
{
struct vcnl3020_data *data;
@ -327,6 +633,19 @@ static int vcnl3020_probe(struct i2c_client *client)
indio_dev->name = "vcnl3020";
indio_dev->modes = INDIO_DIRECT_MODE;
if (client->irq) {
rc = devm_request_threaded_irq(&client->dev, client->irq,
NULL, vcnl3020_handle_irq_thread,
IRQF_ONESHOT, indio_dev->name,
indio_dev);
if (rc) {
dev_err(&client->dev,
"Error (%d) irq request failed (%u)\n", rc,
client->irq);
return rc;
}
}
return devm_iio_device_register(&client->dev, indio_dev);
}

Some files were not shown because too many files have changed in this diff Show More